diff mbox series

[RFC,v1,248/256] cl8k: add wrs/wrs_rssi.c

Message ID 20210617160223.160998-249-viktor.barna@celeno.com (mailing list archive)
State RFC
Delegated to: Kalle Valo
Headers show
Series wireless: cl8k driver for Celeno IEEE 802.11ax devices | expand

Commit Message

Viktor Barna June 17, 2021, 4:02 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/wrs/wrs_rssi.c   | 444 ++++++++++++++++++
 1 file changed, 444 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c

--
2.30.0
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c b/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c
new file mode 100644
index 000000000000..9f4e691c81db
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/wrs/wrs_rssi.c
@@ -0,0 +1,444 @@ 
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_rssi.h"
+#include "wrs/wrs.h"
+#include "def.h"
+#include "rssi.h"
+#include "data_rates.h"
+
+/*
+ * Section #1:
+ * rate based on rssi.
+ */
+static s8 rssi_threshold_he[WRS_MCS_MAX_HE] = {
+       -35, -40, -45, -50, -55, -60, -65, -70, -75, -80, -85, -90
+};
+
+static s8 rssi_threshold_vht[WRS_MCS_MAX_VHT] = {
+       -36, -42, -48, -54, -60, -66, -72, -78, -84, -90
+};
+
+static s8 rssi_threshold_ht[WRS_MCS_MAX_HT] = {
+       -34, -42, -50, -58, -66, -74, -82, -90
+};
+
+static s8 rssi_threshold_ofdm[WRS_MCS_MAX_OFDM] = {
+       -34, -42, -50, -58, -66, -74, -82, -90
+};
+
+static s8 rssi_threshold_cck[WRS_MCS_MAX_CCK] = {
+       -45, -60, -75, -90
+};
+
+static u16 cl_wrs_rssi_find_rate_ht_vht_he(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                          struct cl_wrs_sta *wrs_sta, s8 *rssi_sort,
+                                          s8 *thresholds)
+{
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       s8 max_ss = (s8)wrs_sta->max_rate_cap.nss;
+       s8 nss = 0;
+       u8 max_bw = wrs_sta->max_rate_cap.bw;
+       u8 bw = 0;
+       u8 max_mcs = wrs_sta->max_rate_cap.mcs;
+       u8 mcs = 0;
+       u8 gi = WRS_GI_LONG;
+       u8 selected_mcs = 0;
+       u8 selected_nss = 0;
+       u8 selected_bw = 0;
+       u8 i = 0;
+       u16 rate_idx = 0;
+       u16 data_rate = 0;
+       u16 max_data_rate = 0;
+
+       if (max_bw > cl_hw->conf->ci_wrs_max_bw)
+               max_bw = cl_hw->conf->ci_wrs_max_bw;
+
+       for (i = 0; i <= max_mcs; i++) {
+               mcs = max_mcs - i;
+
+               for (nss = max_ss; nss >= 0; nss--) {
+                       if (rssi_sort[nss] <= thresholds[i])
+                               continue;
+
+                       /* In last level decrease BW */
+                       bw = ((i == max_mcs) && (max_bw > CHNL_BW_20)) ? (max_bw - 1) : max_bw;
+
+                       if (wrs_sta->mode == WRS_MODE_HE) {
+                               data_rate = data_rate_he_x10[nss][bw][mcs][WRS_GI_LONG];
+                       } else {
+                               if (wrs_sta->mode == WRS_MODE_VHT) {
+                                       /* 160MHz in VHT is valid only for 1/2 SS */
+                                       if (nss >= WRS_SS_3 && bw == CHNL_BW_160)
+                                               bw = CHNL_BW_80;
+
+                                       /* BW 80, 3 SS MCS 6 is invalid in VHT */
+                                       if (bw == CHNL_BW_80 &&
+                                           nss == WRS_SS_3 &&
+                                           mcs == WRS_MCS_6)
+                                               continue;
+                               }
+
+                               data_rate = data_rate_ht_vht_x10[bw][nss][mcs][gi];
+                       }
+
+                       if (data_rate > max_data_rate) {
+                               selected_mcs = mcs;
+                               selected_nss = nss;
+                               selected_bw = bw;
+                               max_data_rate = data_rate;
+                               rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+                                                                      bw, nss, mcs, gi);
+                       }
+
+                       break;
+               }
+       }
+
+       if (cl_env_det_is_noisy(cl_hw) || cl_env_det_is_very_noisy(cl_hw)) {
+               /* In conservative mode select less agressive parameters */
+               if (wrs_db->conservative_nss_noisy_env && selected_nss > 0)
+                       selected_nss--;
+
+               if (wrs_db->conservative_nss_noisy_env && selected_mcs > 0)
+                       selected_mcs--;
+
+               /* BW 80, 3 SS MCS 6 is invalid in VHT */
+               if (wrs_sta->mode == WRS_MODE_VHT &&
+                   selected_bw == CHNL_BW_80 &&
+                   selected_nss == WRS_SS_3 &&
+                   selected_mcs == WRS_MCS_6)
+                       selected_mcs--;
+
+               rate_idx = cl_wrs_tables_find_rate_idx(wrs_params,
+                                                      selected_bw, selected_nss, selected_mcs, gi);
+       }
+
+       return rate_idx;
+}
+
+static u16 cl_wrs_rssi_find_rate_cck_ofdm(struct cl_wrs_sta *wrs_sta,
+                                         s8 *rssi_sort, s8 *thresholds)
+{
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       u8 max_mcs = wrs_sta->max_rate_cap.mcs;
+       u8 mcs = 0;
+       u8 i = 0;
+
+       for (i = 0; i <= max_mcs; i++) {
+               mcs = max_mcs - i;
+
+               if (rssi_sort[WRS_SS_1] > thresholds[i])
+                       return cl_wrs_tables_find_rate_idx(wrs_params,
+                                                          CHNL_BW_20, WRS_SS_1, mcs, WRS_GI_LONG);
+       }
+
+       return 0;
+}
+
+static u16 cl_wrs_rssi_find_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                struct cl_wrs_sta *wrs_sta, s8 *rssi_sort)
+{
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       u16 rate_idx = 0;
+
+       switch (wrs_sta->mode) {
+       case WRS_MODE_HE:
+               rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta,
+                                                          rssi_sort, rssi_threshold_he);
+               break;
+       case WRS_MODE_VHT:
+               rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta,
+                                                          rssi_sort, rssi_threshold_vht);
+               break;
+       case WRS_MODE_HT:
+               rate_idx = cl_wrs_rssi_find_rate_ht_vht_he(cl_hw, wrs_db, wrs_sta,
+                                                          rssi_sort, rssi_threshold_ht);
+               break;
+       case WRS_MODE_OFDM:
+               rate_idx = cl_wrs_rssi_find_rate_cck_ofdm(wrs_sta, rssi_sort,
+                                                         rssi_threshold_ofdm);
+               break;
+       case WRS_MODE_CCK:
+               rate_idx = cl_wrs_rssi_find_rate_cck_ofdm(wrs_sta, rssi_sort,
+                                                         rssi_threshold_cck);
+               break;
+       default:
+               break;
+       }
+
+       if (rate_idx == WRS_INVALID_RATE)
+               rate_idx = 0;
+
+       wrs_pr_trace(wrs_db,
+                    "[WRS] Select rate based rssi - sta=%u, rssi [%d,%d,%d,%d], "
+                    "rate_idx=%u, bw=%u, nss=%u, mcs=%u\n",
+                    wrs_sta->sta_idx,
+                    rssi_sort[0],
+                    rssi_sort[1],
+                    rssi_sort[2],
+                    rssi_sort[3],
+                    rate_idx,
+                    wrs_params->table[rate_idx].rate.bw,
+                    wrs_params->table[rate_idx].rate.nss,
+                    wrs_params->table[rate_idx].rate.mcs);
+
+       return rate_idx;
+}
+
+bool cl_wrs_rssi_set_rate(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                         struct cl_wrs_sta *wrs_sta)
+{
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       s8 rssi_sort[MAX_ANTENNAS] = {0};
+       u16 new_rate_idx = 0;
+
+       /* Get rssi */
+       cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, true, rssi_sort);
+
+       /* Find new rate according to rssi thresholds */
+       new_rate_idx = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta, rssi_sort);
+
+       if (new_rate_idx != wrs_params->rate_idx) {
+               cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params,
+                                      WRS_DECISION_RSSI_MGMT, new_rate_idx);
+               cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                       new_rate_idx, false);
+       } else {
+               wrs_params->sync = true;
+       }
+
+       return true;
+}
+
+/*
+ * Section #2:
+ * rssi protect.
+ */
+static void cl_wrs_rssi_prot_set_avg(struct cl_wrs_sta *wrs_sta, s8 avg)
+{
+       struct cl_wrs_rssi_prot_db *rssi_prot_db = &wrs_sta->rssi_prot_db;
+
+       memset(rssi_prot_db->samples_old, avg, WRS_RSSI_PROTECT_BUF_SZ_OLD);
+       memset(rssi_prot_db->samples_new, avg, WRS_RSSI_PROTECT_BUF_SZ_NEW);
+       rssi_prot_db->sum = avg << WRS_RSSI_PROTECT_SHIFT;
+}
+
+static s8 cl_wrs_rssi_prot_add_smpl(struct cl_wrs_sta *wrs_sta, s8 rssi_eq)
+{
+       struct cl_wrs_rssi_prot_db *rssi_prot_db = &wrs_sta->rssi_prot_db;
+       u8 curr_idx_old = rssi_prot_db->curr_idx_old;
+       u8 curr_idx_new = rssi_prot_db->curr_idx_new;
+
+       rssi_prot_db->sum +=
+               rssi_prot_db->samples_new[curr_idx_new] - rssi_prot_db->samples_old[curr_idx_old];
+       rssi_prot_db->samples_old[curr_idx_old] = rssi_prot_db->samples_new[curr_idx_new];
+       rssi_prot_db->samples_new[curr_idx_new] = rssi_eq;
+
+       rssi_prot_db->curr_idx_old =
+               WRS_INC_POW2(rssi_prot_db->curr_idx_old, WRS_RSSI_PROTECT_BUF_SZ_OLD);
+       WRS_INC(rssi_prot_db->curr_idx_new, WRS_RSSI_PROTECT_BUF_SZ_NEW);
+
+       return (s8)(wrs_sta->rssi_prot_db.sum >> WRS_RSSI_PROTECT_SHIFT);
+}
+
+static bool cl_wrs_rssi_prot_decision_up(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                        struct cl_wrs_sta *wrs_sta, s8 rssi_avg, s8 rssi_eq,
+                                        s8 *rssi_sort, u8 up_rate_idx)
+{
+       /* Decide UP only if all new samples are greater than old average */
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       s8 *samples_new = wrs_sta->rssi_prot_db.samples_new;
+       s8 up_thr = rssi_avg + wrs_db->rssi_protect_up_thr;
+       u8 i = 0;
+
+       for (i = 0; i < WRS_RSSI_PROTECT_BUF_SZ_NEW; i++)
+               if (samples_new[i] <= up_thr)
+                       return false;
+
+       if (wrs_db->rssi_protect_mode == WRS_RSSI_PROT_MODE_RSSI) {
+               u16 rate_idx_old = wrs_params->rate_idx;
+               u16 rate_idx_new = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta, rssi_sort);
+               struct cl_wrs_rate *rate_old = &wrs_params->table[rate_idx_old].rate;
+               struct cl_wrs_rate *rate_new = &wrs_params->table[rate_idx_new].rate;
+               u16 data_rate_old = cl_data_rates_get_x10(wrs_sta->mode, rate_old->bw,
+                                                         rate_old->nss, rate_old->mcs,
+                                                         rate_old->gi);
+               u16 data_rate_new = cl_data_rates_get_x10(wrs_sta->mode, rate_new->bw,
+                                                         rate_new->nss, rate_new->mcs,
+                                                         rate_new->gi);
+
+               if (rate_idx_old == rate_idx_new || data_rate_old >= data_rate_new)
+                       rate_idx_new = up_rate_idx;
+
+               wrs_pr_info(wrs_db, "[WRS] Increase rate based on RSSI - old [%u], new [%u]\n",
+                           rate_idx_old, rate_idx_new);
+               cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params,
+                                      WRS_DECISION_UP_RSSI, rate_idx_new);
+               cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta,
+                                       wrs_params, rate_idx_new, true);
+       } else {
+               cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                    WRS_DECISION_UP_RSSI, up_rate_idx);
+       }
+
+       cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+       cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+
+       return true;
+}
+
+static bool cl_wrs_rssi_prot_decision_down(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                                          struct cl_wrs_sta *wrs_sta, s8 rssi_avg, s8 rssi_eq,
+                                          s8 *rssi_sort, u8 down_rate_idx)
+{
+       /* Decide DOWN only if all new samples are smaller than old average */
+       struct cl_wrs_params *wrs_params = &wrs_sta->su_params;
+       s8 *samples_new = wrs_sta->rssi_prot_db.samples_new;
+       s8 dn_thr = rssi_avg - wrs_db->rssi_protect_dn_thr;
+       u8 i = 0;
+
+       if (wrs_params->rate_idx == 0)
+               return false;
+
+       for (i = 0; i < WRS_RSSI_PROTECT_BUF_SZ_NEW; i++)
+               if (samples_new[i] >= dn_thr)
+                       return false;
+
+       if (wrs_db->rssi_protect_mode == WRS_RSSI_PROT_MODE_RSSI) {
+               u16 rate_idx_old = wrs_params->rate_idx;
+               u16 rate_idx_new = cl_wrs_rssi_find_rate(cl_hw, wrs_db, wrs_sta, rssi_sort);
+               struct cl_wrs_rate *rate_old = &wrs_params->table[rate_idx_old].rate;
+               struct cl_wrs_rate *rate_new = &wrs_params->table[rate_idx_new].rate;
+               u16 data_rate_old = cl_data_rates_get_x10(wrs_sta->mode, rate_old->bw,
+                                                         rate_old->nss, rate_old->mcs,
+                                                         rate_old->gi);
+               u16 data_rate_new = cl_data_rates_get_x10(wrs_sta->mode, rate_new->bw,
+                                                         rate_new->nss, rate_new->mcs,
+                                                         rate_new->gi);
+
+               if (rate_idx_old == rate_idx_new || data_rate_old <= data_rate_new)
+                       rate_idx_new = down_rate_idx;
+
+               wrs_pr_info(wrs_db, "[WRS] Decrease rate based on RSSI - old [%u], new [%u]\n",
+                           rate_idx_old, rate_idx_new);
+               cl_wrs_decision_update(wrs_db, wrs_sta, wrs_params,
+                                      WRS_DECISION_DOWN_RSSI, rate_idx_new);
+               cl_wrs_tx_params_update(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                       rate_idx_new, true);
+       } else {
+               cl_wrs_decision_make(cl_hw, wrs_db, wrs_sta, wrs_params,
+                                    WRS_DECISION_DOWN_RSSI, down_rate_idx);
+       }
+
+       cl_wrs_tables_reset(wrs_db, wrs_sta, wrs_params);
+       cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+
+       return true;
+}
+
+static void cl_wrs_rssi_prot_reset(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       memset(&cl_sta->wrs_sta.rssi_prot_db, 0, sizeof(struct cl_wrs_rssi_prot_db));
+}
+
+void cl_wrs_rssi_prot_start(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+       struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+       s8 rssi_sort[MAX_ANTENNAS] = {0};
+       s8 rssi_eq = 0;
+
+       if (!cl_hw->wrs_db.rssi_protect_en)
+               return;
+
+       rssi_eq = cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, false, rssi_sort);
+       cl_wrs_rssi_prot_set_avg(wrs_sta, rssi_eq);
+}
+
+bool cl_wrs_rssi_prot_decision(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                              struct cl_wrs_sta *wrs_sta, bool up_rate_valid,
+                              u8 up_rate_idx, u8 down_rate_idx)
+{
+       s8 rssi_avg = 0;
+       s8 rssi_eq = 0;
+       s8 rssi_sort[MAX_ANTENNAS] = {0};
+
+       rssi_eq = cl_wrs_rssi_eq_calc(cl_hw, wrs_sta, true, rssi_sort);
+       rssi_avg = cl_wrs_rssi_prot_add_smpl(wrs_sta, rssi_eq);
+
+       if (up_rate_valid)
+               if (cl_wrs_rssi_prot_decision_up(cl_hw, wrs_db, wrs_sta, rssi_avg,
+                                                rssi_eq, rssi_sort, up_rate_idx))
+                       return true;
+
+       return cl_wrs_rssi_prot_decision_down(cl_hw, wrs_db, wrs_sta, rssi_avg,
+                                             rssi_eq, rssi_sort, down_rate_idx);
+}
+
+void cl_wrs_rssi_prot_dbg(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                         struct cl_wrs_sta *wrs_sta)
+{
+       struct cl_wrs_rssi_prot_db *rssi_prot_db = NULL;
+       u8 curr_idx_old = 0;
+       u8 curr_idx_new = 0;
+       u8 rate_idx = 0;
+       char *buf = NULL;
+       ssize_t buf_size;
+       int len = 0;
+
+       if (!wrs_db->rssi_protect_en) {
+               cl_snprintf(&buf, &len, &buf_size, "RSSI protect is disabled!\n");
+               goto out;
+       }
+
+       rssi_prot_db = &wrs_sta->rssi_prot_db;
+       curr_idx_old = rssi_prot_db->curr_idx_old;
+       curr_idx_new = rssi_prot_db->curr_idx_new;
+
+       cl_snprintf(&buf, &len, &buf_size, "sta %u\n", wrs_sta->sta_idx);
+       cl_snprintf(&buf, &len, &buf_size, "Old rssi samples:");
+
+       for (rate_idx = 0; rate_idx < WRS_RSSI_PROTECT_BUF_SZ_OLD; rate_idx++) {
+               if (!(rate_idx & 0x7))
+                       cl_snprintf(&buf, &len, &buf_size, "\n");
+
+               cl_snprintf(&buf, &len, &buf_size, "%3u) %d, ",
+                           rate_idx, rssi_prot_db->samples_old[curr_idx_old]);
+               curr_idx_old = WRS_INC_POW2(curr_idx_old, WRS_RSSI_PROTECT_BUF_SZ_OLD);
+       }
+
+       cl_snprintf(&buf, &len, &buf_size, "\nAvg = [%d]\n\n",
+                   wrs_sta->rssi_prot_db.sum >> WRS_RSSI_PROTECT_SHIFT);
+
+       cl_snprintf(&buf, &len, &buf_size, "New rssi samples:\n");
+       for (rate_idx = 0; rate_idx < WRS_RSSI_PROTECT_BUF_SZ_NEW; rate_idx++) {
+               cl_snprintf(&buf, &len, &buf_size, "%u) %d\n", rate_idx,
+                           rssi_prot_db->samples_new[curr_idx_new]);
+               curr_idx_new = WRS_INC_POW2(curr_idx_new, WRS_RSSI_PROTECT_BUF_SZ_NEW);
+       }
+out:
+       cl_vendor_reply(cl_hw, buf, len);
+       kfree(buf);
+}
+
+void cl_wrs_rssi_prot_config(struct cl_hw *cl_hw, struct cl_wrs_db *wrs_db,
+                            bool enable, bool mode, s32 rssi_up_thr, s32 rssi_dn_thr)
+{
+       bool en_prev = wrs_db->rssi_protect_en;
+
+       wrs_db->rssi_protect_en = enable;
+       wrs_db->rssi_protect_mode = mode;
+       wrs_db->rssi_protect_up_thr = (s8)rssi_up_thr;
+       wrs_db->rssi_protect_dn_thr = (s8)rssi_dn_thr;
+
+       if (!en_prev && wrs_db->rssi_protect_en)
+               cl_sta_loop_bh(cl_hw, cl_wrs_rssi_prot_start);
+       else if (en_prev && !wrs_db->rssi_protect_en)
+               cl_sta_loop_bh(cl_hw, cl_wrs_rssi_prot_reset);
+
+       pr_debug("[WRS] Enable = %s, Mode = %s, Up threshold = %d, Down threshold = %d\n",
+                wrs_db->rssi_protect_en ? "true" : "false",
+                wrs_db->rssi_protect_mode ? "rssi" : "neighbor",
+                wrs_db->rssi_protect_up_thr,
+                wrs_db->rssi_protect_dn_thr);
+}