diff mbox series

[RFC,v1,229/256] cl8k: add utils/utils.c

Message ID 20210617160223.160998-230-viktor.barna@celeno.com
State New
Headers show
Series wireless: cl8k driver for Celeno IEEE 802.11ax devices | expand

Commit Message

Viktor Barna June 17, 2021, 4:01 p.m. UTC
From: Viktor Barna <viktor.barna@celeno.com>

(Part of the split. Please, take a look at the cover letter for more
details).

Signed-off-by: Viktor Barna <viktor.barna@celeno.com>
---
 .../net/wireless/celeno/cl8k/utils/utils.c    | 388 ++++++++++++++++++
 1 file changed, 388 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/utils/utils.c

--
2.30.0
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/utils/utils.c b/drivers/net/wireless/celeno/cl8k/utils/utils.c
new file mode 100644
index 000000000000..6d6f913ae95a
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/utils/utils.c
@@ -0,0 +1,388 @@ 
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <net/mac80211.h>
+#include <linux/sched/signal.h>
+
+#include "utils/utils.h"
+#include "rx/rx.h"
+#include "tx/tx.h"
+#include "fw/msg_tx.h"
+#include "debugfs.h"
+#include "ipc_shared.h"
+#include "rssi.h"
+#include "traffic.h"
+#include "reg/reg_riu.h"
+#include "reg/reg_mac_hw.h"
+#include "utils/ip.h"
+
+#define GI_08  0
+#define GI_16  1
+#define GI_32  2
+#define GI_04  3
+
+#define GI_MAX_FW 4
+#define GI_MAX_HE 3
+#define GI_MAX_HT_VHT 2
+
+#define CL_TSF_LOW_MIGHT_OVERFLOW_TH 0xFFFFF000
+
+static u8 conv_wrs_gi_ht_vht[GI_MAX_HT_VHT] = {
+       [WRS_GI_LONG] = GI_08,
+       [WRS_GI_SHORT] = GI_04
+};
+
+static u8 conv_wrs_gi_he[GI_MAX_HE] = {
+       [WRS_GI_LONG] = GI_32,
+       [WRS_GI_SHORT] = GI_16,
+       [WRS_GI_VSHORT] = GI_08
+};
+
+static u8 conv_fw_gi_ht_vht[GI_MAX_FW] = {
+       [GI_08] = WRS_GI_LONG,
+       [GI_16] = 0,
+       [GI_32] = 0,
+       [GI_04] = WRS_GI_SHORT,
+};
+
+static u8 conv_fw_gi_he[GI_MAX_FW] = {
+       [GI_08] = WRS_GI_VSHORT,
+       [GI_16] = WRS_GI_SHORT,
+       [GI_32] = WRS_GI_LONG,
+       [GI_04] = 0,
+};
+
+void cl_hex_dump(char *caption, u8 *buffer, u32 length, u32 offset, bool is_byte)
+{
+       u8 *pt = buffer;
+       u32 i;
+       bool end_nl = false;
+       char buf[STR_LEN_256B] = {0};
+       int len = 0;
+
+       if (caption)
+               pr_debug("%s: %p, len = %u\n", caption, buffer, length);
+
+       if (is_byte) {
+               for (i = 0; i < length; i++) {
+                       if (i % 16 == 0)
+                               len += snprintf(buf + len, sizeof(buf) - len,
+                                               "0x%04x : ", i + offset);
+                       len += snprintf(buf + len, sizeof(buf) - len,
+                                       "%02x ", ((u8)pt[i]));
+                       end_nl = true;
+                       if (i % 16 == 15) {
+                               pr_debug("%s", buf);
+                               len = 0;
+                               end_nl = false;
+                       }
+               }
+       } else {
+               for (i = 0; i < (length / sizeof(u32)); i++) {
+                       if (i % 4 == 0)
+                               len += snprintf(buf + len, sizeof(buf) - len,
+                                               "0x%04x : ",
+                                               (u32)(i * sizeof(u32) + offset));
+                       len += snprintf(buf + len, sizeof(buf) - len,
+                                       "%08x ", *((u32 *)(pt + i * sizeof(u32))));
+                       end_nl = true;
+                       if (i % 4 == 3) {
+                               pr_debug("%s", buf);
+                               len = 0;
+                               end_nl = false;
+                       }
+               }
+       }
+
+       if (end_nl)
+               pr_debug("%s", buf);
+}
+
+u8 convert_gi_format_wrs_to_fw(u8 wrs_mode, u8 gi)
+{
+       if (wrs_mode == WRS_MODE_HE && gi < GI_MAX_HE)
+               return conv_wrs_gi_he[gi];
+       else if (wrs_mode > WRS_MODE_OFDM && gi < GI_MAX_HT_VHT)
+               return conv_wrs_gi_ht_vht[gi];
+       else
+               return 0;
+}
+
+u8 convert_gi_format_fw_to_wrs(u8 format_mode, u8 gi)
+{
+       if (gi < GI_MAX_FW) {
+               if (format_mode >= FORMATMOD_HE_SU)
+                       return conv_fw_gi_he[gi];
+               else if (format_mode >= FORMATMOD_HT_MF)
+                       return conv_fw_gi_ht_vht[gi];
+       }
+
+       return 0;
+}
+
+static u8 map_gi_to_ltf[WRS_GI_MAX] = {
+       [WRS_GI_LONG] = LTF_X4,
+       [WRS_GI_SHORT] = LTF_X2,
+       [WRS_GI_VSHORT] = LTF_X2,
+};
+
+u8 cl_map_gi_to_ltf(u8 mode, u8 gi)
+{
+       if (mode == WRS_MODE_HE && gi < WRS_GI_MAX)
+               return map_gi_to_ltf[gi];
+
+       return 0;
+}
+
+/* This table holds 10^(-110 -> 0) Q39 values for rx RSSI and noise floor calculations */
+#define CL_EXP_TBL_SIZE 111 /* 10^x table size (-110 -> 0dBm) */
+
+static u64 CL_EXP_10[CL_EXP_TBL_SIZE] = {
+       0x7FFFFFFFFF, 0x65AC8C2F36, 0x50C335D3DB, 0x4026E73CCD, 0x32F52CFEEA, 0x287A26C490,
+       0x2026F30FBB, 0x198A13577C, 0x144960C577, 0x101D3F2D96, 0x0CCCCCCCCD, 0x0A2ADAD185,
+       0x08138561FC, 0x066A4A52E1, 0x0518847FE4, 0x040C3713A8, 0x0337184E5F, 0x028DCEBBF3,
+       0x0207567A25, 0x019C86515C, 0x0147AE147B, 0x01044914F4, 0x00CEC089CC, 0x00A43AA1E3,
+       0x008273A664, 0x00679F1B91, 0x00524F3B0A, 0x0041617932, 0x0033EF0C37, 0x002940A1BC,
+       0x0020C49BA6, 0x001A074EE5, 0x0014ACDA94, 0x00106C4364, 0x000D0B90A4, 0x000A5CB5F5,
+       0x00083B1F81, 0x000689BF52, 0x0005318139, 0x000420102C, 0x000346DC5D, 0x00029A54B1,
+       0x000211490F, 0x0001A46D24, 0x00014DF4DD, 0x0001094565, 0x0000D2B65A, 0x0000A75FEF,
+       0x000084F352, 0x0000699B38, 0x000053E2D6, 0x000042A212, 0x000034EDB5, 0x00002A0AEA,
+       0x0000216549, 0x00001A86F1, 0x000015123C, 0x000010BCCB, 0x00000D4B88, 0x00000A8F86,
+       0x000008637C, 0x000006A9CF, 0x0000054AF8, 0x000004344B, 0x00000356EE, 0x000002A718,
+       0x0000021B6C, 0x000001AC7B, 0x000001545A, 0x0000010E5A, 0x000000D6C0, 0x000000AA95,
+       0x000000877F, 0x0000006BA1, 0x000000557E, 0x00000043E9, 0x00000035F1, 0x0000002AD9,
+       0x0000002209, 0x0000001B09, 0x000000157A, 0x000000110F, 0x0000000D8D, 0x0000000AC3,
+       0x000000088D, 0x00000006CA, 0x0000000565, 0x0000000449, 0x0000000367, 0x00000002B4,
+       0x0000000226, 0x00000001B5, 0x000000015B, 0x0000000114, 0x00000000DB, 0x00000000AE,
+       0x000000008A, 0x000000006E, 0x0000000057, 0x0000000045, 0x0000000037, 0x000000002C,
+       0x0000000023, 0x000000001C, 0x0000000016, 0x0000000011, 0x000000000E, 0x000000000B,
+       0x0000000009, 0x0000000007, 0x0000000005
+};
+
+static s8 cl_eng_to_noise_floor(u64 eng)
+{
+       s8 i = 0;
+       s8 noise = 0;
+       s64 min_delta = S64_MAX;
+
+       for (i = ARRAY_SIZE(CL_EXP_10) - 1; i >= 0; i--) {
+               if (abs((s64)(((s64)eng) - ((s64)CL_EXP_10[i]))) < min_delta) {
+                       min_delta = abs((s64)(((s64)eng) - ((s64)CL_EXP_10[i])));
+                       noise = i;
+               }
+       }
+
+       return (-noise);
+}
+
+static void cl_read_reg_noise(struct cl_hw *cl_hw, s8 res[4])
+{
+       u32 reg_val = riu_agcinbdpow_20_pnoisestat_get(cl_hw);
+       u8 i = 0;
+
+       for (i = 0; i < 4; i++) {
+               u8 curr_val = (reg_val >> (i * 8)) & 0xFF;
+               /* Convert reg value to real value */
+               res[i] = curr_val - 0xFF;
+       }
+}
+
+s8 cl_calc_noise_floor(struct cl_hw *cl_hw, const s8 *reg_noise_floor)
+{
+       s8 noise_floor[4] = {0};
+       u64 noise_floor_eng = 0;
+
+       if (reg_noise_floor)
+               memcpy(noise_floor, reg_noise_floor, sizeof(noise_floor));
+       else
+               cl_read_reg_noise(cl_hw, noise_floor);
+
+       noise_floor[0] = abs(noise_floor[0]);
+       noise_floor[1] = abs(noise_floor[1]);
+       noise_floor[2] = abs(noise_floor[2]);
+       noise_floor[3] = abs(noise_floor[3]);
+
+       BUILD_BUG_ON(CL_EXP_TBL_SIZE > S8_MAX);
+       noise_floor_eng = (CL_EXP_10[min_t(s8, noise_floor[0], CL_EXP_TBL_SIZE - 1)] +
+                          CL_EXP_10[min_t(s8, noise_floor[1], CL_EXP_TBL_SIZE - 1)] +
+                          CL_EXP_10[min_t(s8, noise_floor[2], CL_EXP_TBL_SIZE - 1)] +
+                          CL_EXP_10[min_t(s8, noise_floor[3], CL_EXP_TBL_SIZE - 1)]);
+
+       noise_floor_eng = div64_u64(noise_floor_eng, 4);
+
+       return cl_eng_to_noise_floor(noise_floor_eng);
+}
+
+u8 cl_convert_signed_to_reg_value(s8 val)
+{
+       bool sign = (val < 0 ? true : false);
+       u8 res = abs(val);
+
+       if (sign)
+               res |= (1 << 7);
+
+       return res;
+}
+
+static const int nl_width_to_phy_bw[] = {
+       [NL80211_CHAN_WIDTH_20_NOHT] = CHNL_BW_20,
+       [NL80211_CHAN_WIDTH_20]      = CHNL_BW_20,
+       [NL80211_CHAN_WIDTH_40]      = CHNL_BW_40,
+       [NL80211_CHAN_WIDTH_80]      = CHNL_BW_80,
+       [NL80211_CHAN_WIDTH_80P80]   = CHNL_BW_20,
+       [NL80211_CHAN_WIDTH_160]     = CHNL_BW_160,
+       [NL80211_CHAN_WIDTH_5]       = CHNL_BW_20,
+       [NL80211_CHAN_WIDTH_10]      = CHNL_BW_20,
+};
+
+u8 width_to_bw(enum nl80211_chan_width width)
+{
+       if (width <= NL80211_CHAN_WIDTH_10)
+               return nl_width_to_phy_bw[width];
+
+       return NL80211_CHAN_WIDTH_20;
+}
+
+static const int phy_bw_to_nl_width[] = {
+       [CHNL_BW_20]  = NL80211_CHAN_WIDTH_20,
+       [CHNL_BW_40]  = NL80211_CHAN_WIDTH_40,
+       [CHNL_BW_80]  = NL80211_CHAN_WIDTH_80,
+       [CHNL_BW_160] = NL80211_CHAN_WIDTH_160,
+};
+
+enum nl80211_chan_width bw_to_width(u8 bw)
+{
+       if (bw < CHNL_BW_MAX)
+               return phy_bw_to_nl_width[bw];
+
+       return CHNL_BW_20;
+}
+
+bool cl_is_valid_auth_mode(bool is_wpa, u8 auth_mode)
+{
+       return is_wpa ? (auth_mode <= CL_AKM_SUITE_PSK) :
+               (auth_mode <= CL_AKM_SUITE_FT_FILS_SHA384);
+}
+
+bool cl_is_open_auth_mode(u8 auth_mode)
+{
+       return auth_mode == CL_AKM_SUITE_OPEN;
+}
+
+u64 cl_get_tsf_u64(struct cl_hw *cl_hw)
+{
+       u32 tsf_low = mac_hw_tsf_lo_get(cl_hw);
+       u32 tsf_high = mac_hw_tsf_hi_get(cl_hw);
+       u64 tsf;
+
+       if (tsf_low > CL_TSF_LOW_MIGHT_OVERFLOW_TH) {
+               u32 tmp_tsf_low = mac_hw_tsf_lo_get(cl_hw);
+
+               /* Overflow of tsf_low occurred */
+               if (tmp_tsf_low < 0xFFFFF000)
+                       tsf_high++;
+       }
+
+       tsf = ((u64)tsf_high << 32) | (u64)tsf_low;
+
+       return tsf;
+}
+
+u8 cl_center_freq_offset(u8 bw)
+{
+       if (bw == CHNL_BW_160)
+               return 70;
+
+       if (bw == CHNL_BW_80)
+               return 30;
+
+       if (bw == CHNL_BW_40)
+               return 10;
+
+       return 0;
+}
+
+u8 max_bw_idx(u8 wrs_mode, bool is_24g)
+{
+       if (wrs_mode < WRS_MODE_HT)
+               return CHNL_BW_20 + 1;
+
+       if (wrs_mode == WRS_MODE_HT || is_24g)
+               return CHNL_BW_40 + 1;
+
+       return CHNL_BW_MAX;
+}
+
+bool cl_hw_mode_is_b_or_bg(struct cl_hw *cl_hw)
+{
+       return (cl_hw->conf->ha_hw_mode == HW_MODE_B ||
+               cl_hw->conf->ha_hw_mode == HW_MODE_BG);
+}
+
+void cl_snprintf(char **buf, int *offset, size_t *size, const char *fmt, ...)
+{
+       void *new_buf = NULL;
+       va_list args;
+       u16 str_len = strlen(fmt);
+       u16 new_size;
+
+       if (!*buf) {
+               *size = PAGE_SIZE;
+               *buf = kzalloc(*size, GFP_KERNEL);
+               if (!*buf) {
+                       pr_err("Buffer allocation failed (%u)\n", (u32)*size);
+                       return;
+               }
+       }
+
+       /* Additional space is required */
+       if (str_len > *size - *offset) {
+               new_size = *size * 2;
+               new_buf = kvzalloc(new_size, GFP_KERNEL);
+               if (new_buf) {
+                       *size = new_size;
+                       memcpy(new_buf, *buf, strlen(*buf));
+                       kvfree(*buf);
+                       *buf = new_buf;
+               } else {
+                       pr_err("Buffer allocation failed (%u)\n", (u32)*size);
+                       return;
+               }
+       }
+
+       va_start(args, fmt);
+       *offset += vsnprintf(*buf + *offset, *size, fmt, args);
+       va_end(args);
+}
+
+bool cl_is_eapol(struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       __le16 fc = hdr->frame_control;
+       unsigned int hdrlen = 0;
+       unsigned short ethertype = 0;
+       u8 *temp = NULL;
+
+       /* Find the wireless header size */
+       hdrlen = ieee80211_has_a4(fc) ? 30 : 24;
+
+       if (ieee80211_is_data_qos(fc)) {
+               hdrlen += IEEE80211_QOS_CTL_LEN;
+
+               if (ieee80211_has_order(fc))
+                       hdrlen += IEEE80211_HT_CTL_LEN;
+       }
+
+       /* Skip wireless header */
+       temp = (u8 *)(skb->data + hdrlen);
+
+       /* Skip LLC and SNAP header */
+       if (PKT_HAS_LLC_HDR(temp))
+               ethertype = get_ether_type(LENGTH_LLC + LENGTH_SSNAP - 2, temp);
+
+       return (ethertype == ETH_P_PAE) ? true : false;
+}