// SPDX-License-Identifier: GPL-2.0-only #include #include #include "img_exponential_multi_pools_alloc.h" #include "host_rpu_sys_if.h" #include "img_mac80211_types.h" #include "softmac_core.h" #include "img_module_iface.h" #include "img_host_rpu_umac_iface.h" #include "lmac_if.h" #include "lmac_if_common.h" #include "img_host_txrx_buffs.h" #include "img_rx_multi_pkt_proc.h" #include "img_utils.h" RETENTION_MEM_SECTION_UNINITIALIZED unsigned int sleepEnable; RETENTION_MEM_SECTION_UNINITIALIZED unsigned int hw_bringup_time; RETENTION_MEM_SECTION_UNINITIALIZED unsigned int sw_bringup_time; RETENTION_MEM_SECTION_UNINITIALIZED unsigned int bcn_time_out; RETENTION_MEM_SECTION_UNINITIALIZED unsigned int calibSleepClk; RETENTION_MEM_SECTION_UNINITIALIZED struct nrf_wifi_data_config_params data_config_params_g; RETENTION_MEM_SECTION_UNINITIALIZED struct rx_buf_pool_params rx_buf_pools_g[MAX_NUM_OF_RX_QUEUES]; RETENTION_MEM_SECTION_UNINITIALIZED struct temp_vbat_config temp_vbat_config_params_g; RETENTION_MEM_SECTION_UNINITIALIZED struct img_he_gi_ltf_config_params he_gi_ltf_config_params_g; unsigned char host_deinit_cmd_rcvd_flag_g; int rpu_prog_deinit(); int interface_type_default = 0; unsigned long wdev_id_default_g = 0; void img_sys_set_mac_address(unsigned char *user_mac_addr); unsigned char *img_sys_get_mac_address(void); void umac_open(); void umac_modules_init(); int img_data_proc_init_msg(void *msg); int img_sys_send_reset(unsigned int reset_type, unsigned int rpu_mode); int rpu_send_cmd(unsigned char *buf, unsigned int len, unsigned char id); int img_sys_store_rf_params(unsigned char *rf_params, int len) { if(len > RF_PARAMS_SIZE) { return -1; } if(memcmp(wifi->params.rf_params, rf_params, len) == 0) { return 0; } memcpy(wifi->params.rf_params, rf_params, len); return 1; } int img_sys_proc_init(void *msg) { struct img_priv *priv; int send_reinit = 0; unsigned char i = 0; struct nrf_wifi_cmd_sys_init *sys_init = (struct nrf_wifi_cmd_sys_init *)msg; if(sys_init->wdev_id == MAX_VIFS + 1){ interface_type_default = NL80211_IFTYPE_ADHOC; wdev_id_default_g = sys_init->wdev_id - MAX_VIFS; } else{ interface_type_default = NL80211_IFTYPE_STATION; wdev_id_default_g = sys_init->wdev_id; } img_sys_set_mac_address(sys_init->sys_params.mac_addr); data_config_params_g.aggregation = sys_init->data_config_params.aggregation; data_config_params_g.wmm = sys_init->data_config_params.wmm; data_config_params_g.max_num_tx_agg_sessions = sys_init->data_config_params.max_num_tx_agg_sessions; data_config_params_g.max_num_rx_agg_sessions = sys_init->data_config_params.max_num_rx_agg_sessions; data_config_params_g.reorder_buf_size = sys_init->data_config_params.reorder_buf_size; data_config_params_g.max_rxampdu_size = sys_init->data_config_params.max_rxampdu_size; sleepEnable = sys_init->sys_params.sleep_enable; hw_bringup_time = sys_init->sys_params.hw_bringup_time; sw_bringup_time = sys_init->sys_params.sw_bringup_time; bcn_time_out = sys_init->sys_params.bcn_time_out; calibSleepClk = sys_init->sys_params.calib_sleep_clk; umac_modules_init(); wifi->params.mode = RPU_OP_MODE_REG; if(sys_init->sys_params.rf_params_valid) { img_sys_store_rf_params(sys_init->sys_params.rf_params, RF_PARAMS_SIZE); } wifi->params.phy_calib = sys_init->sys_params.phy_calib; wifi->params.rate_protection_type = sys_init->data_config_params.rate_protection_type; for(i = 0;i < MAX_NUM_OF_RX_QUEUES ;i++){ memcpy(&rx_buf_pools_g[i], &sys_init->rx_buf_pools[i], sizeof(struct rx_buf_pool_params)); } memcpy(&temp_vbat_config_params_g, &sys_init->temp_vbat_config_params, sizeof(struct temp_vbat_config)); img_data_proc_init_msg(msg); img_data_send_init_done(); return 0; } int img_sys_proc_he_gi_ltf_config(void *msg) { unsigned char i = 0; struct nrf_wifi_cmd_he_gi_ltf_config *gi_ltf_config = (struct nrf_wifi_cmd_he_gi_ltf_config *)msg; he_gi_ltf_config_params_g.he_gi_type = gi_ltf_config->he_gi_type; he_gi_ltf_config_params_g.he_ltf = gi_ltf_config->he_ltf; he_gi_ltf_config_params_g.configured = gi_ltf_config->enable; return 0; } int img_sys_send_reset(unsigned int reset_type, unsigned int rpu_mode) { struct img_priv *priv = ((struct img_priv *)(wifi->hw->priv)); int ret = 0; priv->reset_complete = 0; CALL_RPU(rpu_prog_reset, reset_type, rpu_mode); if (wait_for_reset_complete(priv) < 0) { ret = -1; } prog_rpu_fail: return ret; } int memory_select(struct master_pool_info *pool_info,struct pool_data_to_host *memory_info) { for(int i=0;i<=56;i++) { if(pool_info[0].num_pool_items[i] == 0) continue; memory_info[i].buffer_size = pool_info[0].pools_info[i]->buffer_size; memory_info[i].num_pool_items = pool_info[0].pools_info[i]->num_pool_items; memory_info[i].items_num_max_allocated = pool_info[0].pools_info[i]->items_num_max_allocated; memory_info[i].items_num_cur_allocated = pool_info[0].pools_info[i]->items_num_cur_allocated; memory_info[i].items_num_total_allocated = pool_info[0].pools_info[i]->items_num_total_allocated; memory_info[i].items_num_not_allocated = pool_info[0].pools_info[i]->items_num_not_allocated; } return 0; } int img_sys_get_umac_normal_stats(struct rpu_umac_stats *stats) { memcpy(&stats->tx_dbg_params, &tx_dbg, sizeof(struct umac_tx_dbg_params)); memcpy(&stats->rx_dbg_params, &rx_dbg, sizeof(struct umac_rx_dbg_params)); memcpy(&stats->cmd_evnt_dbg_params, &img_cmd_event_dbg_params, sizeof(struct umac_cmd_evnt_dbg_params)); return 0; } int img_sys_get_umac_debug_stats(struct rpu_umac_stats *stats) { memcpy(&stats->tx_dbg_params, &tx_dbg, sizeof(struct umac_tx_dbg_params)); memcpy(&stats->rx_dbg_params, &rx_dbg, sizeof(struct umac_rx_dbg_params)); memcpy(&stats->cmd_evnt_dbg_params, &img_cmd_event_dbg_params, sizeof(struct umac_cmd_evnt_dbg_params)); return 0; } int img_sys_get_umac_stats(struct rpu_umac_stats *stats) { if(wifi->params.mode == RPU_OP_MODE_REG) { img_sys_get_umac_normal_stats(stats); } else if(wifi->params.mode == RPU_OP_MODE_DBG) { img_sys_get_umac_debug_stats(stats); } else { return -1; } return 0; } int img_sys_get_lmac_normal_stats(struct rpu_lmac_stats *stats, struct lmac_event_stats *prod_stats) { memcpy(stats, &prod_stats->stats.lmac_stats, sizeof(struct rpu_lmac_stats)); return 0; } int img_sys_get_lmac_debug_stats(struct rpu_lmac_stats *stats) { return 0; } int img_sys_get_lmac_prod_stats(struct rpu_lmac_stats *stats) { return 0; } int img_sys_get_lmac_stats(struct rpu_lmac_stats *stats, struct lmac_event_stats *prod_stats) { if(wifi->params.mode == RPU_OP_MODE_REG) { img_sys_get_lmac_normal_stats(stats, prod_stats); } else if(wifi->params.mode == RPU_OP_MODE_DBG) { img_sys_get_lmac_debug_stats(stats); } else { return -1; } return 0; } int img_sys_get_phy_normal_stats(struct rpu_phy_stats *stats) { stats->ofdm_crc32_pass_cnt = wifi->stats.ofdm_crc32_pass_cnt; stats->ofdm_crc32_fail_cnt = wifi->stats.ofdm_crc32_fail_cnt; stats->dsss_crc32_pass_cnt = wifi->stats.dsss_crc32_pass_cnt; stats->dsss_crc32_fail_cnt = wifi->stats.dsss_crc32_fail_cnt; stats->rssi_avg = wifi->params.rssi_average; return 0; } int img_sys_get_phy_debug_stats(struct rpu_phy_stats *stats) { stats->ofdm_crc32_pass_cnt = wifi->stats.ofdm_crc32_pass_cnt; stats->ofdm_crc32_fail_cnt = wifi->stats.ofdm_crc32_fail_cnt; stats->dsss_crc32_pass_cnt = wifi->stats.dsss_crc32_pass_cnt; stats->dsss_crc32_fail_cnt = wifi->stats.dsss_crc32_fail_cnt; return 0; } int img_sys_get_phy_prod_stats(struct rpu_phy_stats *stats) { stats->ofdm_crc32_pass_cnt = wifi->stats.ofdm_crc32_pass_cnt; stats->ofdm_crc32_fail_cnt = wifi->stats.ofdm_crc32_fail_cnt; stats->dsss_crc32_pass_cnt = wifi->stats.dsss_crc32_pass_cnt; stats->dsss_crc32_fail_cnt = wifi->stats.dsss_crc32_fail_cnt; stats->rssi_avg = wifi->params.rssi_average; return 0; } int img_sys_get_phy_fcm_stats(struct rpu_phy_stats *stats) { return 0; } int img_sys_get_phy_stats(struct rpu_phy_stats *stats) { if(wifi->params.mode == RPU_OP_MODE_REG) { img_sys_get_phy_normal_stats(stats); } else if(wifi->params.mode == RPU_OP_MODE_DBG) { img_sys_get_phy_debug_stats(stats); } else if(wifi->params.mode == RPU_OP_MODE_FCM) { img_sys_get_phy_fcm_stats(stats); } else if(wifi->params.mode == RPU_OP_MODE_PROD) { img_sys_get_phy_prod_stats(stats); } else { return -1; } return 0; } int img_sys_send_stats(struct lmac_event_stats *prod_stats) { struct host_rpu_msg *rpu_msg; struct nrf_wifi_umac_event_stats *stats; unsigned int event_len = sizeof(struct host_rpu_msg) + sizeof(struct nrf_wifi_umac_event_stats); int ret; int index; int total_rssi_samples = 0; int total_rssi_value = 0; rpu_msg = kzalloc(event_len, GFP_KERNEL); if(rpu_msg == NULL) { return -1; } rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_SYSTEM; rpu_msg->hdr.len = event_len; rpu_msg->hdr.resubmit = true; stats = (struct nrf_wifi_umac_event_stats *)rpu_msg->msg; stats->sys_head.cmd_event = NRF_WIFI_EVENT_STATS; stats->sys_head.len = sizeof(struct nrf_wifi_umac_event_stats); if(wifi->params.stats_type == RPU_STATS_TYPE_UMAC) { img_sys_get_umac_stats(&stats->fw.umac); } else if(wifi->params.stats_type == RPU_STATS_TYPE_LMAC) { img_sys_get_lmac_stats(&stats->fw.lmac, prod_stats); } else if(wifi->params.stats_type == RPU_STATS_TYPE_PHY) { img_sys_get_phy_stats(&stats->fw.phy); } else if(wifi->params.stats_type == RPU_STATS_TYPE_ALL) { img_sys_get_phy_stats(&stats->fw.phy); img_sys_get_umac_stats(&stats->fw.umac); img_sys_get_lmac_stats(&stats->fw.lmac, prod_stats); } else { return -1; } send_rx_buffs_to_host(rpu_msg, event_len); return 0; } int img_sys_send_pwr_mon_data(struct lmac_event_pwr_mon_data *pwr_mon_data) { struct host_rpu_msg *rpu_msg; struct nrf_wifi_event_pwr_data *pwr_mon; unsigned int event_len = sizeof(struct host_rpu_msg) + sizeof(struct nrf_wifi_event_pwr_data); int ret; rpu_msg = kzalloc(event_len, GFP_KERNEL); if(rpu_msg == NULL) { return -1; } rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_SYSTEM; rpu_msg->hdr.len = event_len; rpu_msg->hdr.resubmit = true; pwr_mon = (struct nrf_wifi_event_pwr_data *)rpu_msg->msg; pwr_mon->sys_head.cmd_event = NRF_WIFI_EVENT_PWR_DATA; pwr_mon->sys_head.len = sizeof(struct nrf_wifi_event_pwr_data); pwr_mon->mon_status = pwr_mon_data->mon_status; pwr_mon->data.lfc_err = pwr_mon_data->lfc_err; pwr_mon->data.vbat_mon = pwr_mon_data->vbat_mon; pwr_mon->data.temp = pwr_mon_data->temp; pwr_mon->data_type = pwr_mon_data->data_type; send_rx_buffs_to_host(rpu_msg, event_len); return 0; } int img_sys_send_coex_config_data(struct lmac_event_coexMgr *coex_event) { struct host_rpu_msg *rpu_msg; struct nrf_wifi_event_coex_config *umac_coex_config_data; unsigned int event_len = sizeof(struct host_rpu_msg) + sizeof(struct nrf_wifi_event_coex_config) + coex_event->len; rpu_msg = kzalloc(event_len, GFP_KERNEL); if(rpu_msg == NULL) { return -1; } rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_SYSTEM; rpu_msg->hdr.len = event_len; rpu_msg->hdr.resubmit = true; umac_coex_config_data = (struct nrf_wifi_event_coex_config *)rpu_msg->msg; umac_coex_config_data->sys_head.cmd_event = NRF_WIFI_EVENT_COEX_CONFIG; umac_coex_config_data->sys_head.len = sizeof(struct nrf_wifi_event_coex_config) + coex_event->len; memcpy(umac_coex_config_data->coex_config_info.coex_event, coex_event->event, coex_event->len); umac_coex_config_data->coex_config_info.len = coex_event->len; send_rx_buffs_to_host(rpu_msg, event_len); return 0; } #ifdef RF_TEST int img_sys_send_rftest_data(struct lmac_event_rftest *rftest_event) { struct host_rpu_msg *rpu_msg; struct img_event_rftest *rftest_data; unsigned int event_len = sizeof(struct host_rpu_msg) + sizeof(struct img_event_rftest); rpu_msg = kzalloc(event_len, GFP_KERNEL); if(rpu_msg == NULL) { return -1; } rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_SYSTEM; rpu_msg->hdr.len = event_len; rpu_msg->hdr.resubmit = true; rftest_data = (struct img_event_rftest *)rpu_msg->msg; rftest_data->sys_head.cmd_event = NRF_WIFI_EVENT_RF_TEST; rftest_data->sys_head.len = sizeof(struct img_event_rftest); memcpy(rftest_data->rf_test_info.ptr, rftest_event->ptr, sizeof(rftest_data->rf_test_info.ptr)); send_rx_buffs_to_host(rpu_msg, event_len); return 0; } #endif int img_sys_proc_get_stats(void *msg) { struct img_priv *priv = ((struct img_priv *)(wifi->hw->priv)); struct nrf_wifi_cmd_get_stats *get_stats = (struct nrf_wifi_cmd_get_stats *)msg; int ret = 0; wifi->params.stats_type = get_stats->stats_type; { CALL_RPU(rpu_prog_stats, RPU_OP_MODE_REG); } prog_rpu_fail: return 0; } extern struct master_pool_info master_pool_info_g[]; extern struct master_pool_info ret_master_pool_info_g[]; int img_sys_proc_umac_int_stats(void *msg) { struct host_rpu_msg *rpu_msg; struct umac_int_stats *umac_intstats; unsigned int event_len = sizeof(struct host_rpu_msg) + sizeof(struct umac_int_stats); rpu_msg = kzalloc(event_len, GFP_KERNEL); if(rpu_msg == NULL) { return -1; } rpu_msg->type = NRF_WIFI_HOST_RPU_MSG_TYPE_SYSTEM; rpu_msg->hdr.len = event_len; rpu_msg->hdr.resubmit = true; umac_intstats = (struct umac_int_stats *)rpu_msg->msg; umac_intstats->sys_head.cmd_event = NRF_WIFI_EVENT_INT_UMAC_STATS; umac_intstats->sys_head.len = sizeof(struct umac_int_stats); memory_select(master_pool_info_g,umac_intstats->scratch_dynamic_memory_info); memory_select(master_pool_info_g,umac_intstats->retention_dynamic_memory_info); send_rx_buffs_to_host(rpu_msg, event_len); return 0; } int img_sys_proc_clear_stats(void *msg) { struct img_priv *priv = ((struct img_priv *)(wifi->hw->priv)); int ret = 0; CALL_RPU(rpu_prog_clear_stats); prog_rpu_fail: return 0; } int img_sys_proc_pwr_mon(void *msg) { struct nrf_wifi_cmd_pwr *pwr_mon = (struct nrf_wifi_cmd_pwr *)msg; int ret = 0; CALL_RPU(rpu_prog_pwr_mon, pwr_mon->data_type); prog_rpu_fail: return 0; } int img_sys_proc_coex_config(void *msg) { struct nrf_wifi_cmd_coex_config *cmd_coex_config = (struct nrf_wifi_cmd_coex_config *)msg; struct lmac_cmd_coex_config *lmac_coex_config_cmd; int size = sizeof(struct lmac_cmd_coex_config) + cmd_coex_config->coex_config_info.len; lmac_coex_config_cmd = kzalloc(size, GFP_KERNEL); memcpy(lmac_coex_config_cmd->cmd, cmd_coex_config->coex_config_info.coex_cmd, cmd_coex_config->coex_config_info.len); lmac_coex_config_cmd->len = cmd_coex_config->coex_config_info.len; rpu_send_cmd((unsigned char *)lmac_coex_config_cmd, size, LMAC_CMD_COEX_CONFIG); kfree(lmac_coex_config_cmd); return 0; } #ifdef RF_TEST int img_sys_rf_test(void *msg) { struct img_cmd_rftest *cmd_rf_test = (struct img_cmd_rftest *)msg; struct lmac_cmd_rftest lmac_rftest_cmd; memset(&lmac_rftest_cmd, 0, sizeof(struct lmac_cmd_rftest)); memcpy(lmac_rftest_cmd.ptr, cmd_rf_test->rf_test_info.ptr, sizeof(lmac_rftest_cmd.ptr)); return rpu_send_cmd((unsigned char *)&lmac_rftest_cmd, sizeof(struct lmac_cmd_rftest), LMAC_CMD_RFTEST_SW); } #endif int img_sys_proc_host_msg(void *msg) { struct img_priv *priv = ((struct img_priv *)(wifi->hw->priv)); struct host_rpu_msg *host_rpu_msg = (struct host_rpu_msg *)msg; int host_rpu_msg_total_len = host_rpu_msg->hdr.len; struct nrf_wifi_sys_head *sys_head = (struct nrf_wifi_sys_head *)host_rpu_msg->msg; host_rpu_msg_total_len = host_rpu_msg_total_len - sizeof(struct host_rpu_msg); while(host_rpu_msg_total_len > 0) { switch (sys_head->cmd_event) { case NRF_WIFI_CMD_INIT: IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_init, 1); img_sys_proc_init(sys_head); break; case NRF_WIFI_CMD_DEINIT: host_deinit_cmd_rcvd_flag_g = 1; rpu_prog_deinit(); img_sys_send_reset(LMAC_DISABLE, 0); break; case NRF_WIFI_CMD_GET_STATS: IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_get_stats, 1); img_sys_proc_get_stats(sys_head); break; case NRF_WIFI_CMD_UMAC_INT_STATS: img_sys_proc_umac_int_stats(sys_head); break; case NRF_WIFI_CMD_CLEAR_STATS: img_sys_proc_clear_stats(sys_head); break; case NRF_WIFI_CMD_PWR: img_sys_proc_pwr_mon(sys_head); break; case NRF_WIFI_CMD_BTCOEX: img_sys_proc_coex_config(sys_head); break; #ifdef RF_TEST case NRF_WIFI_CMD_RF_TEST: IMG_CMD_EVENT_DBG_PARAM_INCR(cmd_rf_test, 1); img_sys_rf_test(sys_head); break; #endif case NRF_WIFI_CMD_HE_GI_LTF_CONFIG: img_sys_proc_he_gi_ltf_config(sys_head); break; default: wifi->unexpected_code_path ++; break; } host_rpu_msg_total_len = host_rpu_msg_total_len - sys_head->len; sys_head = (struct nrf_wifi_sys_head *)((unsigned long)sys_head + sys_head->len); } umac_hal_resubmit_cmd_buff(msg); return 0; }