Search Linux Wireless

[RFC v1 248/256] cl8k: add wrs/wrs_rssi.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>
---
 .../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

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);
+}
--
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