Search Linux Wireless

[RFC v1 119/256] cl8k: add noise.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Viktor Barna <viktor.barna@xxxxxxxxxx>

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

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

diff --git a/drivers/net/wireless/celeno/cl8k/noise.c b/drivers/net/wireless/celeno/cl8k/noise.c
new file mode 100644
index 000000000000..0bfd025196a6
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/noise.c
@@ -0,0 +1,499 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include <linux/list.h>
+#include "hw.h"
+#include "noise.h"
+#include "reg/reg_riu.h"
+#include "utils/utils.h"
+
+#define NOISE_LOWER_LIMIT -100
+#define NOISE_UPPER_LIMIT -30
+/* Range is -100dBm to -30dBm */
+#define NOISE_SCALE_RANGE  (NOISE_UPPER_LIMIT - NOISE_LOWER_LIMIT + 1)
+#define NOISE_MAX_SAMPLES  U8_MAX
+#define MAX_20M_SUB_BAND   8
+#define MAX_SEC_BW_CNT     3
+#define MAX_ANT_PER_REG    4
+
+static s8 cl_noise_process_sample(u32 sample, u8 cnt)
+{
+       s8 val = (s8)((sample >> (8 * cnt)) & 0xff);
+
+       if (val < NOISE_LOWER_LIMIT)
+               val = NOISE_LOWER_LIMIT;
+       else if (val > NOISE_UPPER_LIMIT)
+               val = NOISE_UPPER_LIMIT;
+
+       return val;
+}
+
+static bool cl_noise_is_hist_line_empty(u8 *hist, u8 cnt)
+{
+       u8 i;
+
+       for (i = 0; i < cnt; i++)
+               if (hist[i] != 0)
+                       return false;
+
+       return true;
+}
+
+static int cl_noise_print_hist(struct cl_hw *cl_hw, bool nasp_stats)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *reg = NULL;
+       u8 hist[NOISE_SCALE_RANGE][MAX_ANTENNAS] = { { 0 } };
+       u8 num_antennas = cl_hw->num_antennas;
+       s8 val_stat;
+       u8 i = 0, j = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (list_empty(&noise_db->reg_list))
+               return 0;
+
+       list_for_each_entry(reg, &noise_db->reg_list, list) {
+               for (i = 0; i < min_t(u8, num_antennas, MAX_ANT_PER_REG); i++) {
+                       if (nasp_stats)
+                               val_stat = cl_noise_process_sample(reg->nasp_prim20_per_ant, i);
+                       else
+                               val_stat = cl_noise_process_sample(reg->np_prim20_per_ant, i);
+
+                       hist[(val_stat * -1) + NOISE_UPPER_LIMIT][i]++;
+               }
+
+               if (num_antennas <= MAX_ANT_PER_REG)
+                       continue;
+
+               for (i = 0; i < num_antennas - MAX_ANT_PER_REG; i++) {
+                       if (nasp_stats)
+                               val_stat = cl_noise_process_sample(reg->nasp_prim20_per_ant2, i);
+                       else
+                               val_stat = cl_noise_process_sample(reg->np_prim20_per_ant2, i);
+
+                       hist[(val_stat * -1) + NOISE_UPPER_LIMIT][i + MAX_ANT_PER_REG]++;
+               }
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Noise %sstrength histogram (dBm):\n", nasp_stats ? "and signal " : "");
+
+       cl_snprintf(&buf, &len, &buf_size, "------------------");
+       for (j = 0; j < num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "\n| Noise Strength ");
+
+       for (j = 0; j < num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "| Ant%u ", j);
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n|----------------");
+
+       for (j = 0; j < num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       for (i = 0; i < NOISE_SCALE_RANGE; i++) {
+               if (cl_noise_is_hist_line_empty(hist[i], num_antennas))
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size, "|%9d       ", -i + NOISE_UPPER_LIMIT);
+               for (j = 0; j < num_antennas; j++)
+                       cl_snprintf(&buf, &len, &buf_size, "| %3u  ", hist[i][j]);
+
+               cl_snprintf(&buf, &len, &buf_size, "|\n");
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|----------------");
+       for (j = 0; j < num_antennas; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_noise_print_hist_per_channel(struct cl_hw *cl_hw,
+                                          bool nasp_stats)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *reg = NULL;
+       u8 ch_bw = cl_hw->conf->ce_channel_bandwidth;
+       u8 ch_cnt = 1 << ch_bw;
+       u8 hist[NOISE_SCALE_RANGE][MAX_20M_SUB_BAND] = { { 0 } };
+       s8 val1, val2;
+       u8 i = 0, j = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (list_empty(&noise_db->reg_list))
+               return 0;
+
+       list_for_each_entry(reg, &noise_db->reg_list, list) {
+               for (i = 0; i < min_t(u8, ch_cnt, MAX_ANT_PER_REG); i++) {
+                       if (nasp_stats) {
+                               val1 = cl_noise_process_sample(reg->nasp_sub20_per_chn, i);
+
+                               if (ch_bw == CHNL_BW_160)
+                                       val2 = cl_noise_process_sample(reg->nasp_sub20_per_chn2, i);
+                       } else {
+                               val1 = cl_noise_process_sample(reg->np_sub20_per_chn, i);
+
+                               if (ch_bw == CHNL_BW_160)
+                                       val2 = cl_noise_process_sample(reg->np_sub20_per_chn2, i);
+                       }
+
+                       hist[(val1 * -1) + NOISE_UPPER_LIMIT][i]++;
+                       if (ch_bw == CHNL_BW_160)
+                               hist[(val2 * -1) + NOISE_UPPER_LIMIT][i + MAX_ANT_PER_REG]++;
+               }
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Noise %sstrength per 20 Mhz channel histogram ant %u (dBm):\n"
+                   "------------------",
+                   nasp_stats ? "and signal " : "", noise_db->active_ant);
+
+       for (j = 0; j < ch_cnt; j++)
+               cl_snprintf(&buf, &len, &buf_size, "--------");
+
+       cl_snprintf(&buf, &len, &buf_size, "\n| Noise Strength ");
+       for (j = 0; j < ch_cnt; j++)
+               cl_snprintf(&buf, &len, &buf_size, "| Chan%u ", j);
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n|----------------");
+
+       for (j = 0; j < ch_cnt; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       for (i = 0; i < NOISE_SCALE_RANGE; i++) {
+               if (cl_noise_is_hist_line_empty(hist[i], ch_cnt))
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size, "|%9d       ", -i + NOISE_UPPER_LIMIT);
+
+               for (j = 0; j < ch_cnt; j++)
+                       cl_snprintf(&buf, &len, &buf_size, "| %3u   ", hist[i][j]);
+
+               cl_snprintf(&buf, &len, &buf_size, "|\n");
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|----------------");
+
+       for (j = 0; j < ch_cnt; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_noise_print_hist_dens(struct cl_hw *cl_hw, bool nasp_stats)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *reg = NULL;
+       u8 hist[NOISE_SCALE_RANGE][MAX_SEC_BW_CNT] = { { 0 } };
+       u8 ch_bw = cl_hw->conf->ce_channel_bandwidth;
+       s8 val;
+       u8 i = 0, j = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int err = 0;
+       int len = 0;
+
+       if (list_empty(&noise_db->reg_list) || ch_bw == 0)
+               return 0;
+
+       list_for_each_entry(reg, &noise_db->reg_list, list) {
+               for (i = 0; i < ch_bw; i++) {
+                       if (nasp_stats)
+                               val = cl_noise_process_sample(reg->nasp_sec20_dens_per_ant, i);
+                       else
+                               val = cl_noise_process_sample(reg->np_sec20_dens_per_ant, i);
+
+                       hist[(val * -1) + NOISE_UPPER_LIMIT][i]++;
+               }
+       }
+
+       cl_snprintf(&buf, &len, &buf_size,
+                   "Noise %spower density histogram ant %u (dBm/20Mhz):\n",
+                   nasp_stats ? "and signal " : "", noise_db->active_ant);
+
+       cl_snprintf(&buf, &len, &buf_size, "-----------------");
+
+       for (j = 0; j < ch_bw; j++)
+               cl_snprintf(&buf, &len, &buf_size, "--------");
+
+       cl_snprintf(&buf, &len, &buf_size, "\n| Noise Density ");
+
+       for (j = 0; j < ch_bw; j++)
+               cl_snprintf(&buf, &len, &buf_size, "| SEC%u ", 20 * (1 << j));
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n|---------------");
+       for (j = 0; j < ch_bw; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       for (i = 0; i < NOISE_SCALE_RANGE; i++) {
+               if (cl_noise_is_hist_line_empty(hist[i], ch_bw))
+                       continue;
+
+               cl_snprintf(&buf, &len, &buf_size, "|%9d      ", -i + NOISE_UPPER_LIMIT);
+               for (j = 0; j < ch_bw; j++)
+                       cl_snprintf(&buf, &len, &buf_size, "| %3u   ", hist[i][j]);
+
+               cl_snprintf(&buf, &len, &buf_size, "|\n");
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "|---------------");
+       for (j = 0; j < ch_bw; j++)
+               cl_snprintf(&buf, &len, &buf_size, "+-------");
+
+       cl_snprintf(&buf, &len, &buf_size, "|\n");
+
+       err = cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+
+       return err;
+}
+
+static int cl_noise_cli_help(struct cl_hw *cl_hw)
+{
+       char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       int err = 0;
+
+       if (!buf)
+               return -ENOMEM;
+
+       snprintf(buf, PAGE_SIZE,
+                "stats usage:\n"
+                "-a : Set antenna\n"
+                "-b : En/Dis noise histogram [0-stop, max samples-255]\n"
+                "-c : Print 20Mhz channels noise power\n"
+                "-d : Print 20Mhz channels noise and signal power\n"
+                "-e : Print noise density histogram\n"
+                "-f : Print noise and signal density histogram\n"
+                "-g : Print noise power histogram\n"
+                "-h : Print noise and signal power histogram\n"
+                "-r : Reset histogram\n");
+
+       err = cl_vendor_reply(cl_hw, buf, strlen(buf));
+       kfree(buf);
+
+       return err;
+}
+
+static void cl_noise_set_ant(struct cl_hw *cl_hw, u8 active_ant)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       u8 max_ant = cl_hw->num_antennas - 1;
+
+       if (noise_db->sample_cnt != 0) {
+               pr_warn("Can't set antenna during statistics collection\n");
+               return;
+       }
+
+       if (active_ant > max_ant) {
+               pr_err("Invalid antennas configuration. Should be 0-%u!\n", max_ant);
+               return;
+       }
+
+       if (active_ant == noise_db->active_ant) {
+               pr_warn("Ant %u already set!\n", active_ant);
+               return;
+       }
+
+       /* Antenna is different now so clear all stats */
+       cl_noise_close(cl_hw);
+
+       riu_rwnxagcccactrl_cca_main_ant_sel_setf(cl_hw, active_ant);
+
+       noise_db->active_ant = active_ant;
+
+       pr_debug("Antenna selected : %u\n", active_ant);
+}
+
+void cl_noise_init(struct cl_hw *cl_hw)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+
+       INIT_LIST_HEAD(&noise_db->reg_list);
+}
+
+void cl_noise_close(struct cl_hw *cl_hw)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *elem = NULL;
+       struct cl_noise_reg *tmp = NULL;
+
+       list_for_each_entry_safe(elem, tmp, &noise_db->reg_list, list) {
+               list_del(&elem->list);
+               kfree(elem);
+       }
+}
+
+void cl_noise_maintenance(struct cl_hw *cl_hw)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       struct cl_noise_reg *reg = NULL;
+       u8 ch_bw = cl_hw->conf->ce_channel_bandwidth;
+
+       if (noise_db->sample_cnt == 0)
+               return;
+
+       reg = kzalloc(sizeof(*reg), GFP_ATOMIC);
+
+       if (!reg)
+               return;
+
+       /*collect statistics */
+       reg->np_prim20_per_ant = riu_agcinbdpow_20_pnoisestat_get(cl_hw);
+       reg->np_sub20_per_chn = riu_agcinbdpownoiseper_20_stat_0_get(cl_hw);
+       reg->np_sec20_dens_per_ant = riu_agcinbdpowsecnoisestat_get(cl_hw);
+       reg->nasp_prim20_per_ant = riu_inbdpowformac_0_get(cl_hw);
+       reg->nasp_sub20_per_chn = riu_inbdpowformac_3_get(cl_hw);
+       reg->nasp_sec20_dens_per_ant = riu_inbdpowformac_2_get(cl_hw);
+
+       if (ch_bw == CHNL_BW_160) {
+               reg->np_sub20_per_chn2 = riu_agcinbdpownoiseper_20_stat_1_get(cl_hw);
+               reg->nasp_sub20_per_chn2 = riu_inbdpowformac_4_get(cl_hw);
+       }
+
+       if (cl_hw->num_antennas > MAX_ANT_PER_REG) {
+               reg->np_prim20_per_ant2 = riu_agcinbdpow_20_pnoisestat_2_get(cl_hw);
+               reg->nasp_prim20_per_ant2 = riu_inbdpowformac_1_get(cl_hw);
+       }
+
+       list_add(&reg->list, &noise_db->reg_list);
+
+       noise_db->sample_cnt--;
+
+       if (noise_db->sample_cnt == 0)
+               pr_debug("record done\n");
+}
+
+int cl_noise_cli(struct cl_hw *cl_hw, struct cli_params *cli_params)
+{
+       struct cl_noise_db *noise_db = &cl_hw->noise_db;
+       bool set_ant = false;
+       bool hist_enable = false;
+       bool hist_per_channel = false;
+       bool hist_mac_per_channel = false;
+       bool hist_dens = false;
+       bool hist_mac_dens = false;
+       bool hist_pwr_print = false;
+       bool hist_mac_pwr_print = false;
+       bool hist_reset = false;
+       u32 param = (u32)cli_params->params[0];
+       u32 expected_params = -1;
+
+       switch (cli_params->option) {
+       case 'a':
+               set_ant = true;
+               expected_params = 1;
+               break;
+       case 'b':
+               hist_enable = true;
+               expected_params = 1;
+               break;
+       case 'c':
+               hist_per_channel = true;
+               expected_params = 0;
+               break;
+       case 'd':
+               hist_mac_per_channel = true;
+               expected_params = 0;
+               break;
+       case 'e':
+               hist_dens = true;
+               expected_params = 0;
+               break;
+       case 'f':
+               hist_mac_dens = true;
+               expected_params = 0;
+               break;
+       case 'g':
+               hist_pwr_print = true;
+               expected_params = 0;
+               break;
+       case 'h':
+               hist_mac_pwr_print = true;
+               expected_params = 0;
+               break;
+       case 'r':
+               hist_reset = true;
+               expected_params = 0;
+               break;
+       case '?':
+               return cl_noise_cli_help(cl_hw);
+       default:
+               cl_dbg_err(cl_hw, "Illegal option (%c) - try '?' for help\n", cli_params->option);
+               goto out_err;
+       }
+
+       if (expected_params != cli_params->num_params) {
+               cl_dbg_err(cl_hw, "Wrong number of arguments (expected %u) (actual %u)\n",
+                          expected_params, cli_params->num_params);
+               goto out_err;
+       }
+
+       if (set_ant) {
+               cl_noise_set_ant(cl_hw, (u8)param);
+
+               return 0;
+       }
+
+       if (hist_enable) {
+               if (param > NOISE_MAX_SAMPLES) {
+                       pr_err("Error! Max samples should be < %u\n", NOISE_MAX_SAMPLES);
+               } else {
+                       pr_debug("%s record histogram\n", param ? "Start" : "Stop");
+                       noise_db->sample_cnt = param;
+               }
+
+               return 0;
+       }
+
+       if (hist_per_channel)
+               return cl_noise_print_hist_per_channel(cl_hw, false);
+
+       if (hist_mac_per_channel)
+               return cl_noise_print_hist_per_channel(cl_hw, true);
+
+       if (hist_dens)
+               return cl_noise_print_hist_dens(cl_hw, false);
+
+       if (hist_mac_dens)
+               return cl_noise_print_hist_dens(cl_hw, true);
+
+       if (hist_pwr_print)
+               return cl_noise_print_hist(cl_hw, false);
+
+       if (hist_mac_pwr_print)
+               return cl_noise_print_hist(cl_hw, true);
+
+       if (hist_reset) {
+               pr_debug("Clear histogram\n");
+               cl_noise_close(cl_hw);
+               return 0;
+       }
+
+out_err:
+       return -EIO;
+}
+
--
2.30.0

________________________________
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any retransmission, dissemination, copying or other use of, or taking of any action in reliance upon this information is prohibited. If you received this in error, please contact the sender and delete the material from any computer. Nothing contained herein shall be deemed as a representation, warranty or a commitment by Celeno. No warranties are expressed or implied, including, but not limited to, any implied warranties of non-infringement, merchantability and fitness for a particular purpose.
________________________________





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux