18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: utility functions 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991 88c2ecf20Sopenharmony_ci * (the "License"). You may use, redistribute and/or modify this File in 98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which 108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc., 118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 178c2ecf20Sopenharmony_ci * this warranty disclaimer. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "decl.h" 218c2ecf20Sopenharmony_ci#include "ioctl.h" 228c2ecf20Sopenharmony_ci#include "util.h" 238c2ecf20Sopenharmony_ci#include "fw.h" 248c2ecf20Sopenharmony_ci#include "main.h" 258c2ecf20Sopenharmony_ci#include "wmm.h" 268c2ecf20Sopenharmony_ci#include "11n.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct mwifiex_debug_data items[] = { 298c2ecf20Sopenharmony_ci {"debug_mask", item_size(debug_mask), 308c2ecf20Sopenharmony_ci item_addr(debug_mask), 1}, 318c2ecf20Sopenharmony_ci {"int_counter", item_size(int_counter), 328c2ecf20Sopenharmony_ci item_addr(int_counter), 1}, 338c2ecf20Sopenharmony_ci {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), 348c2ecf20Sopenharmony_ci item_addr(packets_out[WMM_AC_VO]), 1}, 358c2ecf20Sopenharmony_ci {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), 368c2ecf20Sopenharmony_ci item_addr(packets_out[WMM_AC_VI]), 1}, 378c2ecf20Sopenharmony_ci {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), 388c2ecf20Sopenharmony_ci item_addr(packets_out[WMM_AC_BE]), 1}, 398c2ecf20Sopenharmony_ci {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), 408c2ecf20Sopenharmony_ci item_addr(packets_out[WMM_AC_BK]), 1}, 418c2ecf20Sopenharmony_ci {"tx_buf_size", item_size(tx_buf_size), 428c2ecf20Sopenharmony_ci item_addr(tx_buf_size), 1}, 438c2ecf20Sopenharmony_ci {"curr_tx_buf_size", item_size(curr_tx_buf_size), 448c2ecf20Sopenharmony_ci item_addr(curr_tx_buf_size), 1}, 458c2ecf20Sopenharmony_ci {"ps_mode", item_size(ps_mode), 468c2ecf20Sopenharmony_ci item_addr(ps_mode), 1}, 478c2ecf20Sopenharmony_ci {"ps_state", item_size(ps_state), 488c2ecf20Sopenharmony_ci item_addr(ps_state), 1}, 498c2ecf20Sopenharmony_ci {"is_deep_sleep", item_size(is_deep_sleep), 508c2ecf20Sopenharmony_ci item_addr(is_deep_sleep), 1}, 518c2ecf20Sopenharmony_ci {"wakeup_dev_req", item_size(pm_wakeup_card_req), 528c2ecf20Sopenharmony_ci item_addr(pm_wakeup_card_req), 1}, 538c2ecf20Sopenharmony_ci {"wakeup_tries", item_size(pm_wakeup_fw_try), 548c2ecf20Sopenharmony_ci item_addr(pm_wakeup_fw_try), 1}, 558c2ecf20Sopenharmony_ci {"hs_configured", item_size(is_hs_configured), 568c2ecf20Sopenharmony_ci item_addr(is_hs_configured), 1}, 578c2ecf20Sopenharmony_ci {"hs_activated", item_size(hs_activated), 588c2ecf20Sopenharmony_ci item_addr(hs_activated), 1}, 598c2ecf20Sopenharmony_ci {"num_tx_timeout", item_size(num_tx_timeout), 608c2ecf20Sopenharmony_ci item_addr(num_tx_timeout), 1}, 618c2ecf20Sopenharmony_ci {"is_cmd_timedout", item_size(is_cmd_timedout), 628c2ecf20Sopenharmony_ci item_addr(is_cmd_timedout), 1}, 638c2ecf20Sopenharmony_ci {"timeout_cmd_id", item_size(timeout_cmd_id), 648c2ecf20Sopenharmony_ci item_addr(timeout_cmd_id), 1}, 658c2ecf20Sopenharmony_ci {"timeout_cmd_act", item_size(timeout_cmd_act), 668c2ecf20Sopenharmony_ci item_addr(timeout_cmd_act), 1}, 678c2ecf20Sopenharmony_ci {"last_cmd_id", item_size(last_cmd_id), 688c2ecf20Sopenharmony_ci item_addr(last_cmd_id), DBG_CMD_NUM}, 698c2ecf20Sopenharmony_ci {"last_cmd_act", item_size(last_cmd_act), 708c2ecf20Sopenharmony_ci item_addr(last_cmd_act), DBG_CMD_NUM}, 718c2ecf20Sopenharmony_ci {"last_cmd_index", item_size(last_cmd_index), 728c2ecf20Sopenharmony_ci item_addr(last_cmd_index), 1}, 738c2ecf20Sopenharmony_ci {"last_cmd_resp_id", item_size(last_cmd_resp_id), 748c2ecf20Sopenharmony_ci item_addr(last_cmd_resp_id), DBG_CMD_NUM}, 758c2ecf20Sopenharmony_ci {"last_cmd_resp_index", item_size(last_cmd_resp_index), 768c2ecf20Sopenharmony_ci item_addr(last_cmd_resp_index), 1}, 778c2ecf20Sopenharmony_ci {"last_event", item_size(last_event), 788c2ecf20Sopenharmony_ci item_addr(last_event), DBG_CMD_NUM}, 798c2ecf20Sopenharmony_ci {"last_event_index", item_size(last_event_index), 808c2ecf20Sopenharmony_ci item_addr(last_event_index), 1}, 818c2ecf20Sopenharmony_ci {"last_mp_wr_bitmap", item_size(last_mp_wr_bitmap), 828c2ecf20Sopenharmony_ci item_addr(last_mp_wr_bitmap), MWIFIEX_DBG_SDIO_MP_NUM}, 838c2ecf20Sopenharmony_ci {"last_mp_wr_ports", item_size(last_mp_wr_ports), 848c2ecf20Sopenharmony_ci item_addr(last_mp_wr_ports), MWIFIEX_DBG_SDIO_MP_NUM}, 858c2ecf20Sopenharmony_ci {"last_mp_wr_len", item_size(last_mp_wr_len), 868c2ecf20Sopenharmony_ci item_addr(last_mp_wr_len), MWIFIEX_DBG_SDIO_MP_NUM}, 878c2ecf20Sopenharmony_ci {"last_mp_curr_wr_port", item_size(last_mp_curr_wr_port), 888c2ecf20Sopenharmony_ci item_addr(last_mp_curr_wr_port), MWIFIEX_DBG_SDIO_MP_NUM}, 898c2ecf20Sopenharmony_ci {"last_sdio_mp_index", item_size(last_sdio_mp_index), 908c2ecf20Sopenharmony_ci item_addr(last_sdio_mp_index), 1}, 918c2ecf20Sopenharmony_ci {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), 928c2ecf20Sopenharmony_ci item_addr(num_cmd_host_to_card_failure), 1}, 938c2ecf20Sopenharmony_ci {"num_cmd_sleep_cfm_fail", 948c2ecf20Sopenharmony_ci item_size(num_cmd_sleep_cfm_host_to_card_failure), 958c2ecf20Sopenharmony_ci item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, 968c2ecf20Sopenharmony_ci {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), 978c2ecf20Sopenharmony_ci item_addr(num_tx_host_to_card_failure), 1}, 988c2ecf20Sopenharmony_ci {"num_evt_deauth", item_size(num_event_deauth), 998c2ecf20Sopenharmony_ci item_addr(num_event_deauth), 1}, 1008c2ecf20Sopenharmony_ci {"num_evt_disassoc", item_size(num_event_disassoc), 1018c2ecf20Sopenharmony_ci item_addr(num_event_disassoc), 1}, 1028c2ecf20Sopenharmony_ci {"num_evt_link_lost", item_size(num_event_link_lost), 1038c2ecf20Sopenharmony_ci item_addr(num_event_link_lost), 1}, 1048c2ecf20Sopenharmony_ci {"num_cmd_deauth", item_size(num_cmd_deauth), 1058c2ecf20Sopenharmony_ci item_addr(num_cmd_deauth), 1}, 1068c2ecf20Sopenharmony_ci {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), 1078c2ecf20Sopenharmony_ci item_addr(num_cmd_assoc_success), 1}, 1088c2ecf20Sopenharmony_ci {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), 1098c2ecf20Sopenharmony_ci item_addr(num_cmd_assoc_failure), 1}, 1108c2ecf20Sopenharmony_ci {"cmd_sent", item_size(cmd_sent), 1118c2ecf20Sopenharmony_ci item_addr(cmd_sent), 1}, 1128c2ecf20Sopenharmony_ci {"data_sent", item_size(data_sent), 1138c2ecf20Sopenharmony_ci item_addr(data_sent), 1}, 1148c2ecf20Sopenharmony_ci {"cmd_resp_received", item_size(cmd_resp_received), 1158c2ecf20Sopenharmony_ci item_addr(cmd_resp_received), 1}, 1168c2ecf20Sopenharmony_ci {"event_received", item_size(event_received), 1178c2ecf20Sopenharmony_ci item_addr(event_received), 1}, 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* variables defined in struct mwifiex_adapter */ 1208c2ecf20Sopenharmony_ci {"cmd_pending", adapter_item_size(cmd_pending), 1218c2ecf20Sopenharmony_ci adapter_item_addr(cmd_pending), 1}, 1228c2ecf20Sopenharmony_ci {"tx_pending", adapter_item_size(tx_pending), 1238c2ecf20Sopenharmony_ci adapter_item_addr(tx_pending), 1}, 1248c2ecf20Sopenharmony_ci {"rx_pending", adapter_item_size(rx_pending), 1258c2ecf20Sopenharmony_ci adapter_item_addr(rx_pending), 1}, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int num_of_items = ARRAY_SIZE(items); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * Firmware initialization complete callback handler. 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * This function wakes up the function waiting on the init 1348c2ecf20Sopenharmony_ci * wait queue for the firmware initialization to complete. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ciint mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) 1408c2ecf20Sopenharmony_ci if (adapter->if_ops.init_fw_port) 1418c2ecf20Sopenharmony_ci adapter->if_ops.init_fw_port(adapter); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci adapter->init_wait_q_woken = true; 1448c2ecf20Sopenharmony_ci wake_up_interruptible(&adapter->init_wait_q); 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* 1498c2ecf20Sopenharmony_ci * This function sends init/shutdown command 1508c2ecf20Sopenharmony_ci * to firmware. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ciint mwifiex_init_shutdown_fw(struct mwifiex_private *priv, 1538c2ecf20Sopenharmony_ci u32 func_init_shutdown) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci u16 cmd; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (func_init_shutdown == MWIFIEX_FUNC_INIT) { 1588c2ecf20Sopenharmony_ci cmd = HostCmd_CMD_FUNC_INIT; 1598c2ecf20Sopenharmony_ci } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) { 1608c2ecf20Sopenharmony_ci cmd = HostCmd_CMD_FUNC_SHUTDOWN; 1618c2ecf20Sopenharmony_ci } else { 1628c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 1638c2ecf20Sopenharmony_ci "unsupported parameter\n"); 1648c2ecf20Sopenharmony_ci return -1; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* 1728c2ecf20Sopenharmony_ci * IOCTL request handler to set/get debug information. 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * This function collates/sets the information from/to different driver 1758c2ecf20Sopenharmony_ci * structures. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ciint mwifiex_get_debug_info(struct mwifiex_private *priv, 1788c2ecf20Sopenharmony_ci struct mwifiex_debug_info *info) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (info) { 1838c2ecf20Sopenharmony_ci info->debug_mask = adapter->debug_mask; 1848c2ecf20Sopenharmony_ci memcpy(info->packets_out, 1858c2ecf20Sopenharmony_ci priv->wmm.packets_out, 1868c2ecf20Sopenharmony_ci sizeof(priv->wmm.packets_out)); 1878c2ecf20Sopenharmony_ci info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size; 1888c2ecf20Sopenharmony_ci info->tx_buf_size = (u32) adapter->tx_buf_size; 1898c2ecf20Sopenharmony_ci info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv, 1908c2ecf20Sopenharmony_ci info->rx_tbl); 1918c2ecf20Sopenharmony_ci info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv, 1928c2ecf20Sopenharmony_ci info->tx_tbl); 1938c2ecf20Sopenharmony_ci info->tdls_peer_num = mwifiex_get_tdls_list(priv, 1948c2ecf20Sopenharmony_ci info->tdls_list); 1958c2ecf20Sopenharmony_ci info->ps_mode = adapter->ps_mode; 1968c2ecf20Sopenharmony_ci info->ps_state = adapter->ps_state; 1978c2ecf20Sopenharmony_ci info->is_deep_sleep = adapter->is_deep_sleep; 1988c2ecf20Sopenharmony_ci info->pm_wakeup_card_req = adapter->pm_wakeup_card_req; 1998c2ecf20Sopenharmony_ci info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; 2008c2ecf20Sopenharmony_ci info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED, 2018c2ecf20Sopenharmony_ci &adapter->work_flags); 2028c2ecf20Sopenharmony_ci info->hs_activated = adapter->hs_activated; 2038c2ecf20Sopenharmony_ci info->is_cmd_timedout = test_bit(MWIFIEX_IS_CMD_TIMEDOUT, 2048c2ecf20Sopenharmony_ci &adapter->work_flags); 2058c2ecf20Sopenharmony_ci info->num_cmd_host_to_card_failure 2068c2ecf20Sopenharmony_ci = adapter->dbg.num_cmd_host_to_card_failure; 2078c2ecf20Sopenharmony_ci info->num_cmd_sleep_cfm_host_to_card_failure 2088c2ecf20Sopenharmony_ci = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; 2098c2ecf20Sopenharmony_ci info->num_tx_host_to_card_failure 2108c2ecf20Sopenharmony_ci = adapter->dbg.num_tx_host_to_card_failure; 2118c2ecf20Sopenharmony_ci info->num_event_deauth = adapter->dbg.num_event_deauth; 2128c2ecf20Sopenharmony_ci info->num_event_disassoc = adapter->dbg.num_event_disassoc; 2138c2ecf20Sopenharmony_ci info->num_event_link_lost = adapter->dbg.num_event_link_lost; 2148c2ecf20Sopenharmony_ci info->num_cmd_deauth = adapter->dbg.num_cmd_deauth; 2158c2ecf20Sopenharmony_ci info->num_cmd_assoc_success = 2168c2ecf20Sopenharmony_ci adapter->dbg.num_cmd_assoc_success; 2178c2ecf20Sopenharmony_ci info->num_cmd_assoc_failure = 2188c2ecf20Sopenharmony_ci adapter->dbg.num_cmd_assoc_failure; 2198c2ecf20Sopenharmony_ci info->num_tx_timeout = adapter->dbg.num_tx_timeout; 2208c2ecf20Sopenharmony_ci info->timeout_cmd_id = adapter->dbg.timeout_cmd_id; 2218c2ecf20Sopenharmony_ci info->timeout_cmd_act = adapter->dbg.timeout_cmd_act; 2228c2ecf20Sopenharmony_ci memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id, 2238c2ecf20Sopenharmony_ci sizeof(adapter->dbg.last_cmd_id)); 2248c2ecf20Sopenharmony_ci memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act, 2258c2ecf20Sopenharmony_ci sizeof(adapter->dbg.last_cmd_act)); 2268c2ecf20Sopenharmony_ci info->last_cmd_index = adapter->dbg.last_cmd_index; 2278c2ecf20Sopenharmony_ci memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id, 2288c2ecf20Sopenharmony_ci sizeof(adapter->dbg.last_cmd_resp_id)); 2298c2ecf20Sopenharmony_ci info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index; 2308c2ecf20Sopenharmony_ci memcpy(info->last_event, adapter->dbg.last_event, 2318c2ecf20Sopenharmony_ci sizeof(adapter->dbg.last_event)); 2328c2ecf20Sopenharmony_ci info->last_event_index = adapter->dbg.last_event_index; 2338c2ecf20Sopenharmony_ci memcpy(info->last_mp_wr_bitmap, adapter->dbg.last_mp_wr_bitmap, 2348c2ecf20Sopenharmony_ci sizeof(adapter->dbg.last_mp_wr_bitmap)); 2358c2ecf20Sopenharmony_ci memcpy(info->last_mp_wr_ports, adapter->dbg.last_mp_wr_ports, 2368c2ecf20Sopenharmony_ci sizeof(adapter->dbg.last_mp_wr_ports)); 2378c2ecf20Sopenharmony_ci memcpy(info->last_mp_curr_wr_port, 2388c2ecf20Sopenharmony_ci adapter->dbg.last_mp_curr_wr_port, 2398c2ecf20Sopenharmony_ci sizeof(adapter->dbg.last_mp_curr_wr_port)); 2408c2ecf20Sopenharmony_ci memcpy(info->last_mp_wr_len, adapter->dbg.last_mp_wr_len, 2418c2ecf20Sopenharmony_ci sizeof(adapter->dbg.last_mp_wr_len)); 2428c2ecf20Sopenharmony_ci info->last_sdio_mp_index = adapter->dbg.last_sdio_mp_index; 2438c2ecf20Sopenharmony_ci info->data_sent = adapter->data_sent; 2448c2ecf20Sopenharmony_ci info->cmd_sent = adapter->cmd_sent; 2458c2ecf20Sopenharmony_ci info->cmd_resp_received = adapter->cmd_resp_received; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciint mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf, 2528c2ecf20Sopenharmony_ci struct mwifiex_debug_info *info) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci char *p = buf; 2558c2ecf20Sopenharmony_ci struct mwifiex_debug_data *d = &items[0]; 2568c2ecf20Sopenharmony_ci size_t size, addr; 2578c2ecf20Sopenharmony_ci long val; 2588c2ecf20Sopenharmony_ci int i, j; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (!info) 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci for (i = 0; i < num_of_items; i++) { 2648c2ecf20Sopenharmony_ci p += sprintf(p, "%s=", d[i].name); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci size = d[i].size / d[i].num; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (i < (num_of_items - 3)) 2698c2ecf20Sopenharmony_ci addr = d[i].addr + (size_t)info; 2708c2ecf20Sopenharmony_ci else /* The last 3 items are struct mwifiex_adapter variables */ 2718c2ecf20Sopenharmony_ci addr = d[i].addr + (size_t)priv->adapter; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci for (j = 0; j < d[i].num; j++) { 2748c2ecf20Sopenharmony_ci switch (size) { 2758c2ecf20Sopenharmony_ci case 1: 2768c2ecf20Sopenharmony_ci val = *((u8 *)addr); 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci case 2: 2798c2ecf20Sopenharmony_ci val = get_unaligned((u16 *)addr); 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci case 4: 2828c2ecf20Sopenharmony_ci val = get_unaligned((u32 *)addr); 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci case 8: 2858c2ecf20Sopenharmony_ci val = get_unaligned((long long *)addr); 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci default: 2888c2ecf20Sopenharmony_ci val = -1; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci p += sprintf(p, "%#lx ", val); 2938c2ecf20Sopenharmony_ci addr += size; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci p += sprintf(p, "\n"); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (info->tx_tbl_num) { 3008c2ecf20Sopenharmony_ci p += sprintf(p, "Tx BA stream table:\n"); 3018c2ecf20Sopenharmony_ci for (i = 0; i < info->tx_tbl_num; i++) 3028c2ecf20Sopenharmony_ci p += sprintf(p, "tid = %d, ra = %pM\n", 3038c2ecf20Sopenharmony_ci info->tx_tbl[i].tid, info->tx_tbl[i].ra); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (info->rx_tbl_num) { 3078c2ecf20Sopenharmony_ci p += sprintf(p, "Rx reorder table:\n"); 3088c2ecf20Sopenharmony_ci for (i = 0; i < info->rx_tbl_num; i++) { 3098c2ecf20Sopenharmony_ci p += sprintf(p, "tid = %d, ta = %pM, ", 3108c2ecf20Sopenharmony_ci info->rx_tbl[i].tid, 3118c2ecf20Sopenharmony_ci info->rx_tbl[i].ta); 3128c2ecf20Sopenharmony_ci p += sprintf(p, "start_win = %d, ", 3138c2ecf20Sopenharmony_ci info->rx_tbl[i].start_win); 3148c2ecf20Sopenharmony_ci p += sprintf(p, "win_size = %d, buffer: ", 3158c2ecf20Sopenharmony_ci info->rx_tbl[i].win_size); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci for (j = 0; j < info->rx_tbl[i].win_size; j++) 3188c2ecf20Sopenharmony_ci p += sprintf(p, "%c ", 3198c2ecf20Sopenharmony_ci info->rx_tbl[i].buffer[j] ? 3208c2ecf20Sopenharmony_ci '1' : '0'); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci p += sprintf(p, "\n"); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (info->tdls_peer_num) { 3278c2ecf20Sopenharmony_ci p += sprintf(p, "TDLS peer table:\n"); 3288c2ecf20Sopenharmony_ci for (i = 0; i < info->tdls_peer_num; i++) { 3298c2ecf20Sopenharmony_ci p += sprintf(p, "peer = %pM", 3308c2ecf20Sopenharmony_ci info->tdls_list[i].peer_addr); 3318c2ecf20Sopenharmony_ci p += sprintf(p, "\n"); 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return p - buf; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int 3398c2ecf20Sopenharmony_cimwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, 3408c2ecf20Sopenharmony_ci struct rxpd *rx_pd) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci u16 stype; 3438c2ecf20Sopenharmony_ci u8 category, action_code, *addr2; 3448c2ecf20Sopenharmony_ci struct ieee80211_hdr *ieee_hdr = (void *)payload; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci switch (stype) { 3498c2ecf20Sopenharmony_ci case IEEE80211_STYPE_ACTION: 3508c2ecf20Sopenharmony_ci category = *(payload + sizeof(struct ieee80211_hdr)); 3518c2ecf20Sopenharmony_ci switch (category) { 3528c2ecf20Sopenharmony_ci case WLAN_CATEGORY_PUBLIC: 3538c2ecf20Sopenharmony_ci action_code = *(payload + sizeof(struct ieee80211_hdr) 3548c2ecf20Sopenharmony_ci + 1); 3558c2ecf20Sopenharmony_ci if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { 3568c2ecf20Sopenharmony_ci addr2 = ieee_hdr->addr2; 3578c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 3588c2ecf20Sopenharmony_ci "TDLS discovery response %pM nf=%d, snr=%d\n", 3598c2ecf20Sopenharmony_ci addr2, rx_pd->nf, rx_pd->snr); 3608c2ecf20Sopenharmony_ci mwifiex_auto_tdls_update_peer_signal(priv, 3618c2ecf20Sopenharmony_ci addr2, 3628c2ecf20Sopenharmony_ci rx_pd->snr, 3638c2ecf20Sopenharmony_ci rx_pd->nf); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci case WLAN_CATEGORY_BACK: 3678c2ecf20Sopenharmony_ci /*we dont indicate BACK action frames to cfg80211*/ 3688c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 3698c2ecf20Sopenharmony_ci "drop BACK action frames"); 3708c2ecf20Sopenharmony_ci return -1; 3718c2ecf20Sopenharmony_ci default: 3728c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 3738c2ecf20Sopenharmony_ci "unknown public action frame category %d\n", 3748c2ecf20Sopenharmony_ci category); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci default: 3788c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 3798c2ecf20Sopenharmony_ci "unknown mgmt frame subtype %#x\n", stype); 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci/* 3868c2ecf20Sopenharmony_ci * This function processes the received management packet and send it 3878c2ecf20Sopenharmony_ci * to the kernel. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ciint 3908c2ecf20Sopenharmony_cimwifiex_process_mgmt_packet(struct mwifiex_private *priv, 3918c2ecf20Sopenharmony_ci struct sk_buff *skb) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct rxpd *rx_pd; 3948c2ecf20Sopenharmony_ci u16 pkt_len; 3958c2ecf20Sopenharmony_ci struct ieee80211_hdr *ieee_hdr; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (!skb) 3988c2ecf20Sopenharmony_ci return -1; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (!priv->mgmt_frame_mask || 4018c2ecf20Sopenharmony_ci priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) { 4028c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 4038c2ecf20Sopenharmony_ci "do not receive mgmt frames on uninitialized intf"); 4048c2ecf20Sopenharmony_ci return -1; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci rx_pd = (struct rxpd *)skb->data; 4088c2ecf20Sopenharmony_ci pkt_len = le16_to_cpu(rx_pd->rx_pkt_length); 4098c2ecf20Sopenharmony_ci if (pkt_len < sizeof(struct ieee80211_hdr) + sizeof(pkt_len)) { 4108c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "invalid rx_pkt_length"); 4118c2ecf20Sopenharmony_ci return -1; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset)); 4158c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(pkt_len)); 4168c2ecf20Sopenharmony_ci pkt_len -= sizeof(pkt_len); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ieee_hdr = (void *)skb->data; 4198c2ecf20Sopenharmony_ci if (ieee80211_is_mgmt(ieee_hdr->frame_control)) { 4208c2ecf20Sopenharmony_ci if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr, 4218c2ecf20Sopenharmony_ci pkt_len, rx_pd)) 4228c2ecf20Sopenharmony_ci return -1; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci /* Remove address4 */ 4258c2ecf20Sopenharmony_ci memmove(skb->data + sizeof(struct ieee80211_hdr_3addr), 4268c2ecf20Sopenharmony_ci skb->data + sizeof(struct ieee80211_hdr), 4278c2ecf20Sopenharmony_ci pkt_len - sizeof(struct ieee80211_hdr)); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci pkt_len -= ETH_ALEN; 4308c2ecf20Sopenharmony_ci rx_pd->rx_pkt_length = cpu_to_le16(pkt_len); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq, 4338c2ecf20Sopenharmony_ci CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len, 4348c2ecf20Sopenharmony_ci 0); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* 4408c2ecf20Sopenharmony_ci * This function processes the received packet before sending it to the 4418c2ecf20Sopenharmony_ci * kernel. 4428c2ecf20Sopenharmony_ci * 4438c2ecf20Sopenharmony_ci * It extracts the SKB from the received buffer and sends it to kernel. 4448c2ecf20Sopenharmony_ci * In case the received buffer does not contain the data in SKB format, 4458c2ecf20Sopenharmony_ci * the function creates a blank SKB, fills it with the data from the 4468c2ecf20Sopenharmony_ci * received buffer and then sends this new SKB to the kernel. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_ciint mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct mwifiex_sta_node *src_node; 4518c2ecf20Sopenharmony_ci struct ethhdr *p_ethhdr; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (!skb) 4548c2ecf20Sopenharmony_ci return -1; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci priv->stats.rx_bytes += skb->len; 4578c2ecf20Sopenharmony_ci priv->stats.rx_packets++; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 4608c2ecf20Sopenharmony_ci p_ethhdr = (void *)skb->data; 4618c2ecf20Sopenharmony_ci src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source); 4628c2ecf20Sopenharmony_ci if (src_node) { 4638c2ecf20Sopenharmony_ci src_node->stats.last_rx = jiffies; 4648c2ecf20Sopenharmony_ci src_node->stats.rx_bytes += skb->len; 4658c2ecf20Sopenharmony_ci src_node->stats.rx_packets++; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci skb->dev = priv->netdev; 4708c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, priv->netdev); 4718c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* This is required only in case of 11n and USB/PCIE as we alloc 4748c2ecf20Sopenharmony_ci * a buffer of 4K only if its 11N (to be able to receive 4K 4758c2ecf20Sopenharmony_ci * AMSDU packets). In case of SD we allocate buffers based 4768c2ecf20Sopenharmony_ci * on the size of packet and hence this is not needed. 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * Modifying the truesize here as our allocation for each 4798c2ecf20Sopenharmony_ci * skb is 4K but we only receive 2K packets and this cause 4808c2ecf20Sopenharmony_ci * the kernel to start dropping packets in case where 4818c2ecf20Sopenharmony_ci * application has allocated buffer based on 2K size i.e. 4828c2ecf20Sopenharmony_ci * if there a 64K packet received (in IP fragments and 4838c2ecf20Sopenharmony_ci * application allocates 64K to receive this packet but 4848c2ecf20Sopenharmony_ci * this packet would almost double up because we allocate 4858c2ecf20Sopenharmony_ci * each 1.5K fragment in 4K and pass it up. As soon as the 4868c2ecf20Sopenharmony_ci * 64K limit hits kernel will start to drop rest of the 4878c2ecf20Sopenharmony_ci * fragments. Currently we fail the Filesndl-ht.scr script 4888c2ecf20Sopenharmony_ci * for UDP, hence this fix 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_ci if ((priv->adapter->iface_type == MWIFIEX_USB || 4918c2ecf20Sopenharmony_ci priv->adapter->iface_type == MWIFIEX_PCIE) && 4928c2ecf20Sopenharmony_ci (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)) 4938c2ecf20Sopenharmony_ci skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci netif_rx_any_context(skb); 4968c2ecf20Sopenharmony_ci return 0; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci/* 5008c2ecf20Sopenharmony_ci * IOCTL completion callback handler. 5018c2ecf20Sopenharmony_ci * 5028c2ecf20Sopenharmony_ci * This function is called when a pending IOCTL is completed. 5038c2ecf20Sopenharmony_ci * 5048c2ecf20Sopenharmony_ci * If work queue support is enabled, the function wakes up the 5058c2ecf20Sopenharmony_ci * corresponding waiting function. Otherwise, it processes the 5068c2ecf20Sopenharmony_ci * IOCTL response and frees the response buffer. 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ciint mwifiex_complete_cmd(struct mwifiex_adapter *adapter, 5098c2ecf20Sopenharmony_ci struct cmd_ctrl_node *cmd_node) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci WARN_ON(!cmd_node->wait_q_enabled); 5128c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n", 5138c2ecf20Sopenharmony_ci adapter->cmd_wait_q.status); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci *cmd_node->condition = true; 5168c2ecf20Sopenharmony_ci wake_up_interruptible(&adapter->cmd_wait_q.wait); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci/* This function will return the pointer to station entry in station list 5228c2ecf20Sopenharmony_ci * table which matches specified mac address. 5238c2ecf20Sopenharmony_ci * This function should be called after acquiring RA list spinlock. 5248c2ecf20Sopenharmony_ci * NULL is returned if station entry is not found in associated STA list. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_cistruct mwifiex_sta_node * 5278c2ecf20Sopenharmony_cimwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct mwifiex_sta_node *node; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (!mac) 5328c2ecf20Sopenharmony_ci return NULL; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci list_for_each_entry(node, &priv->sta_list, list) { 5358c2ecf20Sopenharmony_ci if (!memcmp(node->mac_addr, mac, ETH_ALEN)) 5368c2ecf20Sopenharmony_ci return node; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return NULL; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic struct mwifiex_sta_node * 5438c2ecf20Sopenharmony_cimwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct mwifiex_sta_node *node; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci list_for_each_entry(node, &priv->sta_list, list) { 5488c2ecf20Sopenharmony_ci if (node->tdls_status == status) 5498c2ecf20Sopenharmony_ci return node; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return NULL; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/* If tdls channel switching is on-going, tx data traffic should be 5568c2ecf20Sopenharmony_ci * blocked until the switching stage completed. 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ciu8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) 5638c2ecf20Sopenharmony_ci return false; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING); 5668c2ecf20Sopenharmony_ci if (sta_ptr) 5678c2ecf20Sopenharmony_ci return true; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return false; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ciu8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) 5778c2ecf20Sopenharmony_ci return false; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN); 5808c2ecf20Sopenharmony_ci if (sta_ptr) 5818c2ecf20Sopenharmony_ci return true; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return false; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci/* If tdls channel switching is on-going or tdls operate on off-channel, 5878c2ecf20Sopenharmony_ci * cmd path should be blocked until tdls switched to base-channel. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ciu8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) 5928c2ecf20Sopenharmony_ci return true; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (mwifiex_is_tdls_chan_switching(priv) || 5958c2ecf20Sopenharmony_ci mwifiex_is_tdls_off_chan(priv)) 5968c2ecf20Sopenharmony_ci return false; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return true; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/* This function will add a sta_node entry to associated station list 6028c2ecf20Sopenharmony_ci * table with the given mac address. 6038c2ecf20Sopenharmony_ci * If entry exist already, existing entry is returned. 6048c2ecf20Sopenharmony_ci * If received mac address is NULL, NULL is returned. 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_cistruct mwifiex_sta_node * 6078c2ecf20Sopenharmony_cimwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct mwifiex_sta_node *node; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (!mac) 6128c2ecf20Sopenharmony_ci return NULL; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 6158c2ecf20Sopenharmony_ci node = mwifiex_get_sta_entry(priv, mac); 6168c2ecf20Sopenharmony_ci if (node) 6178c2ecf20Sopenharmony_ci goto done; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_ATOMIC); 6208c2ecf20Sopenharmony_ci if (!node) 6218c2ecf20Sopenharmony_ci goto done; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci memcpy(node->mac_addr, mac, ETH_ALEN); 6248c2ecf20Sopenharmony_ci list_add_tail(&node->list, &priv->sta_list); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cidone: 6278c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 6288c2ecf20Sopenharmony_ci return node; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci/* This function will search for HT IE in association request IEs 6328c2ecf20Sopenharmony_ci * and set station HT parameters accordingly. 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_civoid 6358c2ecf20Sopenharmony_cimwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies, 6368c2ecf20Sopenharmony_ci int ies_len, struct mwifiex_sta_node *node) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct ieee_types_header *ht_cap_ie; 6398c2ecf20Sopenharmony_ci const struct ieee80211_ht_cap *ht_cap; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (!ies) 6428c2ecf20Sopenharmony_ci return; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, 6458c2ecf20Sopenharmony_ci ies_len); 6468c2ecf20Sopenharmony_ci if (ht_cap_ie) { 6478c2ecf20Sopenharmony_ci ht_cap = (void *)(ht_cap_ie + 1); 6488c2ecf20Sopenharmony_ci node->is_11n_enabled = 1; 6498c2ecf20Sopenharmony_ci node->max_amsdu = le16_to_cpu(ht_cap->cap_info) & 6508c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_MAX_AMSDU ? 6518c2ecf20Sopenharmony_ci MWIFIEX_TX_DATA_BUF_SIZE_8K : 6528c2ecf20Sopenharmony_ci MWIFIEX_TX_DATA_BUF_SIZE_4K; 6538c2ecf20Sopenharmony_ci } else { 6548c2ecf20Sopenharmony_ci node->is_11n_enabled = 0; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/* This function will delete a station entry from station list */ 6618c2ecf20Sopenharmony_civoid mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct mwifiex_sta_node *node; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci node = mwifiex_get_sta_entry(priv, mac); 6688c2ecf20Sopenharmony_ci if (node) { 6698c2ecf20Sopenharmony_ci list_del(&node->list); 6708c2ecf20Sopenharmony_ci kfree(node); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 6748c2ecf20Sopenharmony_ci return; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci/* This function will delete all stations from associated station list. */ 6788c2ecf20Sopenharmony_civoid mwifiex_del_all_sta_list(struct mwifiex_private *priv) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct mwifiex_sta_node *node, *tmp; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci list_for_each_entry_safe(node, tmp, &priv->sta_list, list) { 6858c2ecf20Sopenharmony_ci list_del(&node->list); 6868c2ecf20Sopenharmony_ci kfree(node); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->sta_list); 6908c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 6918c2ecf20Sopenharmony_ci return; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci/* This function adds histogram data to histogram array*/ 6958c2ecf20Sopenharmony_civoid mwifiex_hist_data_add(struct mwifiex_private *priv, 6968c2ecf20Sopenharmony_ci u8 rx_rate, s8 snr, s8 nflr) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci struct mwifiex_histogram_data *phist_data = priv->hist_data; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES) 7018c2ecf20Sopenharmony_ci mwifiex_hist_data_reset(priv); 7028c2ecf20Sopenharmony_ci mwifiex_hist_data_set(priv, rx_rate, snr, nflr); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/* function to add histogram record */ 7068c2ecf20Sopenharmony_civoid mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, 7078c2ecf20Sopenharmony_ci s8 nflr) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct mwifiex_histogram_data *phist_data = priv->hist_data; 7108c2ecf20Sopenharmony_ci s8 nf = -nflr; 7118c2ecf20Sopenharmony_ci s8 rssi = snr - nflr; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci atomic_inc(&phist_data->num_samples); 7148c2ecf20Sopenharmony_ci atomic_inc(&phist_data->rx_rate[rx_rate]); 7158c2ecf20Sopenharmony_ci atomic_inc(&phist_data->snr[snr + 128]); 7168c2ecf20Sopenharmony_ci atomic_inc(&phist_data->noise_flr[nf + 128]); 7178c2ecf20Sopenharmony_ci atomic_inc(&phist_data->sig_str[rssi + 128]); 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci/* function to reset histogram data during init/reset */ 7218c2ecf20Sopenharmony_civoid mwifiex_hist_data_reset(struct mwifiex_private *priv) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci int ix; 7248c2ecf20Sopenharmony_ci struct mwifiex_histogram_data *phist_data = priv->hist_data; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci atomic_set(&phist_data->num_samples, 0); 7278c2ecf20Sopenharmony_ci for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++) 7288c2ecf20Sopenharmony_ci atomic_set(&phist_data->rx_rate[ix], 0); 7298c2ecf20Sopenharmony_ci for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++) 7308c2ecf20Sopenharmony_ci atomic_set(&phist_data->snr[ix], 0); 7318c2ecf20Sopenharmony_ci for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++) 7328c2ecf20Sopenharmony_ci atomic_set(&phist_data->noise_flr[ix], 0); 7338c2ecf20Sopenharmony_ci for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++) 7348c2ecf20Sopenharmony_ci atomic_set(&phist_data->sig_str[ix], 0); 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_civoid *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct sk_buff *skb; 7408c2ecf20Sopenharmony_ci int buf_len, pad; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci buf_len = rx_len + MWIFIEX_RX_HEADROOM + MWIFIEX_DMA_ALIGN_SZ; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci skb = __dev_alloc_skb(buf_len, flags); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!skb) 7478c2ecf20Sopenharmony_ci return NULL; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci skb_reserve(skb, MWIFIEX_RX_HEADROOM); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci pad = MWIFIEX_ALIGN_ADDR(skb->data, MWIFIEX_DMA_ALIGN_SZ) - 7528c2ecf20Sopenharmony_ci (long)skb->data; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci skb_reserve(skb, pad); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci return skb; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_civoid mwifiex_fw_dump_event(struct mwifiex_private *priv) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_FW_DUMP_EVENT, HostCmd_ACT_GEN_SET, 7638c2ecf20Sopenharmony_ci 0, NULL, true); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_fw_dump_event); 766