Search Linux Wireless

[RFC v1 094/256] cl8k: add fw/msg_rx.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/fw/msg_rx.c | 349 +++++++++++++++++++
 1 file changed, 349 insertions(+)
 create mode 100644 drivers/net/wireless/celeno/cl8k/fw/msg_rx.c

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