new file mode 100644
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "wrs/wrs_api.h"
+#include "wrs/wrs.h"
+#include "wrs/wrs_sta.h"
+#include "wrs/wrs_ap.h"
+#include "wrs/wrs_cli.h"
+#include "rate_ctrl.h"
+#include "prot_mode.h"
+#include "utils/utils.h"
+#include "band.h"
+#include "sta.h"
+#include "data_rates.h"
+
+void cl_wrs_api_init(struct cl_hw *cl_hw)
+{
+ cl_wrs_init(cl_hw);
+ cl_wrs_ap_capab_set(cl_hw);
+}
+
+void cl_wrs_api_close(struct cl_hw *cl_hw)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+ cl_timer_disable_sync(&wrs_db->timer_maintenance);
+}
+
+void cl_wrs_api_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+ cl_wrs_lock_bh(wrs_db);
+ cl_wrs_sta_add(cl_hw, sta);
+ cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_sta_remove(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+ cl_wrs_lock_bh(wrs_db);
+ cl_wrs_sta_remove(cl_hw, wrs_db, cl_sta);
+ cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_bss_set_bw(struct cl_hw *cl_hw, u8 bw)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+ cl_wrs_lock_bh(wrs_db);
+ cl_wrs_ap_capab_modify_bw(cl_hw, wrs_db, bw);
+ cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_bw_changed(struct cl_hw *cl_hw, struct ieee80211_sta *sta, u8 bw)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+ struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+ struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+
+ cl_wrs_lock_bh(wrs_db);
+
+ wrs_sta->max_rate_cap.bw = bw;
+ cl_wrs_sta_capabilities_set(wrs_db, sta);
+ cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->su_params);
+
+ cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_nss_changed(struct cl_hw *cl_hw, struct ieee80211_sta *sta, u8 nss)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+ struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+ struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+
+ cl_wrs_lock_bh(wrs_db);
+
+ wrs_sta->max_rate_cap.nss = nss;
+ cl_wrs_sta_capabilities_set(wrs_db, sta);
+ cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->su_params);
+
+ cl_wrs_unlock_bh(wrs_db);
+}
+
+static void _cl_wrs_api_recovery(struct cl_hw *cl_hw, struct cl_wrs_sta *wrs_sta,
+ struct cl_wrs_params *wrs_params)
+{
+ u16 fallback_rate_idx = wrs_params->table[wrs_params->rate_idx].rate_down.rate_idx;
+ struct cl_wrs_rate *rate_fallback = &wrs_params->table[fallback_rate_idx].rate;
+ struct cl_wrs_tx_params *tx_params = &wrs_params->tx_params;
+
+ cl_wrs_tx_param_set(cl_hw, wrs_sta, wrs_params, tx_params, rate_fallback);
+}
+
+void cl_wrs_api_recovery(struct cl_hw *cl_hw)
+{
+ struct cl_sta *cl_sta = NULL;
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+ struct cl_wrs_sta *wrs_sta = NULL;
+
+ cl_wrs_lock_bh(wrs_db);
+ cl_sta_lock(cl_hw);
+
+ list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+ wrs_sta = &cl_sta->wrs_sta;
+
+ _cl_wrs_api_recovery(cl_hw, wrs_sta, &wrs_sta->su_params);
+ }
+
+ cl_sta_unlock(cl_hw);
+ cl_wrs_unlock_bh(wrs_db);
+}
+
+void cl_wrs_api_beamforming_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+ struct cl_wrs_params *wrs_params = &cl_sta->wrs_sta.su_params;
+ u8 up_idx = 0;
+ u16 rate_idx = wrs_params->rate_idx;
+
+ cl_wrs_lock(wrs_db);
+
+ for (up_idx = 0; up_idx < WRS_TABLE_NODE_UP_MAX; up_idx++)
+ wrs_params->table[rate_idx].rate_up[up_idx].time_th = WRS_INIT_MSEC_WEIGHT_UP;
+
+ cl_wrs_unlock(wrs_db);
+
+ wrs_pr_info(wrs_db, "[WRS] sta %u - beamforming sync\n", cl_sta->sta_idx);
+}
+
+void cl_wrs_api_quick_down_check(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+ struct cl_wrs_params *wrs_params)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+ cl_wrs_lock(wrs_db);
+ cl_wrs_quick_down_check(cl_hw, wrs_db, &cl_sta->wrs_sta, wrs_params);
+ cl_wrs_unlock(wrs_db);
+}
+
+void cl_wrs_api_rate_sync(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+ struct cl_wrs_params *wrs_params)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+
+ cl_wrs_lock(wrs_db);
+ cl_wrs_tx_param_sync(wrs_db, &cl_sta->wrs_sta, wrs_params);
+ cl_wrs_unlock(wrs_db);
+}
+
+bool cl_wrs_api_up_mcs1(struct cl_hw *cl_hw, struct cl_sta *cl_sta,
+ struct cl_wrs_params *wrs_params)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+ bool result = false;
+
+ cl_wrs_lock(wrs_db);
+ result = cl_wrs_up_mcs1(cl_hw, wrs_db, &cl_sta->wrs_sta, wrs_params);
+ cl_wrs_unlock(wrs_db);
+
+ return result;
+}
+
+void cl_wrs_api_set_smps_mode(struct cl_hw *cl_hw, struct ieee80211_sta *sta, const u8 bw)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+ struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+ struct cl_wrs_sta *wrs_sta = &cl_sta->wrs_sta;
+ u8 min_bw;
+
+ if (sta->smps_mode == IEEE80211_SMPS_STATIC ||
+ sta->smps_mode == IEEE80211_SMPS_DYNAMIC) {
+ /* If RTS is enabled, there is no need to go down to 1ss */
+ if (cl_prot_mode_get(cl_hw) == TXL_PROT_RTS)
+ return;
+
+ wrs_sta->smps_enable = true;
+ } else if (sta->smps_mode == IEEE80211_SMPS_OFF && wrs_sta->smps_enable) {
+ wrs_sta->smps_enable = false;
+ }
+
+ cl_wrs_lock_bh(wrs_db);
+ min_bw = min_t(u8, bw, wrs_db->max_cap.bw);
+
+ if (wrs_sta->max_rate_cap.bw != min_bw) {
+ wrs_sta->max_rate_cap.bw = min_bw;
+ wrs_pr_trace(wrs_db, "[WRS] SMPS mode: sta %u, bw %u\n",
+ wrs_sta->sta_idx, min_bw);
+ cl_wrs_tables_build(cl_hw, wrs_sta, &wrs_sta->su_params);
+ }
+
+ cl_wrs_unlock_bh(wrs_db);
+}
+
+u16 cl_wrs_api_get_sta_data_rate(struct cl_sta *cl_sta)
+{
+ return cl_sta->wrs_sta.su_params.data_rate;
+}
+
+int cl_wrs_api_cli(struct cl_hw *cl_hw, struct cl_vif *cl_vif, struct cli_params *cli_params)
+{
+ struct cl_wrs_db *wrs_db = &cl_hw->wrs_db;
+ int ret;
+
+ cl_wrs_lock_bh(wrs_db);
+ ret = cl_wrs_cli(cl_hw, cl_vif, cli_params);
+ cl_wrs_unlock_bh(wrs_db);
+
+ return ret;
+}
+