new file mode 100644
@@ -0,0 +1,1800 @@
+// SPDX-License-Identifier: MIT
+/* Copyright(c) 2019-2021, Celeno Communications Ltd. */
+
+#include "chip.h"
+#include "tx/tx.h"
+#include "rx/rx.h"
+#include "fw/msg_tx.h"
+#include "fw/msg_cfm.h"
+#include "fw/fw_msg.h"
+#include "drv_ops.h"
+#include "temperature.h"
+#include "chan_info.h"
+#include "power.h"
+#include "env_det.h"
+#include "rx/rx_filter.h"
+#include "prot_mode.h"
+#include "rate_ctrl.h"
+#include "utils/utils.h"
+#include "calib.h"
+#include "band.h"
+#include "reg/reg_riu.h"
+#include "reg/reg_ricu.h"
+#include "calib.h"
+#include "recovery.h"
+#include "utils/math.h"
+#include "fem.h"
+#include "agc_params.h"
+#include "mac_addr.h"
+#include "cap.h"
+#include "ampdu.h"
+#include "phy/phy_common_lut.h"
+#include "channel.h"
+
+#define DRV_TASK_ID 100
+
+#define CL_DEF_ANT_BITMAP 0x55
+
+/* No scale-down on ASIC platform */
+#define CL_ASIC_FW_SCALEDOWN 1
+
+struct cl_msg_tx_work {
+ struct work_struct ws;
+
+ /* Background message info */
+ struct cl_hw *cl_hw;
+ void *msg_params;
+};
+
+void cl_msg_tx_free_cfm_params(struct cl_hw *cl_hw, u16 id)
+{
+ /* Free message and set pointer to NULL */
+ kfree(cl_hw->msg_cfm_params[id]);
+ cl_hw->msg_cfm_params[id] = NULL;
+}
+
+static inline void *cl_msg_zalloc(struct cl_hw *cl_hw, u16 msg_id, u8 dst_task_id, u16 param_len)
+{
+ struct fw_msg *msg;
+ u32 total_size = ALIGN(sizeof(struct fw_msg) + param_len, sizeof(u32));
+ u32 max_size = sizeof(u32) * IPC_A2E_MSG_BUF_SIZE;
+
+ if (total_size > max_size) {
+ cl_dbg_err(cl_hw, "total size (%u) > max size (%u)\n",
+ total_size, max_size);
+ return NULL;
+ }
+
+ /* msg is freed out of the scope of this function */
+ msg = kzalloc(total_size, GFP_ATOMIC);
+ if (!msg)
+ return NULL;
+
+ msg->msg_id = cpu_to_le16(msg_id);
+ msg->dst_kern_id = cl_hw->fw_dst_kern_id;
+ msg->dst_task_id = dst_task_id;
+ msg->src_kern_id = KERN_HOST;
+ msg->src_task_id = DRV_TASK_ID;
+ msg->param_len = cpu_to_le16(param_len);
+
+ return msg->param;
+}
+
+static inline void cl_msg_free(const void *msg_param)
+{
+ kfree(container_of((void *)msg_param, struct fw_msg, param));
+}
+
+static void cl_send_msg_background_handler(struct work_struct *ws)
+{
+ struct cl_msg_tx_work *msg_tx_work = container_of(ws, struct cl_msg_tx_work, ws);
+
+ cl_drv_ops_msg_fw_send(msg_tx_work->cl_hw, msg_tx_work->msg_params, true);
+ kfree(msg_tx_work);
+}
+
+static int cl_send_msg_background(struct cl_hw *cl_hw,
+ const void *msg_params)
+{
+ /* Generate & populate the work struct wrapper for the background msg */
+ struct cl_msg_tx_work *msg_tx_work = kzalloc(sizeof(*msg_tx_work), GFP_ATOMIC);
+
+ if (msg_tx_work) {
+ INIT_WORK(&msg_tx_work->ws, cl_send_msg_background_handler);
+ msg_tx_work->cl_hw = cl_hw;
+ msg_tx_work->msg_params = (void *)msg_params;
+
+ /* Schedule work, the work will be executed in the background */
+ queue_work(cl_hw->drv_workqueue, &msg_tx_work->ws);
+
+ return 0;
+ }
+
+ cl_dbg_err(cl_hw, "msg_tx_work allocation failed\n");
+ cl_msg_free(msg_params);
+
+ return -ENODATA;
+}
+
+static int cl_send_request(struct cl_hw *cl_hw, const void *msg_params)
+{
+ int ret;
+ bool background = (preempt_count() != 0);
+
+ if (background) {
+ /*
+ * asynchronous operation mode, message would be triggered in the background
+ */
+ ret = cl_send_msg_background(cl_hw, msg_params);
+ } else {
+ /*
+ * synchronous operation mode, message would be triggered immediately
+ * feedback to caller given immediately
+ */
+ ret = cl_drv_ops_msg_fw_send(cl_hw, msg_params, false);
+ }
+
+ /*
+ * In case of synchronous mode ret success implies that the msg was successfully
+ * transmited where is asynchronous mode ret success implies that the msg was
+ * successfully pushed to background queue
+ */
+ return ret;
+}
+
+int cl_msg_tx_reset(struct cl_hw *cl_hw)
+{
+ void *void_param;
+
+ /* RESET REQ has no parameter */
+ void_param = cl_msg_zalloc(cl_hw, MM_RESET_REQ, TASK_MM, 0);
+ if (!void_param)
+ return -ENOMEM;
+
+ return cl_send_request(cl_hw, void_param);
+}
+
+static u8 copy_mask_bits(u8 mask, u8 num_bits)
+{
+ /* Copy first X bits that are set in mask to new_mask */
+ u8 i = 0, cntr = 0, new_mask = 0;
+
+ for (i = 0; i < MAX_ANTENNAS; i++) {
+ if (mask & (1 << i)) {
+ new_mask |= (1 << i);
+
+ cntr++;
+ if (cntr == num_bits)
+ break;
+ }
+ }
+
+ return new_mask;
+}
+
+static void cl_fill_ant_config(struct cl_hw *cl_hw,
+ struct cl_antenna_config *ant_config,
+ u8 num_antennas, u8 mask_antennas,
+ u8 tx_mask_cck, u8 rx_mask_cck)
+{
+ struct cl_chip *chip = cl_hw->chip;
+ u8 ricu_cdb = 0;
+ u8 ant_shift = cl_hw_ant_shift(cl_hw);
+
+ ant_config->num_tx_he = num_antennas;
+ ant_config->num_rx = num_antennas;
+ ant_config->mask_tx_he = mask_antennas << ant_shift;
+ ant_config->mask_rx = mask_antennas << ant_shift;
+
+ /* Configuration for TX OFDM/HT/VHT (limited to 4 antennas) */
+ if (num_antennas <= MAX_ANTENNAS_OFDM_HT_VHT) {
+ ant_config->num_tx_ofdm_ht_vht = num_antennas;
+ ant_config->mask_tx_ofdm_ht_vht = mask_antennas << ant_shift;
+ } else {
+ ant_config->num_tx_ofdm_ht_vht = MAX_ANTENNAS_OFDM_HT_VHT;
+ ant_config->mask_tx_ofdm_ht_vht =
+ copy_mask_bits(mask_antennas, MAX_ANTENNAS_OFDM_HT_VHT) << ant_shift;
+ }
+
+ /* Antenna configuration for CCK */
+ if (cl_band_is_24g(cl_hw)) {
+ ant_config->mask_tx_cck = tx_mask_cck << ant_shift;
+ ant_config->mask_rx_cck = rx_mask_cck << ant_shift;
+ }
+
+ ricu_cdb = ricu_static_conf_0_cdb_mode_maj_getf(chip);
+
+ /*
+ * In current implementation cdb_mode equals the num of ants for SX1
+ * cbd_mask 0x0 -> SX0 chain. 0x1-> SX1 chain.
+ */
+ ricu_cdb = MAX_ANTENNAS_CHIP - ricu_cdb;
+ ricu_cdb = ANT_MASK(ricu_cdb);
+ ricu_cdb = ~ricu_cdb;
+
+ ant_config->cdb_mask = ricu_cdb;
+}
+
+static void cl_fill_fem_config(struct cl_hw *cl_hw, struct cl_fem_config *fem_conf)
+{
+ int i;
+
+ cl_fem_get_registers(cl_hw, fem_conf->reg);
+
+ for (i = 0; i < ARRAY_SIZE(fem_conf->reg); i++)
+ fem_conf->reg[i] = cpu_to_le32(fem_conf->reg[i]);
+}
+
+static void cl_fill_calib_config(struct cl_hw *cl_hw, struct cl_calib_param *calib_param,
+ u16 primary, u16 center, u8 mode)
+{
+ struct cl_hw *cl_hw_other = cl_hw_other_tcv(cl_hw);
+ struct cl_tcv_conf *conf = cl_hw->conf;
+ u8 ant = 0;
+ u8 calib_bitmap = cl_hw->mask_num_antennas;
+ u8 ant_shift = cl_hw_ant_shift(cl_hw);
+
+ memset(calib_param->ant_tx_pairs, U8_MAX, ARRAY_SIZE(calib_param->ant_tx_pairs));
+ memset(calib_param->ant_rx_pairs, U8_MAX, ARRAY_SIZE(calib_param->ant_rx_pairs));
+
+ ant_for_each(ant) {
+ if (calib_bitmap & (1 << ant)) {
+ calib_param->ant_tx_pairs[ant] = conf->ci_calib_ant_tx[ant - ant_shift];
+ if (mode & SET_CHANNEL_MODE_CALIB_IQ)
+ calib_param->ant_rx_pairs[ant] =
+ conf->ci_calib_ant_rx[ant - ant_shift];
+ }
+ }
+
+ if (IS_PHY_ATHOS(cl_hw->chip)) {
+ calib_param->conf.initial_rx_gain = CALIB_RX_GAIN_DEFAULT_ATHOS;
+ calib_param->conf.rx_gain_upper_limit = CALIB_RX_GAIN_UPPER_LIMIT_ATHOS;
+ calib_param->conf.rx_gain_lower_limit = CALIB_RX_GAIN_LOWER_LIMIT_ATHOS;
+ } else {
+ calib_param->conf.initial_rx_gain = CALIB_RX_GAIN_DEFAULT;
+ calib_param->conf.rx_gain_upper_limit = CALIB_RX_GAIN_UPPER_LIMIT;
+ calib_param->conf.rx_gain_lower_limit = CALIB_RX_GAIN_LOWER_LIMIT;
+ }
+
+ calib_param->conf.initial_tx_gain = CALIB_TX_GAIN_DEFAULT;
+ calib_param->conf.nco_freq = cpu_to_le16(CALIB_NCO_FREQ_DEFAULT);
+ calib_param->conf.nco_amp = CALIB_NCO_AMP_DEFAULT;
+ calib_param->conf.sleeve_trshld = GAIN_SLEEVE_TRSHLD_DEFAULT;
+ calib_param->conf.n_samples_exp_lolc = N_SAMPLES_EXP_LOLC;
+ calib_param->conf.n_samples_exp_iqc = N_SAMPLES_EXP_IQC;
+ calib_param->conf.p_thresh = cpu_to_le32(LO_P_THRESH);
+ calib_param->conf.n_bit_fir_scale = N_BIT_FIR_SCALE;
+ calib_param->conf.n_bit_amp_scale = N_BIT_AMP_SCALE;
+ calib_param->conf.n_bit_phase_scale = N_BIT_PHASE_SCALE;
+
+ cl_calib_iq_get_tone_vector(cl_hw->bw, calib_param->conf.tone_vector);
+
+ calib_param->conf.gp_rad_trshld = cpu_to_le32(GP_RAD_TRSHLD_DEFAULT);
+ calib_param->conf.ga_lin_upper_trshld = cpu_to_le32(GA_LIN_UPPER_TRSHLD_DEFAULT);
+ calib_param->conf.ga_lin_lower_trshld = cpu_to_le32(GA_LIN_LOWER_TRSHLD_DEFAULT);
+ calib_param->conf.comp_filter_len = COMP_FILTER_LEN_DEFAULT;
+ calib_param->conf.singletons_num = SINGLETONS_NUM_DEFAULT;
+ calib_param->conf.tones_num = IQ_NUM_TONES_REQ;
+ calib_param->conf.rampup_time = cpu_to_le16(RAMPUP_TIME);
+ calib_param->conf.lo_coarse_step = cpu_to_le16(LO_COARSE_STEP);
+ calib_param->conf.lo_fine_step = cpu_to_le16(LO_FINE_STEP);
+
+ calib_param->other_tcv.prim20_freq = cpu_to_le16(primary + SX_FREQ_OFFSET_Q2);
+ cl_phy_oly_lut_update(cl_hw->nl_band,
+ center + SX_FREQ_OFFSET_Q2,
+ &calib_param->other_tcv.center1_freq_lut);
+
+ if (cl_chip_is_both_enabled(cl_hw->chip)) {
+ calib_param->other_tcv.mask_tx_he = cl_hw_other->mask_num_antennas;
+ calib_param->other_tcv.num_tx_he = cl_hw_other->num_antennas;
+ calib_param->other_tcv.band = cl_band_to_fw_idx(cl_hw_other);
+ } else {
+ calib_param->other_tcv.mask_tx_he = cl_hw->mask_num_antennas;
+ calib_param->other_tcv.num_tx_he = cl_hw->num_antennas;
+ calib_param->other_tcv.band = cl_band_to_fw_idx(cl_hw);
+ }
+}
+
+int cl_msg_tx_start(struct cl_hw *cl_hw)
+{
+ struct mm_start_req *req;
+ struct cl_phy_cfg *phy_cfg;
+ struct cl_start_param *param;
+ struct cl_cca_config *cca_config;
+ struct dbg_meta_data *dbg_metadata;
+ struct cl_chip *chip = cl_hw->chip;
+ struct cl_tcv_conf *tcv_conf = cl_hw->conf;
+ struct cl_chip_conf *chip_conf = chip->conf;
+ struct cl_ipc_host_env *ipc_env = cl_hw->ipc_env;
+ u8 bw = 0, ant = 0;
+
+ req = cl_msg_zalloc(cl_hw, MM_START_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ phy_cfg = &req->phy_cfg;
+ param = &req->param;
+ cca_config = &phy_cfg->cca_config;
+ dbg_metadata = ¶m->dbg_metadata;
+
+ phy_cfg->band = cl_band_to_fw_idx(cl_hw);
+ phy_cfg->channel_bandwidth = tcv_conf->ce_channel_bandwidth;
+ phy_cfg->ht_rxldpc_en = tcv_conf->ce_ht_rxldpc_en;
+ phy_cfg->freq_offset = cpu_to_le16(chip->eeprom_cache->calib.freq_offset);
+ phy_cfg->vns_tx_power_mode = chip_conf->ce_production_mode ? 0 : tcv_conf->ci_vns_pwr_mode;
+ phy_cfg->vns_rssi_suto_resp_th = tcv_conf->ci_vns_rssi_auto_resp_thr;
+ phy_cfg->afe_config_en = true;
+ phy_cfg->no_capture_noise_sleep = chip_conf->ci_no_capture_noise_sleep;
+ phy_cfg->gain_update_enable = tcv_conf->ci_gain_update_enable;
+ phy_cfg->mcs_sig_b = tcv_conf->ci_mcs_sig_b;
+ phy_cfg->ofdm_only = tcv_conf->ci_ofdm_only;
+ phy_cfg->hr_factor = tcv_conf->ci_hr_factor[phy_cfg->channel_bandwidth];
+ phy_cfg->td_csd_en = tcv_conf->ci_csd_en;
+ phy_cfg->pe_duration_bcast = tcv_conf->ci_pe_duration_bcast;
+ phy_cfg->tx_digital_gain = cpu_to_le32(tcv_conf->ci_tx_digital_gain);
+ phy_cfg->tx_digital_gain_cck = cpu_to_le32(tcv_conf->ci_tx_digital_gain_cck);
+ phy_cfg->ofdm_cck_power_offset = (u8)tcv_conf->ci_ofdm_cck_power_offset;
+ phy_cfg->phy_clk_gating_en = tcv_conf->ci_phy_clk_gating_en;
+
+ /*
+ * Set rx_sensitivity according to number of antennas.
+ * For all other antennas set 0xff which is equal to -1
+ */
+ memcpy(phy_cfg->rx_sensitivity, cl_hw->rx_sensitivity, cl_hw->num_antennas);
+ if (cl_hw->num_antennas < ARRAY_SIZE(phy_cfg->rx_sensitivity))
+ memset(&phy_cfg->rx_sensitivity[cl_hw->num_antennas], U8_MAX,
+ MAX_ANTENNAS - cl_hw->num_antennas);
+
+ if (!cl_hw->fw_send_start) {
+ cl_hw->fw_send_start = true;
+ phy_cfg->first_start = true;
+ }
+
+ cl_fill_ant_config(cl_hw, &phy_cfg->ant_config, cl_hw->num_antennas,
+ cl_hw->mask_num_antennas, tcv_conf->ce_cck_tx_ant_mask,
+ tcv_conf->ce_cck_rx_ant_mask);
+ cl_fill_fem_config(cl_hw, &phy_cfg->fem_conf);
+
+ cca_config->ed_rise_thr_dbm = (u8)tcv_conf->ci_cca_ed_rise_thr_dbm;
+ cca_config->ed_fall_thr_dbm = (u8)tcv_conf->ci_cca_ed_fall_thr_dbm;
+ cca_config->cs_en = tcv_conf->ci_cca_cs_en;
+ cca_config->modem_en = tcv_conf->ci_cca_modem_en;
+ cca_config->main_ant = tcv_conf->ci_cca_main_ant;
+ cca_config->second_ant = tcv_conf->ci_cca_second_ant;
+ cca_config->flag0_ctrl = tcv_conf->ci_cca_flag0_ctrl;
+ cca_config->flag1_ctrl = tcv_conf->ci_cca_flag1_ctrl;
+ cca_config->flag2_ctrl = tcv_conf->ci_cca_flag2_ctrl;
+ cca_config->flag3_ctrl = tcv_conf->ci_cca_flag3_ctrl;
+ cca_config->gi_rise_thr_dbm = (u8)tcv_conf->ci_cca_gi_rise_thr_dbm;
+ cca_config->gi_fall_thr_dbm = (u8)tcv_conf->ci_cca_gi_fall_thr_dbm;
+ cca_config->gi_pow_lim_dbm = (u8)tcv_conf->ci_cca_gi_pow_lim_dbm;
+ cca_config->ed_en = cpu_to_le16(tcv_conf->ci_cca_ed_en);
+ cca_config->gi_en = tcv_conf->ci_cca_gi_en;
+
+ param->prot_log_nav_en = tcv_conf->ce_prot_log_nav_en;
+ param->prot_mode = cl_prot_mode_get(cl_hw);
+ param->prot_rate_format = tcv_conf->ce_prot_rate_format;
+ param->prot_rate_mcs = tcv_conf->ce_prot_rate_mcs;
+ param->prot_rate_pre_type = tcv_conf->ce_prot_rate_pre_type;
+ param->bw_signaling_mode = tcv_conf->ce_bw_signaling_mode;
+ param->cfm_size = cpu_to_le16(IPC_CFM_SIZE);
+ param->cfm_dma_base_addr = cpu_to_le32(ipc_env->cfm_dma_base_addr);
+ param->phy_dev = cpu_to_le16(chip_conf->ci_phy_dev);
+ param->fw_scale_down = cpu_to_le16(CL_ASIC_FW_SCALEDOWN);
+ param->hal_timeout.idle = cpu_to_le32(tcv_conf->ci_hal_idle_to);
+ param->hal_timeout.ac0 = cpu_to_le32(tcv_conf->ci_tx_ac0_to);
+ param->hal_timeout.ac1 = cpu_to_le32(tcv_conf->ci_tx_ac1_to);
+ param->hal_timeout.ac2 = cpu_to_le32(tcv_conf->ci_tx_ac2_to);
+ param->hal_timeout.ac3 = cpu_to_le32(tcv_conf->ci_tx_ac3_to);
+ param->hal_timeout.bcn = cpu_to_le32(tcv_conf->ci_tx_bcn_to);
+
+ /* Update rxbuff/txqueue & ring_indices that hold the array metadata */
+ param->ipc_ring_indices_base = cpu_to_le32(ipc_env->ring_indices_elem->dma_addr);
+ param->host_rxbuf_base_addr[CL_RX_BUF_RXM] =
+ ipc_env->rx_hostbuf_array[CL_RX_BUF_RXM].dma_payload_base_addr;
+ param->host_rxbuf_base_addr[CL_RX_BUF_FW] =
+ ipc_env->rx_hostbuf_array[CL_RX_BUF_FW].dma_payload_base_addr;
+
+ /*
+ * The FW needs to be aware of the DMA addresses of the
+ * TX queues so it could fetch txdesc from the host.
+ */
+ param->ipc_host_tx_queues_dma_addr = cpu_to_le32(cl_hw->ipc_env->tx_queues.dma_addr);
+
+ /*
+ * Compilation flags match check - please add here all compilation flags
+ * which should be compiled on both driver and firmware.
+ */
+ param->comp_flags = cpu_to_le32(0) | cpu_to_le32(BIT(CENX_CFG_CE_TX_CFM));
+
+ param->dbg_test_mode_max = DBG_TEST_MODE_MAX;
+
+ param->ipc_rxbuf_size[CL_RX_BUF_RXM] =
+ cpu_to_le16(tcv_conf->ci_ipc_rxbuf_size[CL_RX_BUF_RXM]);
+ param->ipc_rxbuf_size[CL_RX_BUF_FW] =
+ cpu_to_le16(tcv_conf->ci_ipc_rxbuf_size[CL_RX_BUF_FW]);
+
+ param->ipc_rxbuf_extra_headroom = cpu_to_le32(IPC_RXBUF_EXTRA_HEADROOM);
+ param->host_pci_gen_ver = chip_conf->ce_host_pci_gen_ver;
+ param->dma_lli_max_chan[0] = chip_conf->ci_dma_lli_max_chan[0];
+ param->dma_lli_max_chan[1] = chip_conf->ci_dma_lli_max_chan[1];
+ param->production_mode = chip_conf->ce_production_mode;
+ param->mult_ampdu_in_txop_en = tcv_conf->ci_mult_ampdu_in_txop_en;
+ param->cca_timeout = cpu_to_le32(tcv_conf->ci_cca_timeout);
+ param->long_retry_limit = tcv_conf->ce_long_retry_limit;
+ param->short_retry_limit = tcv_conf->ce_short_retry_limit;
+ param->assoc_auth_retry_limit = tcv_conf->ci_assoc_auth_retry_limit;
+ param->bcn_tx_path_min_time = cpu_to_le16(tcv_conf->ce_bcn_tx_path_min_time);
+ param->backup_bcn_en = tcv_conf->ci_backup_bcn_en;
+ param->tx_txop_cut_en = tcv_conf->ce_tx_txop_cut_en;
+ param->ac_with_bcns_flushed_cnt_thr = tcv_conf->ci_bcns_flushed_cnt_thr;
+ param->txl_statistics_struct_size = cpu_to_le32(sizeof(struct cl_txl_statistics));
+ param->rxl_statistics_struct_size = cpu_to_le32(sizeof(struct cl_rxl_statistics));
+ param->phy_err_prevents_phy_dump = tcv_conf->ci_phy_err_prevents_phy_dump;
+ param->tx_rx_delay = tcv_conf->ci_tx_rx_delay;
+ param->assert_storm_detect_thd = tcv_conf->ci_fw_assert_storm_detect_thd;
+ param->assert_time_diff_sec = tcv_conf->ci_fw_assert_time_diff_sec;
+ param->ps_ctrl_enabled = tcv_conf->ce_ps_ctrl_enabled;
+ param->phy_data_dma_addr = cpu_to_le32(cl_hw->phy_data_info.dma_addr);
+ param->phy_remote_rom_dma_addr = cpu_to_le32(cl_hw->fw_remote_rom.dma_addr);
+ param->iq_dcoc_calib_tables_dma_addr = cpu_to_le32(cl_hw->iq_dcoc_data_info.dma_addr);
+ param->power_table_dma_addr = cpu_to_le32(cl_hw->power_table_info.dma_addr);
+ param->tf_info_dma_addr = 0;
+ param->min_ant_pwr_q1 = cl_power_min_ant_q1(cl_hw);
+
+ for (bw = 0; bw < ARRAY_SIZE(param->bw_factor_q2); bw++) {
+ cl_hw->power_db.bw_factor_q2[bw] = cl_power_bw_factor_q2(cl_hw, bw);
+ param->bw_factor_q2[bw] =
+ cl_convert_signed_to_reg_value(cl_hw->power_db.bw_factor_q2[bw]);
+ }
+
+ for (ant = 0; ant < ARRAY_SIZE(param->ant_factor_q2); ant++) {
+ cl_hw->power_db.ant_factor_q2[ant] = cl_power_array_gain_q2(cl_hw, ant + 1);
+ param->ant_factor_q2[ant] = cl_hw->power_db.ant_factor_q2[ant];
+ }
+
+ param->default_distance.auto_resp_all = tcv_conf->ci_distance_auto_resp_all;
+ param->default_distance.auto_resp_msta = tcv_conf->ci_distance_auto_resp_msta;
+ param->su_force_min_spacing_usec = tcv_conf->ci_su_force_min_spacing;
+ param->mu_force_min_spacing_usec = tcv_conf->ci_mu_force_min_spacing;
+ param->force_tcv0_only = false;
+ param->rx_padding = tcv_conf->ci_rx_padding_en;
+ param->bar_cap_disable = tcv_conf->ci_bar_disable;
+ param->hw_bsr = 0; /* FIXME */
+ param->drop_to_lower_bw = tcv_conf->ci_drop_to_lower_bw;
+ param->dra_enable = cl_chip_is_both_enabled(chip); /* DRA enable only in CDB mode */
+ param->mac_clk_gating_en = tcv_conf->ci_mac_clk_gating_en;
+ param->imaging_blocker = tcv_conf->ci_imaging_blocker;
+ param->fec_coding = tcv_conf->ce_he_rxldpc_en;
+ param->cs_required = tcv_conf->ci_cs_required;
+
+ if (!chip->fw_first_tcv) {
+ chip->fw_first_tcv = true;
+ param->first_tcv = true;
+ }
+
+ dbg_metadata->lmac_req_buf_size = cpu_to_le32(sizeof(struct dbg_error_trace_info_drv));
+ dbg_metadata->physical_queue_cnt = CL_MAX_BA_PHYSICAL_QUEUE_CNT;
+ dbg_metadata->agg_index_max = AGG_IDX_MAX;
+ dbg_metadata->ce_ac_max = CE_AC_MAX;
+ dbg_metadata->mu_user_max = MU_MAX_STREAMS;
+ dbg_metadata->txl_exch_trace_depth = DBG_TXL_FRAME_EXCH_TRACE_DEPTH;
+ dbg_metadata->mac_hw_regs_max = cpu_to_le16(HAL_MACHW_REG_NUM);
+ dbg_metadata->phy_hw_regs_max = cpu_to_le16(PHY_HW_DBG_REGS_CNT);
+ dbg_metadata->thd_chains_data_size = cpu_to_le16(DBG_THD_CHAINS_INFO_ARRAY_SIZE);
+ dbg_metadata->chains_info_elem_cnt = DBG_CHAINS_INFO_ELEM_CNT;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_version(struct cl_hw *cl_hw)
+{
+ void *void_param;
+
+ /* VERSION REQ has no parameter */
+ void_param = cl_msg_zalloc(cl_hw, MM_VERSION_REQ, TASK_MM, 0);
+ if (!void_param)
+ return -ENOMEM;
+
+ return cl_send_request(cl_hw, void_param);
+}
+
+int cl_msg_tx_add_if(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+ u8 vif_index)
+{
+ struct mm_add_if_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_ADD_IF_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ cl_mac_addr_copy(req->addr.array, vif->addr);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ req->type = MM_STA;
+ break;
+
+ case NL80211_IFTYPE_ADHOC:
+ req->type = MM_IBSS;
+ break;
+
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ req->type = MM_AP;
+ break;
+
+ case NL80211_IFTYPE_MONITOR:
+ req->type = MM_MONITOR;
+ break;
+
+ case NL80211_IFTYPE_MESH_POINT:
+ req->type = MM_MESH_POINT;
+ break;
+
+ default:
+ req->type = MM_STA;
+ break;
+ }
+
+ req->tx_strip_vlan = 1;
+ req->mac_addr_hi_mask = cpu_to_le32(cl_hw->mask_hi);
+ req->mac_addr_low_mask = cpu_to_le32(cl_hw->mask_low);
+ req->inst_nbr = vif_index;
+
+ if (vif->type == NL80211_IFTYPE_AP) {
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ps_data *ps = &sdata->u.ap.ps;
+
+ req->start_dtim_count = (u8)(ps->dtim_count);
+ }
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_remove_if(struct cl_hw *cl_hw, u8 vif_index)
+{
+ struct mm_remove_if_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_REMOVE_IF_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->inst_nbr = vif_index;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sta_add(struct cl_hw *cl_hw, struct ieee80211_sta *sta,
+ struct cl_vif *cl_vif, u8 recovery_sta_idx,
+ u32 rate_ctrl_info)
+{
+ struct mm_sta_add_req *req;
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+ struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+ struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
+ u16 my_aid = 0;
+ u8 inst_nbr = cl_vif->vif_index;
+ bool is_6g = cl_band_is_6g(cl_hw);
+ struct cl_sta *cl_sta = IEEE80211_STA_TO_CL_STA(sta);
+
+ req = cl_msg_zalloc(cl_hw, MM_STA_ADD_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ cl_mac_addr_copy(req->mac_addr.array, sta->addr);
+
+ if (cl_vif->vif->type == NL80211_IFTYPE_STATION)
+ my_aid = cl_vif->vif->bss_conf.aid;
+
+ if (is_6g) {
+ u8 mac_cap_info4 = he_cap->he_cap_elem.mac_cap_info[4];
+
+ req->su_bfee = (mac_cap_info4 & IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE) ? 1 : 0;
+ req->mu_bfee = (mac_cap_info4 & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER) ? 1 : 0;
+ } else if (vht_cap->vht_supported) {
+ req->su_bfee = (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) ? 1 : 0;
+ req->mu_bfee = (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) ? 1 : 0;
+ }
+
+ req->ampdu_min_spacing = cl_sta->ampdu_min_spacing;
+
+ if (he_cap->has_he) {
+ u8 mac_cap_info1 = he_cap->he_cap_elem.mac_cap_info[1];
+ u8 mac_cap_info3 = he_cap->he_cap_elem.mac_cap_info[3];
+
+ req->he_tf_mac_padding_duration =
+ (mac_cap_info1 & IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK);
+
+ req->he_rx_ctrl_frm_to_mbss =
+ (mac_cap_info3 & IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS) ?
+ true : false;
+
+ /* Fill PE duration table */
+ cl_cap_ppe_duration(cl_hw, sta, req->pe_duration);
+ }
+
+ cl_ampdu_size_exp(cl_hw, sta, &req->ampdu_size_exp_he,
+ &req->ampdu_size_exp_vht, &req->ampdu_size_exp_ht);
+
+ if (cl_hw->conf->ce_txldpc_en) {
+ if (he_cap->has_he)
+ req->ldpc_enabled = (he_cap->he_cap_elem.phy_cap_info[1] &
+ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) ? 1 : 0;
+ else if (vht_cap->vht_supported)
+ req->ldpc_enabled = (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC) ? 1 : 0;
+ else if (ht_cap->ht_supported)
+ req->ldpc_enabled = (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) ? 1 : 0;
+ }
+
+ /* TODO Set the interface index from the vif structure */
+ req->inst_nbr = inst_nbr;
+
+ req->aid = cpu_to_le16(sta->aid);
+ req->my_aid = cpu_to_le16(my_aid);
+ req->recovery_sta_idx = recovery_sta_idx;
+
+ /* Station power save configuration */
+ req->uapsd_queues = sta->uapsd_queues;
+ req->max_sp = sta->max_sp;
+
+ /* Set WRS default parameters for rate control */
+ req->tx_params.rate = cpu_to_le32(rate_ctrl_info);
+
+ /* Fill TX antenna with default value */
+ req->tx_params.ant_set = CL_DEF_ANT_BITMAP;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sta_del(struct cl_hw *cl_hw, u8 sta_idx)
+{
+ struct mm_sta_del_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_STA_DEL_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sta_idx = sta_idx;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_filter(struct cl_hw *cl_hw, u32 filter, bool force)
+{
+ struct mm_set_filter_req *req;
+ u32 rx_filter = 0;
+
+ if (cl_channel_is_scan_active(cl_hw)) {
+ cl_dbg_trace(cl_hw, "Set filter ignored due to active channel scan\n");
+ return 0;
+ }
+
+ if (force)
+ rx_filter = filter;
+ else
+ rx_filter = cl_rx_filter_update_flags(cl_hw, filter);
+
+ if (rx_filter == cl_hw->rx_filter) {
+ cl_dbg_trace(cl_hw, "Rx filter 0x%x already set - return\n", rx_filter);
+ return 0;
+ }
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_FILTER_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Now copy all the flags into the message parameter */
+ req->filter = cpu_to_le32(rx_filter);
+ cl_hw->rx_filter = rx_filter;
+
+ cl_dbg_trace(cl_hw, "new total_flags = 0x%08x\nrx filter set to 0x%08x\n",
+ filter, rx_filter);
+
+ return cl_send_request(cl_hw, req);
+}
+
+u8 cl_mark_calib_flags(struct cl_hw *cl_hw, u8 mode)
+{
+ int lna = 0;
+ int ant = 0;
+ u8 calib_info_set = 0;
+ struct cl_iq_dcoc_info *iq_dcoc_db = &cl_hw->phy_data_info.data->iq_dcoc_db;
+
+ /* In case DCOC is going to be calibrated, no need to raise any calibration flag. */
+ if (mode & SET_CHANNEL_MODE_CALIB_DCOC)
+ return calib_info_set;
+
+ /* Check if DCOC flag should be marked */
+ for (lna = 0; lna < ARRAY_SIZE(iq_dcoc_db->dcoc); lna++) {
+ for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+ if (iq_dcoc_db->dcoc[lna][ant].i || iq_dcoc_db->dcoc[lna][ant].q) {
+ calib_info_set |= SET_PHY_DATA_FLAGS_DCOC;
+ break;
+ }
+ }
+ }
+
+ /* Check if IQ Tx LOLC flag should be marked */
+ for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+ if (iq_dcoc_db->iq_tx_lolc[ant]) {
+ calib_info_set |= SET_PHY_DATA_FLAGS_IQ_TX_LOLC;
+ break;
+ }
+ }
+
+ /* Check if IQ Tx flag should be marked */
+ for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+ if (iq_dcoc_db->iq_tx[ant].coef0 || iq_dcoc_db->iq_tx[ant].coef1 ||
+ iq_dcoc_db->iq_tx[ant].coef2 || iq_dcoc_db->iq_tx[ant].gain) {
+ calib_info_set |= SET_PHY_DATA_FLAGS_IQ_TX;
+ break;
+ }
+ }
+
+ /* Check if IQ Rx flag should be marked */
+ for (ant = 0; ant < cl_hw->num_antennas; ant++) {
+ if (iq_dcoc_db->iq_rx[ant].coef0 || iq_dcoc_db->iq_rx[ant].coef1 ||
+ iq_dcoc_db->iq_rx[ant].coef2 || iq_dcoc_db->iq_rx[ant].gain) {
+ calib_info_set |= SET_PHY_DATA_FLAGS_IQ_RX;
+ return calib_info_set;
+ }
+ }
+ return calib_info_set;
+}
+
+static int __cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u16 primary,
+ u16 center, u8 mode)
+{
+ struct mm_set_channel_req *req;
+ int res = 0;
+ struct cl_phy_data *data = cl_hw->phy_data_info.data;
+
+ /* Fill AGC parameters - check before we start building the message */
+ if ((res = cl_agc_params_fill(cl_hw, &data->agc_params)))
+ return res;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_CHANNEL_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->band = cl_band_to_fw_idx(cl_hw);
+ req->bandwidth = bw;
+ req->prim20_freq = cpu_to_le16(primary);
+ cl_phy_oly_lut_update(cl_hw->nl_band, center, &req->center1_freq_lut);
+ req->hr_factor = cl_hw->conf->ci_hr_factor[bw];
+ req->signal_ext = cl_hw->conf->ci_signal_extension_en;
+
+ /* Set power per mcs offset after EIRP truncation */
+ cl_power_tables_update(cl_hw, &data->pwr_tables);
+
+ /* Get antenna power offset from eeprom */
+ cl_calib_power_offset_fill(cl_hw, channel, bw, req->ant_pwr_offset);
+
+ cl_calib_fill_phy_data(cl_hw, &data->iq_dcoc_db, SET_PHY_DATA_FLAGS_ALL);
+
+ if (mode == SET_CHANNEL_MODE_CALIB)
+ req->calib_info_set = SET_PHY_DATA_FLAGS_ALL;
+ else
+ req->calib_info_set = SET_PHY_DATA_FLAGS_NONE;
+
+ req->calib_param.mode = mode;
+
+ if (mode & (SET_CHANNEL_MODE_CALIB_LOLC | SET_CHANNEL_MODE_CALIB_IQ)) {
+ req->sx_freq_offset_mhz = SX_FREQ_OFFSET_Q2;
+ cl_fill_calib_config(cl_hw, &req->calib_param, primary, center, mode);
+ }
+
+ if (mode & SET_CHANNEL_MODE_CALIB_DCOC) {
+ if (IS_PHY_ATHOS(cl_hw->chip))
+ req->calib_param.dcoc_max_vga = DCOC_MAX_VGA_ATHOS;
+ else
+ req->calib_param.dcoc_max_vga = DCOC_MAX_VGA;
+ }
+
+ /* Antenna configuration */
+ cl_fill_ant_config(cl_hw, &req->ant_config, cl_hw->num_antennas, cl_hw->mask_num_antennas,
+ cl_hw->conf->ce_cck_tx_ant_mask, cl_hw->conf->ce_cck_rx_ant_mask);
+ /* FEM configuration */
+ cl_fill_fem_config(cl_hw, &req->fem_conf);
+
+ res = cl_send_request(cl_hw, req);
+
+ cl_temperature_comp_update_calib(cl_hw);
+
+ cl_dbg_info(cl_hw,
+ "band=%u, channel=%u, bw=%u, primary=%u.%u, center=%u.%u, sx_index=%u\n",
+ cl_hw->conf->ci_band_num, channel, bw, GET_FREQ_INT(primary),
+ GET_FREQ_FRAC(primary), GET_FREQ_INT(center), GET_FREQ_FRAC(center),
+ cl_hw->tcv_idx);
+
+ return res;
+}
+
+int _cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary,
+ u32 center, u8 mode)
+{
+ int res = 0;
+ u32 primary_q2 = FREQ_TO_Q2(primary);
+ u32 center_q2 = FREQ_TO_Q2(center);
+
+ /*
+ * Need to take mutex lock to ensure that no one touching the phy_data
+ * DMA before FW is reading all its values.
+ * The mutex is unlocked right after the iq_dcoc_data_info DMA is
+ * handled in cl_calib_handle_set_channel_cfm.
+ */
+ res = mutex_lock_interruptible(&cl_hw->set_channel_mutex);
+
+ if (res != 0) {
+ cl_dbg_verbose(cl_hw, "Error - mutex_lock_interruptible (%d)\n", res);
+ return res;
+ }
+
+ cl_hw->channel = channel;
+ cl_hw->bw = bw;
+ cl_hw->primary_freq = primary;
+ cl_hw->center_freq = center;
+
+ if (mode & SET_CHANNEL_MODE_CALIB)
+ cl_hw->msg_calib_timeout = true;
+
+ res = __cl_msg_tx_set_channel(cl_hw, channel, bw, primary_q2, center_q2, mode);
+
+ if (mode & SET_CHANNEL_MODE_CALIB) {
+ cl_hw->msg_calib_timeout = false;
+
+ if (!res)
+ res = cl_calib_handle_cfm(cl_hw, mode);
+ }
+
+ mutex_unlock(&cl_hw->set_channel_mutex);
+
+ return res;
+}
+
+int cl_msg_tx_set_channel(struct cl_hw *cl_hw, u32 channel, u8 bw, u32 primary, u32 center)
+{
+ if (cl_calib_is_needed(cl_hw, channel, bw))
+ return cl_calib_set_channel(cl_hw, channel, bw, primary, center);
+ else
+ return _cl_msg_tx_set_channel(cl_hw, channel, bw, primary, center,
+ SET_CHANNEL_MODE_OPERETIONAL);
+}
+
+int cl_msg_tx_dtim(struct cl_hw *cl_hw, u8 dtim_period)
+{
+ struct mm_set_dtim_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_DTIM_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->dtim_period = dtim_period;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_beacon_int(struct cl_hw *cl_hw, u16 beacon_int, u8 vif_idx)
+{
+ struct mm_set_beacon_int_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_BEACON_INT_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->beacon_int = cpu_to_le16(beacon_int);
+ req->inst_nbr = vif_idx;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_basic_rates(struct cl_hw *cl_hw, u32 basic_rates)
+{
+ struct mm_set_basic_rates_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_BASIC_RATES_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->rates = cpu_to_le32(basic_rates);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_bssid(struct cl_hw *cl_hw, const u8 *bssid, u8 vif_idx)
+{
+ struct mm_set_bssid_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_BSSID_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ cl_mac_addr_copy(req->bssid.array, bssid);
+ req->inst_nbr = vif_idx;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_edca(struct cl_hw *cl_hw, u8 hw_queue, u32 param,
+ struct ieee80211_he_mu_edca_param_ac_rec *mu_edca)
+{
+ struct mm_set_edca_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_EDCA_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->ac_param = cpu_to_le32(param);
+ req->hw_queue = hw_queue;
+
+ if (mu_edca) {
+ req->mu_edca_aifsn = mu_edca->aifsn;
+ req->mu_edca_ecw_min_max = mu_edca->ecw_min_max;
+ req->mu_edca_timer = mu_edca->mu_edca_timer;
+ }
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_associated(struct cl_hw *cl_hw,
+ struct ieee80211_bss_conf *bss_conf)
+{
+ struct mm_set_associated_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_ASSOCIATED_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->aid = cpu_to_le16(bss_conf->aid);
+
+ /* Multiple BSSID feature support */
+ if (bss_conf->nontransmitted && bss_conf->assoc) {
+ u8 i = 0;
+ u8 mask_addr[ETH_ALEN] = {0};
+ u32 bssid_hi_mask = 0;
+ u32 bssid_low_mask = 0;
+
+ for (i = 0; i < ARRAY_SIZE(mask_addr); i++)
+ mask_addr[i] = (bss_conf->transmitter_bssid[i] ^
+ bss_conf->bssid[i]);
+ cl_mac_addr_array_to_nxmac(mask_addr, &bssid_low_mask,
+ &bssid_hi_mask);
+ /* Set mask to allow the transmitter BSSID Rx reception */
+ req->bssid_hi_mask = cpu_to_le32(bssid_hi_mask);
+ req->bssid_low_mask = cpu_to_le32(bssid_low_mask);
+ }
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_slottime(struct cl_hw *cl_hw, bool use_short_slot)
+{
+ struct mm_set_slottime_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_SLOTTIME_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->slottime = use_short_slot ? 9 : 20;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_idle(struct cl_hw *cl_hw, u8 idle)
+{
+ struct mm_set_idle_req *req;
+
+ if (cl_fem_read_wiring_id(cl_hw->chip)) {
+ cl_dbg_err(cl_hw, "!!! Invalid wiring id [%u] !!! Aborting\n",
+ cl_hw->chip->fem.wiring_id);
+ return -EINVAL;
+ }
+
+ /*
+ * Rearm last_tbtt_ind so that error message will
+ * not be printed in cl_irq_status_tbtt()
+ */
+ if (!idle)
+ cl_hw->last_tbtt_irq = jiffies;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_IDLE_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->hw_idle = idle;
+
+ cl_dbg_info(cl_hw, "idle = %s\n", idle ? "True" : "False");
+
+ return cl_send_request(cl_hw, req);
+}
+
+void cl_msg_tx_idle_async(struct cl_hw *cl_hw)
+{
+ cl_hw->idle_async_set = true;
+ cl_msg_tx_set_idle(cl_hw, MAC_IDLE_ASYNC);
+}
+
+int cl_msg_tx_key_add(struct cl_hw *cl_hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key_conf,
+ u8 cipher_suite)
+{
+ struct mm_key_add_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_KEY_ADD_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ if (sta) {
+ /* Pairwise key */
+ req->sta_idx = ((struct cl_sta *)sta->drv_priv)->sta_idx;
+ } else {
+ /* Default key */
+ req->sta_idx = 0xFF;
+ req->key_idx = (u8)(key_conf->keyidx); /* Only useful for default keys */
+ }
+
+ req->inst_nbr = ((struct cl_vif *)vif->drv_priv)->vif_index;
+ req->key.length = key_conf->keylen;
+
+ /* TODO: check if this works well in Big endian platforms */
+ memcpy(req->key.array, key_conf->key, key_conf->keylen);
+
+ req->cipher_suite = cipher_suite;
+ req->spp = cl_hw->conf->ci_spp_ksr_value;
+
+ cl_dbg_info(cl_hw, "sta_idx:%u, key_idx:%u, inst_nbr:%u, cipher:%u, key_len:%u, spp:%u\n",
+ req->sta_idx, req->key_idx, req->inst_nbr,
+ req->cipher_suite, req->key.length, req->spp);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_key_del(struct cl_hw *cl_hw, u8 hw_key_idx)
+{
+ struct mm_key_del_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_KEY_DEL_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->hw_key_idx = hw_key_idx;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ba_add(struct cl_hw *cl_hw, u8 type, u8 sta_idx,
+ u16 tid, u16 bufsz, u16 ssn)
+{
+ struct mm_ba_add_req *req;
+ u16 msg_id = ((type == BA_AGMT_TX) ? MM_BA_ADD_TX_REQ : MM_BA_ADD_RX_REQ);
+
+ req = cl_msg_zalloc(cl_hw, msg_id, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->type = type;
+ req->sta_idx = sta_idx;
+ req->tid = (u8)tid;
+ req->bufsz = cpu_to_le16(bufsz);
+ req->ssn = cpu_to_le16(ssn);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ba_del(struct cl_hw *cl_hw, u8 sta_idx, u16 tid)
+{
+ struct mm_ba_del_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_BA_DEL_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sta_idx = sta_idx;
+ req->tid = (u8)tid;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_phy_reset(struct cl_hw *cl_hw)
+{
+ struct mm_phy_reset_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_PHY_RESET_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_available_ba_txq(struct cl_hw *cl_hw, u8 sta_idx, u16 tid)
+{
+ struct mm_available_ba_txq_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_AVAILABLE_BA_TXQ_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sta_idx = sta_idx;
+ req->tid = (u8)tid;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_update_rate_dl(struct cl_hw *cl_hw, u8 sta_idx, u32 rate, u32 rate_fallback,
+ u8 req_bw_tx, u8 op_mode, u8 ltf, u8 ltf_fallback, u32 rate_he)
+{
+ struct mm_update_rate_dl_req *req;
+
+ cl_dbg_info(cl_hw, "sta_idx=%u, rate=0x%x, rate_fallback=0x%x, req_bw_tx=%u, "
+ "op_mode=%u, ltf=%u, ltf_fallback=%u, rate_he=0x%x\n",
+ sta_idx, rate, rate_fallback, req_bw_tx, op_mode,
+ ltf, ltf_fallback, rate_he);
+
+ req = cl_msg_zalloc(cl_hw, MM_UPDATE_RATE_DL_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Populate tx_params */
+ req->tx_params.rate = cpu_to_le32(rate);
+ req->tx_params.rate_he = cpu_to_le32(rate_he);
+ req->tx_params.req_bw_tx = req_bw_tx;
+ req->tx_params.ant_set = CL_DEF_ANT_BITMAP;
+ req->tx_params.ltf = ltf;
+
+ req->op_mode = op_mode;
+ req->sta_idx = sta_idx;
+ req->rate_fallback = cpu_to_le32(rate_fallback);
+ req->ltf_fallback = ltf_fallback;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_vns(struct cl_hw *cl_hw, u8 sta_idx, u8 is_vns)
+{
+ struct mm_set_vns_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_VNS_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sta_idx = sta_idx;
+ req->is_vns = is_vns;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_tx_bf(struct cl_hw *cl_hw, u8 sta_idx, u8 is_on, u8 is_on_fallback)
+{
+ struct mm_set_tx_bf_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_TX_BF_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sta_idx = sta_idx;
+ req->is_on = is_on;
+ req->is_on_fallback = is_on_fallback;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding(struct cl_hw *cl_hw,
+ struct mm_sounding_req *sounding_req)
+{
+ struct mm_sounding_req *req;
+ u8 i;
+
+ req = cl_msg_zalloc(cl_hw, MM_SOUNDING_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Populate mm_sounding_req */
+ memcpy(req, sounding_req, sizeof(struct mm_sounding_req));
+
+ /* In case of non-TB HE SU/CQI, nc should be set to 0 */
+ if (req->sounding_type == SOUNDING_TYPE_HE_CQI ||
+ req->sounding_type == SOUNDING_TYPE_HE_SU)
+ for (i = 0; i < req->sta_num; i++)
+ req->info_per_sta[i].nc = 0;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding_pairing(struct cl_hw *cl_hw, u8 sounding_id, u8 sounding_type,
+ u8 gid, u8 sta_idx)
+{
+ struct mm_sounding_pairing *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SOUNDING_PAIRING_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sounding_type = sounding_type;
+ req->sta_idx = sta_idx;
+ req->gid = gid;
+ req->sounding_id = sounding_id;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_sounding_interval(struct cl_hw *cl_hw, u16 interval, u16 lifetime,
+ u8 sounding_type, u8 sta_idx)
+{
+ struct mm_sounding_interval_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SOUNDING_INTERVAL_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->interval = cpu_to_le16(interval);
+ req->bfr_lifetime = cpu_to_le16(lifetime);
+ req->sounding_type = sounding_type;
+ req->sta_idx = sta_idx;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_config_cca(struct cl_hw *cl_hw, bool enable)
+{
+ struct mm_config_cca_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_CONFIG_CCA_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->enable = enable;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_dfs(struct cl_hw *cl_hw, bool enable, u8 standard,
+ u8 initial_gain, u8 agc_cd_th)
+{
+ struct mm_set_dfs_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_DFS_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->enable = enable;
+ req->standard_fcc = (standard == CL_STANDARD_FCC) ? true : false;
+ req->initial_gain = initial_gain;
+ req->agc_cd_th = agc_cd_th;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_ant_bitmap(struct cl_hw *cl_hw, u8 bitmap)
+{
+ struct mm_set_ant_bitmap_req *req;
+ u8 num_antennas = hweight8(bitmap);
+ u8 bitmap_cck = 0;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_ANT_BITMAP_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ if (cl_band_is_24g(cl_hw)) {
+ if (num_antennas > MAX_ANTENNAS_CCK)
+ bitmap_cck = copy_mask_bits(bitmap, MAX_ANTENNAS_CCK);
+ else
+ bitmap_cck = bitmap;
+ }
+
+ cl_fill_ant_config(cl_hw, &req->ant_config, num_antennas, bitmap, bitmap_cck, bitmap_cck);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_ndp_tx_control(struct cl_hw *cl_hw, u8 chain_mask, u8 bw, u8 format, u8 num_ltf)
+{
+ struct mm_ndp_tx_control_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_NDP_TX_CONTROL_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->chain_mask = chain_mask;
+ req->bw = bw;
+ req->format = format;
+ req->num_ltf = num_ltf;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_reg_write(struct cl_hw *cl_hw, u32 address, u32 value, u32 mask)
+{
+ struct mm_reg_write_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_REG_WRITE_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->address = cpu_to_le32(address);
+ req->value = cpu_to_le32(value);
+ req->mask = cpu_to_le32(mask);
+
+ cl_dbg_info(cl_hw, "address=0x%x, value=0x%x, mask=0x%x\n", address, value, mask);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_prot_mode(struct cl_hw *cl_hw, u8 log_nav_en, u8 mode, u8 rate_format,
+ u8 rate_mcs, u8 rate_pre_type)
+{
+ struct mm_prot_mode_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_PROT_MODE_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->log_nav_en = log_nav_en;
+ req->mode = mode;
+ req->rate_format = rate_format;
+ req->rate_mcs = rate_mcs;
+ req->rate_pre_type = rate_pre_type;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_goto_power_reduction(struct cl_hw *cl_hw, u8 mode)
+{
+ struct mm_goto_power_reduction_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_GOTO_POWER_REDUCTION_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->goto_power_reduction_mode = mode;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_backup_bcn_en(struct cl_hw *cl_hw, bool backup_bcn_en)
+{
+ struct mm_set_backup_bcn_en_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_BACKUP_BCN_EN_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->backup_bcn_en = backup_bcn_en;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_start_periodic_tx_time(struct cl_hw *cl_hw, u16 periodic_tx_time_off,
+ u16 periodic_tx_time_on)
+{
+ struct mm_start_periodic_tx_time_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_START_PERIODIC_TX_TIME_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->periodic_tx_time_off = cpu_to_le16(periodic_tx_time_off);
+ req->periodic_tx_time_on = cpu_to_le16(periodic_tx_time_on);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_anamon_read(struct cl_hw *cl_hw, u8 mode, u8 param1, u8 param2)
+{
+ struct mm_anamon_read_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_ANAMON_READ_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->mode = mode;
+ req->param1 = param1;
+ req->param2 = param2;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_refresh_power(struct cl_hw *cl_hw)
+{
+ void *void_param;
+
+ /* MM_REFRESH_PWR_REQ has no parameter */
+ void_param = cl_msg_zalloc(cl_hw, MM_REFRESH_PWR_REQ, TASK_MM, 0);
+ if (!void_param)
+ return -ENOMEM;
+
+ return cl_send_request(cl_hw, void_param);
+}
+
+int cl_msg_tx_set_ant_pwr_offset(struct cl_hw *cl_hw, s8 pwr_offset[MAX_ANTENNAS])
+{
+ struct mm_set_ant_pwr_offset_req *req;
+ u8 i = 0;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_ANT_PWR_OFFSET_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(req->pwr_offset); i++) {
+ pwr_offset[i] = cl_power_offset_check_margin(cl_hw, cl_hw->bw, i, pwr_offset[i]);
+ req->pwr_offset[i] = cl_convert_signed_to_reg_value(pwr_offset[i]);
+ }
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_rate_fallback(struct cl_hw *cl_hw)
+{
+ struct mm_rate_fallback_req *req;
+ u8 *fb_conf = cl_hw->conf->ci_rate_fallback;
+
+ req = cl_msg_zalloc(cl_hw, MM_SET_RATE_FALLBACK_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->fallback_count_su = fb_conf[CL_RATE_FALLBACK_COUNT_SU];
+ req->fallback_count_mu = fb_conf[CL_RATE_FALLBACK_COUNT_MU];
+ req->retry_count_thr = fb_conf[CL_RATE_FALLBACK_RETRY_COUNT_THR];
+ req->ba_per_thr = fb_conf[CL_RATE_FALLBACK_BA_PER_THR];
+ req->ba_not_received_thr = fb_conf[CL_RATE_FALLBACK_BA_NOT_RECEIVED_THR];
+ req->disable_mcs0 = fb_conf[CL_RATE_FALLBACK_DISABLE_MCS];
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_twt_setup(struct cl_hw *cl_hw, struct mm_twt_setup_req *params)
+{
+ struct mm_twt_setup_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_TWT_SETUP_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sta_idx = params->sta_idx;
+ req->twt_flow_id = params->twt_flow_id;
+ req->announced = params->announced;
+ req->triggered = params->triggered;
+ req->min_wake_duration_us = cpu_to_le32(params->min_wake_duration_us);
+ req->twt_interval_us = cpu_to_le64(params->twt_interval_us);
+ req->twt_start_time_tsf = cpu_to_le64(params->twt_start_time_tsf);
+
+ cl_dbg_info(cl_hw,
+ "sta_idx %u, flow_id %u, interval_us %llu, min_wake_duration_us %u,"
+ "start_time %llu, announced %u, triggered %u\n",
+ req->sta_idx, req->twt_flow_id, req->twt_interval_us,
+ req->min_wake_duration_us, req->twt_start_time_tsf,
+ req->announced, req->triggered);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_twt_teardown(struct cl_hw *cl_hw, struct mm_twt_teardown_req *params)
+{
+ struct mm_twt_teardown_req *req;
+
+ req = cl_msg_zalloc(cl_hw, MM_TWT_TEARDOWN_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sta_idx = params->sta_idx;
+ req->twt_flow_id = params->twt_flow_id;
+
+ cl_dbg_info(cl_hw, "sta_idx %u, flow_id %u\n",
+ req->sta_idx, req->twt_flow_id);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_rsrc_mgmt_traffic_event(struct cl_hw *cl_hw, u8 event_type,
+ enum cl_traffic_level level,
+ enum cl_traffic_direction direction,
+ u8 active_sta_cnt)
+{
+ struct mm_rsrc_mgmt_req *req = NULL;
+ struct cl_sta *cl_sta = NULL;
+ int curr_cnt = 0;
+ size_t size = sizeof(*req) + active_sta_cnt * sizeof(struct mm_rsrc_mgmt_active_sta);
+
+ req = cl_msg_zalloc(cl_hw, MM_RSRC_MGMT_REQ, TASK_MM, size);
+ if (!req)
+ return -ENOMEM;
+
+ req->subtype = event_type;
+ req->u.traffic_event.level = level;
+ req->u.traffic_event.direction = direction;
+
+ cl_sta_lock_bh(cl_hw);
+ list_for_each_entry(cl_sta, &cl_hw->cl_sta_db.head, list) {
+ struct cl_wrs_rate *max_rate_cap = &cl_sta->wrs_sta.max_rate_cap;
+ struct cl_wrs_tx_params *su_tx_params = &cl_sta->wrs_sta.su_params.tx_params;
+
+ if (!cl_sta->traffic_db[direction].activity_db[level].is_active)
+ continue;
+
+ if (req->u.traffic_event.active_sta.cnt == active_sta_cnt) {
+ WARN_ONCE(active_sta_cnt != 0,
+ "Synchronization failure between actual and "
+ "preallocated station entities!");
+ break;
+ }
+
+ req->u.traffic_event.active_sta.list[curr_cnt] = (struct mm_rsrc_mgmt_active_sta) {
+ .idx = cl_sta->sta_idx,
+ .su_rate = {
+ .bw = su_tx_params->bw,
+ .nss = su_tx_params->nss,
+ .mcs = su_tx_params->mcs
+ },
+ .max_rate = {
+ .bw = max_rate_cap->bw,
+ .nss = max_rate_cap->nss,
+ .mcs = max_rate_cap->mcs
+ },
+ };
+
+ curr_cnt++;
+ }
+ req->u.traffic_event.active_sta.cnt = curr_cnt;
+ cl_sta_unlock_bh(cl_hw);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_rsrc_mgmt_rates_event(struct cl_hw *cl_hw, u8 event_type,
+ struct cl_sta *cl_sta)
+{
+ struct mm_rsrc_mgmt_req *req = NULL;
+ struct cl_wrs_rate *max_rate_cap = &cl_sta->wrs_sta.max_rate_cap;
+ struct cl_wrs_tx_params *su_tx_params = &cl_sta->wrs_sta.su_params.tx_params;
+
+ req = cl_msg_zalloc(cl_hw, MM_RSRC_MGMT_REQ, TASK_MM, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->subtype = event_type;
+ req->u.rate_event.sta = (struct mm_rsrc_mgmt_active_sta) {
+ .idx = cl_sta->sta_idx,
+ .su_rate = {
+ .bw = su_tx_params->bw,
+ .nss = su_tx_params->nss,
+ .mcs = su_tx_params->mcs
+ },
+ .max_rate = {
+ .bw = max_rate_cap->bw,
+ .nss = max_rate_cap->nss,
+ .mcs = max_rate_cap->mcs
+ },
+ };
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_set_freq_offset(struct cl_hw *cl_hw, u16 val)
+{
+ struct mm_set_freq_offset_req *req;
+
+ /* Build the MM_SET_FREQ_OFFSET_REQ message */
+ req = cl_msg_zalloc(cl_hw, MM_SET_FREQ_OFFSET_REQ, TASK_MM,
+ sizeof(struct mm_set_freq_offset_req));
+
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_SET_FREQ_OFFSET_REQ message */
+ req->val = cpu_to_le16(val);
+
+ /* Send the MM_SET_FREQ_OFFSET_REQ message to firmware */
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_mod_filter(struct cl_hw *cl_hw, u32 filter)
+{
+ struct dbg_set_mod_filter_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_SET_MOD_FILTER_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->mod_filter = cpu_to_le32(filter);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_ce_mod_filter(struct cl_hw *cl_hw, u32 filter)
+{
+ struct dbg_set_mod_filter_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_CE_SET_MOD_FILTER_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->mod_filter = cpu_to_le32(filter);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_sev_filter(struct cl_hw *cl_hw, u32 filter)
+{
+ struct dbg_set_sev_filter_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_SET_SEV_FILTER_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sev_filter = cpu_to_le32(filter);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_beamforming_tx(struct cl_hw *cl_hw, u32 param32)
+{
+ struct dbg_beamforming_tx_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_BEAMFORMING_TX_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->bf_cmd = cpu_to_le32(param32);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_get_e2w_stats(struct cl_hw *cl_hw, bool clear)
+{
+ struct dbg_e2w_stats_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_GET_E2W_STATS_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->clear = cpu_to_le32(clear);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_la_mpif_mask(struct cl_hw *cl_hw, u32 mask)
+{
+ struct dbg_set_la_mpif_mask_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_SET_LA_MPIF_MASK_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->mpif_mask = cpu_to_le32(mask);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_la_trig_point(struct cl_hw *cl_hw, u32 trigger_point)
+{
+ struct dbg_set_la_trig_point_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_SET_LA_TRIG_POINT_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->trigger_point = cpu_to_le32(trigger_point);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_la_mpif_debug_mode(struct cl_hw *cl_hw, u8 mode)
+{
+ struct dbg_set_la_mpif_debug_mode_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_SET_LA_MPIF_DEBUG_MODE_REQ, TASK_DBG,
+ sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->mode = mode;
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_set_la_trig_rule(struct cl_hw *cl_hw, u8 idx, bool enable, u32 address,
+ u8 oper, u32 value, u32 mask, u32 duration)
+{
+ struct dbg_set_la_trig_rule_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_SET_LA_TRIG_RULE_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->rule_id = idx;
+ req->oper = oper;
+ req->enable = enable;
+ req->address = cpu_to_le32(address);
+ req->value = cpu_to_le32(value);
+ req->mask = cpu_to_le32(mask);
+ req->duration = cpu_to_le32(duration);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_tx_trace_debug_flag(struct cl_hw *cl_hw, u32 bitmap, u8 w_r_cmd)
+{
+ struct dbg_tx_trace_debug_flag_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_TX_TRACE_DEBUG_FLAG_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->read_write_flag = w_r_cmd;
+ req->bitmap = cpu_to_le32(bitmap);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_print_stats(struct cl_hw *cl_hw, u32 command,
+ u32 param0, u32 param1, u32 param2, u32 param3)
+{
+ struct dbg_print_stats_req *req;
+
+ req = cl_msg_zalloc(cl_hw, DBG_PRINT_STATS_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->command = cpu_to_le32(command);
+ req->param[0] = cpu_to_le32(param0);
+ req->param[1] = cpu_to_le32(param1);
+ req->param[2] = cpu_to_le32(param2);
+ req->param[3] = cpu_to_le32(param3);
+
+ cl_dbg_verbose(cl_hw, "param0 = 0x%x, param1 = 0x%x, param2 = 0x%x, param3 = 0x%x\n",
+ req->param[0], req->param[1], req->param[2], req->param[3]);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_trigger(struct cl_hw *cl_hw, char *msg)
+{
+ struct dbg_trigger_req *req;
+ u8 msg_len = min(strlen(msg), sizeof(req->error) - 1);
+
+ req = cl_msg_zalloc(cl_hw, DBG_TRIGGER_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ strncpy(req->error, msg, msg_len);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_test_mode(struct cl_hw *cl_hw, u32 *params)
+{
+ struct dbg_test_mode_req *req;
+ int i = 0;
+
+ req = cl_msg_zalloc(cl_hw, DBG_TEST_MODE_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ req->command = cpu_to_le32(params[0]);
+
+ /* Param[0] is the command, therefore start from param[i + 1] */
+ for (i = 0; i < ARRAY_SIZE(req->params); i++)
+ req->params[i] = cpu_to_le32(params[i + 1]);
+
+ return cl_send_request(cl_hw, req);
+}
+
+int cl_msg_tx_dbg_sounding_cmd(struct cl_hw *cl_hw, struct dbg_sounding_cmd_param *params)
+{
+ struct dbg_sounding_cmd_param *req;
+ int i;
+
+ req = cl_msg_zalloc(cl_hw, DBG_SOUNDING_CMD_REQ, TASK_DBG, sizeof(*req));
+ if (!req)
+ return -ENOMEM;
+
+ memcpy(req, params, sizeof(struct dbg_sounding_cmd_param));
+ req->sounding_cmd_index = cpu_to_le32(params->sounding_cmd_index);
+
+ for (i = 0; i < ARRAY_SIZE(req->param); i++)
+ req->param[i] = cpu_to_le32(params->param[i]);
+
+ return cl_send_request(cl_hw, req);
+}