diff mbox series

[RFC,v1,094/256] cl8k: add fw/msg_rx.c

Message ID 20210617160223.160998-95-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, 3:59 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>
---
 drivers/net/wireless/celeno/cl8k/fw/msg_rx.c | 349 +++++++++++++++++++
 1 file changed, 349 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_rx.c

--
2.30.0
diff mbox series

Patch

diff --git a/drivers/net/wireless/celeno/cl8k/fw/msg_rx.c b/drivers/net/wireless/celeno/cl8k/fw/msg_rx.c
new file mode 100644
index 000000000000..be8a6b13392b
--- /dev/null
+++ b/drivers/net/wireless/celeno/cl8k/fw/msg_rx.c
@@ -0,0 +1,349 @@ 
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "tx/tx.h"
+#include "sounding.h"
+#include "fw/msg_rx.h"
+#include "fw/msg_tx.h"
+#include "fw/msg_cfm.h"
+#include "stats.h"
+#include "rssi.h"
+#include "fw/fw_dbg.h"
+#include "utils/utils.h"
+#include "hw_assert.h"
+#include "rate_ctrl.h"
+#include "bus/pci/ipc.h"
+#include "rsrc_mgmt.h"
+#ifdef TRACE_SUPPORT
+#include "trace.h"
+#endif
+
+static inline void rx_mm_start_cfm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       cl_msg_cfm_clear(cl_hw, msg);
+
+       /* Send indication to the embedded that a new rxbuffer element are ready */
+       cl_hw->ipc_host2xmac_trigger_set(cl_hw->chip, IPC_IRQ_A2E_RXBUF_BACK);
+}
+
+static inline void rx_mm_ba_add_cfm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       if (le16_to_cpu(msg->id) == MM_BA_ADD_TX_CFM)
+               cl_msg_cfm_assign_and_clear(cl_hw, msg);
+       else
+               cl_msg_cfm_clear(cl_hw, msg);
+}
+
+static inline void rx_mm_rsrc_mgmt_cfm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       struct mm_rsrc_mgmt_cfm *cfm = (struct mm_rsrc_mgmt_cfm *)msg->param;
+
+       cl_rsrc_mgmt_process_cfm(cl_hw, cfm);
+       cl_msg_cfm_clear(cl_hw, msg);
+}
+
+static inline void rx_mm_agg_tx_report_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       struct cl_agg_tx_report *agg_report = (struct cl_agg_tx_report *)msg->param;
+       struct cl_sta *cl_sta;
+       union cl_rate_ctrl_info rate_ctrl_info;
+
+       /*
+        * Take care of endianness and update gi and format_mod fields of rate
+        * ctrl info in agg_report for the sake of any function that needs to
+        * use them
+        */
+       agg_report->rate_cntrl_info = le32_to_cpu(agg_report->rate_cntrl_info);
+       agg_report->rate_cntrl_info_he = le32_to_cpu(agg_report->rate_cntrl_info_he);
+
+       rate_ctrl_info.word = agg_report->rate_cntrl_info;
+
+       cl_rate_ctrl_convert(&rate_ctrl_info);
+       agg_report->rate_cntrl_info = rate_ctrl_info.word;
+
+       cl_sta_lock(cl_hw);
+       cl_sta = cl_sta_get(cl_hw, agg_report->sta_idx);
+
+       if (cl_sta) {
+               /* TX stats */
+               cl_agg_tx_report_handler(cl_hw, cl_sta, (void *)agg_report);
+               cl_stats_update_tx_agg(cl_hw, cl_sta, agg_report);
+
+               /* RSSI stats */
+               if (!agg_report->ba_not_received)
+                       cl_rssi_block_ack_handler(cl_hw, cl_sta, agg_report);
+
+               /*
+                * TODO: Do we need to notify upper layer at agg_report->success?
+                * Ageout may need to reset ageout counter if at least one
+                * frame was success.
+                * May be needed when sending UDP downlink because BA's are not
+                * forwarded to driver.
+                */
+       }
+
+       cl_sta_unlock(cl_hw);
+}
+
+static inline void rx_mm_sounding_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       struct mm_sounding_ind *ind = (struct mm_sounding_ind *)msg->param;
+
+       cl_sounding_indication(cl_hw, ind);
+}
+
+static inline void rx_mm_fw_error_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       struct mm_fw_error_ind *ind = (struct mm_fw_error_ind *)msg->param;
+
+       switch (ind->error_type) {
+       case MM_FW_ERROR_TYPE_MU_OFDMA_SLOW_SECONDARY:
+               break;
+       case MM_FW_ERROR_TYPE_MAX:
+       default:
+               cl_dbg_err(cl_hw, "Invalid fw error type %u\n", ind->error_type);
+               break;
+       }
+}
+
+static inline void rx_mm_idle_async_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       cl_hw->idle_async_set = false;
+
+       cl_dbg_trace(cl_hw, "Clear MM_IDLE_ASYNC_IND\n");
+}
+
+static inline void rx_mm_rsrc_mgmt_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       cl_rsrc_mgmt_process_ind(cl_hw, (struct mm_rsrc_mgmt_ind *)msg->param);
+}
+
+static inline void rx_dbg_print_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       cl_hw_assert_print(cl_hw, msg);
+}
+
+static inline void rx_dbg_info_ind(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       cl_fw_dbg_handler(cl_hw);
+}
+
+static void (*mm_hdlrs[])(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg) = {
+       [MM_RESET_CFM]                  = cl_msg_cfm_clear,
+       [MM_START_CFM]                  = rx_mm_start_cfm,
+       [MM_VERSION_CFM]                = cl_msg_cfm_assign_and_clear,
+       [MM_ADD_IF_CFM]                 = cl_msg_cfm_assign_and_clear,
+       [MM_REMOVE_IF_CFM]              = cl_msg_cfm_clear,
+       [MM_STA_ADD_CFM]                = cl_msg_cfm_assign_and_clear,
+       [MM_STA_DEL_CFM]                = cl_msg_cfm_clear,
+       [MM_SET_FILTER_CFM]             = cl_msg_cfm_clear,
+       [MM_SET_CHANNEL_CFM]            = cl_msg_cfm_clear,
+       [MM_SET_DTIM_CFM]               = cl_msg_cfm_clear,
+       [MM_SET_BEACON_INT_CFM]         = cl_msg_cfm_clear,
+       [MM_SET_BASIC_RATES_CFM]        = cl_msg_cfm_clear,
+       [MM_SET_BSSID_CFM]              = cl_msg_cfm_clear,
+       [MM_SET_EDCA_CFM]               = cl_msg_cfm_clear,
+       [MM_SET_ASSOCIATED_CFM]         = cl_msg_cfm_clear,
+       [MM_SET_SLOTTIME_CFM]           = cl_msg_cfm_clear,
+       [MM_SET_IDLE_CFM]               = cl_msg_cfm_clear,
+       [MM_KEY_ADD_CFM]                = cl_msg_cfm_assign_and_clear,
+       [MM_KEY_DEL_CFM]                = cl_msg_cfm_clear,
+       [MM_BA_ADD_TX_CFM]              = rx_mm_ba_add_cfm,
+       [MM_BA_ADD_RX_CFM]              = rx_mm_ba_add_cfm,
+       [MM_BA_DEL_CFM]                 = cl_msg_cfm_assign_and_clear,
+       [MM_AVAILABLE_BA_TXQ_CFM]       = cl_msg_cfm_assign_and_clear,
+       [MM_UPDATE_RATE_DL_CFM]         = cl_msg_cfm_clear,
+       [MM_SET_VNS_CFM]                = cl_msg_cfm_clear,
+       [MM_SET_TX_BF_CFM]              = cl_msg_cfm_clear,
+       [MM_PHY_RESET_CFM]              = cl_msg_cfm_clear,
+       [MM_CONFIG_CCA_CFM]             = cl_msg_cfm_clear,
+       [MM_SET_DFS_CFM]                = cl_msg_cfm_clear,
+       [MM_SET_ANT_BITMAP_CFM]         = cl_msg_cfm_clear,
+       [MM_NDP_TX_CONTROL_CFM]         = cl_msg_cfm_clear,
+       [MM_REG_WRITE_CFM]              = cl_msg_cfm_clear,
+       [MM_PROT_MODE_CFM]              = cl_msg_cfm_clear,
+       [MM_GOTO_POWER_REDUCTION_CFM]   = cl_msg_cfm_clear,
+       [MM_SOUNDING_CFM]               = cl_msg_cfm_assign_and_clear,
+       [MM_SOUNDING_PAIRING_CFM]       = cl_msg_cfm_clear,
+       [MM_SOUNDING_INTERVAL_CFM]      = cl_msg_cfm_assign_and_clear,
+       [MM_SOUNDING_STA_SWITCH_CFM]    = cl_msg_cfm_assign_and_clear,
+       [MM_BACKUP_BCN_EN_CFM]          = cl_msg_cfm_clear,
+       [MM_START_PERIODIC_TX_TIME_CFM] = cl_msg_cfm_clear,
+       [MM_ANAMON_READ_CFM]            = cl_msg_cfm_assign_and_clear,
+       [MM_REFRESH_PWR_CFM]            = cl_msg_cfm_clear,
+       [MM_SET_ANT_PWR_OFFSET_CFM]     = cl_msg_cfm_clear,
+       [MM_SET_RATE_FALLBACK_CFM]      = cl_msg_cfm_clear,
+       [MM_TWT_SETUP_CFM]              = cl_msg_cfm_clear,
+       [MM_TWT_TEARDOWN_CFM]           = cl_msg_cfm_clear,
+       [MM_RSRC_MGMT_CFM]              = rx_mm_rsrc_mgmt_cfm,
+       [MM_SET_FREQ_OFFSET_CFM]        = cl_msg_cfm_clear,
+       [MM_AGG_TX_REPORT_IND]          = rx_mm_agg_tx_report_ind,
+       [MM_SOUNDING_IND]               = rx_mm_sounding_ind,
+       [MM_FW_ERROR_IND]               = rx_mm_fw_error_ind,
+       [MM_IDLE_ASYNC_IND]             = rx_mm_idle_async_ind,
+       [MM_RSRC_MGMT_IND]              = rx_mm_rsrc_mgmt_ind,
+       [MM_MAX]                        = NULL,
+};
+
+#define DBG_MSG_SHIFT(id)  ((id) - FIRST_MSG(TASK_DBG))
+
+static void (*dbg_hdlrs[])(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg) = {
+       [DBG_MSG_SHIFT(DBG_SET_MOD_FILTER_CFM)]         = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_SET_SEV_FILTER_CFM)]         = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_CE_SET_MOD_FILTER_CFM)]      = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_BEAMFORMING_TX_CFM)]         = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_GET_E2W_STATS_CFM)]          = cl_msg_cfm_assign_and_clear,
+       [DBG_MSG_SHIFT(DBG_SET_LA_MPIF_MASK_CFM)]       = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_SET_LA_TRIG_POINT_CFM)]      = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_SET_LA_MPIF_DEBUG_MODE_CFM)] = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_SET_LA_TRIG_RULE_CFM)]       = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_TX_TRACE_DEBUG_FLAG_CFM)]    = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_PRINT_STATS_CFM)]            = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_TRIGGER_CFM)]                = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_TEST_MODE_CFM)]              = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_SOUNDING_CMD_CFM)]           = cl_msg_cfm_clear,
+       [DBG_MSG_SHIFT(DBG_PRINT_IND)]                  = rx_dbg_print_ind,
+       [DBG_MSG_SHIFT(DBG_INFO_IND)]                   = rx_dbg_info_ind,
+       [DBG_MSG_SHIFT(DBG_MAX)]                        = NULL,
+};
+
+static bool is_dbg_msg(u16 msg_id)
+{
+       return (msg_id >= FIRST_MSG(TASK_DBG) && msg_id < DBG_MAX);
+}
+
+static void cl_msg_rx_run_mm(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg, u16 msg_id)
+{
+       if (msg_id < MM_REQ_CFM_MAX)
+               cl_dbg_trace(cl_hw, "%s\n", msg2str[msg_id]);
+
+       mm_hdlrs[msg_id](cl_hw, msg);
+}
+
+static int cl_msg_rx_run_dbg(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg, u16 msg_id)
+{
+       u16 dbg_id = DBG_MSG_SHIFT(msg_id);
+
+       if (dbg_hdlrs[dbg_id]) {
+               if (msg_id < DBG_REQ_CFM_MAX) {
+                       u16 str_id = DBG_STR_SHIFT(msg_id);
+
+                       cl_dbg_trace(cl_hw, "%s\n", msg2str[str_id]);
+               }
+
+               dbg_hdlrs[dbg_id](cl_hw, msg);
+               return 0;
+       }
+
+       return -1;
+}
+
+static int cl_msg_rx_run(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       u16 msg_id = le16_to_cpu(msg->id);
+
+       if (msg_id < MM_MAX && mm_hdlrs[msg_id]) {
+               cl_msg_rx_run_mm(cl_hw, msg, msg_id);
+               return 0;
+       }
+
+       if (is_dbg_msg(msg_id))
+               return cl_msg_rx_run_dbg(cl_hw, msg, msg_id);
+
+       return -1;
+}
+
+static bool is_cfm_msg(u16 msg_id)
+{
+       /* A confirmation must be an odd id */
+       if ((msg_id & 0x1) == 0)
+               return false;
+
+       return ((msg_id < MM_FIRST_IND) || is_dbg_msg(msg_id));
+}
+
+static int cl_msg_rx_handler(struct cl_hw *cl_hw, struct cl_ipc_e2a_msg *msg)
+{
+       int ret = 0;
+       u16 msg_id = le16_to_cpu(msg->id);
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_msg_rx_handler_start(cl_hw->idx, msg_id,
+                                           le32_to_cpu(msg->pattern), cl_hw->cfm_flags);
+#endif
+       /* Relay further actions to the msg parser */
+       ret = cl_msg_rx_run(cl_hw, msg);
+
+       if (ret) {
+               cl_dbg_err(cl_hw, "Unexpected msg (%u)\n", msg_id);
+       } else {
+               /* Wake up the queue in case the msg is a confirmation */
+               if (is_cfm_msg(msg_id))
+                       wake_up(&cl_hw->wait_queue);
+       }
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_msg_rx_handler_end(cl_hw->idx, cl_hw->cfm_flags);
+#endif
+
+       return ret;
+}
+
+void cl_msg_rx_tasklet(unsigned long data)
+{
+       struct cl_hw *cl_hw = (struct cl_hw *)data;
+       struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+       struct cl_e2a_msg_elem *msg_elem = NULL;
+       struct cl_ipc_e2a_msg *msg = NULL;
+       int msg_handled = 0;
+       u8 idx;
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_msg_rx_tasklet_start(cl_hw->idx);
+#endif
+
+       while (1) {
+               idx = ipc_env->e2a_msg_host_idx;
+               msg_elem = (struct cl_e2a_msg_elem *)(ipc_env->e2a_msg_hostbuf_array[idx].hostid);
+               msg = msg_elem->msgbuf_ptr;
+
+               /* Look for pattern which means that this hostbuf has been used for a MSG */
+               if (le32_to_cpu(msg->pattern) != IPC_E2A_MSG_VALID_PATTERN)
+                       break;
+
+               cl_msg_rx_handler(cl_hw, msg);
+               msg_handled++;
+
+               /* Reset the msg element and re-use it */
+               msg->pattern = 0;
+
+               /* Make sure memory is written before push to HW */
+               wmb();
+
+               /* Push back the buffer */
+               cl_ipc_msgbuf_push(ipc_env, (ptrdiff_t)msg_elem, msg_elem->dma_addr);
+       }
+
+#ifdef TRACE_SUPPORT
+       trace_cl_trace_msg_rx_tasklet_end(cl_hw->idx, msg_handled);
+#endif
+}
+
+void cl_msg_rx_flush_all(struct cl_hw *cl_hw)
+{
+       int i = 0;
+
+       for (i = FIRST_MSG(TASK_MM); i < MM_MAX; i++) {
+               if (cl_hw->msg_cfm_params[i]) {
+                       cl_dbg_verbose(cl_hw, "free MM msg_cfm_params %d\n", i);
+                       cl_msg_tx_free_cfm_params(cl_hw, i);
+               }
+       }
+
+       for (i = FIRST_MSG(TASK_DBG); i < DBG_MAX; i++) {
+               if (cl_hw->msg_cfm_params[i]) {
+                       cl_dbg_verbose(cl_hw, "free DBG msg_cfm_params %d\n", i);
+                       cl_msg_tx_free_cfm_params(cl_hw, i);
+               }
+       }
+}