162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Wireless LAN device driver: utility functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2020 NXP 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "decl.h" 962306a36Sopenharmony_ci#include "ioctl.h" 1062306a36Sopenharmony_ci#include "util.h" 1162306a36Sopenharmony_ci#include "fw.h" 1262306a36Sopenharmony_ci#include "main.h" 1362306a36Sopenharmony_ci#include "wmm.h" 1462306a36Sopenharmony_ci#include "11n.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic struct mwifiex_debug_data items[] = { 1762306a36Sopenharmony_ci {"debug_mask", item_size(debug_mask), 1862306a36Sopenharmony_ci item_addr(debug_mask), 1}, 1962306a36Sopenharmony_ci {"int_counter", item_size(int_counter), 2062306a36Sopenharmony_ci item_addr(int_counter), 1}, 2162306a36Sopenharmony_ci {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), 2262306a36Sopenharmony_ci item_addr(packets_out[WMM_AC_VO]), 1}, 2362306a36Sopenharmony_ci {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), 2462306a36Sopenharmony_ci item_addr(packets_out[WMM_AC_VI]), 1}, 2562306a36Sopenharmony_ci {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), 2662306a36Sopenharmony_ci item_addr(packets_out[WMM_AC_BE]), 1}, 2762306a36Sopenharmony_ci {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), 2862306a36Sopenharmony_ci item_addr(packets_out[WMM_AC_BK]), 1}, 2962306a36Sopenharmony_ci {"tx_buf_size", item_size(tx_buf_size), 3062306a36Sopenharmony_ci item_addr(tx_buf_size), 1}, 3162306a36Sopenharmony_ci {"curr_tx_buf_size", item_size(curr_tx_buf_size), 3262306a36Sopenharmony_ci item_addr(curr_tx_buf_size), 1}, 3362306a36Sopenharmony_ci {"ps_mode", item_size(ps_mode), 3462306a36Sopenharmony_ci item_addr(ps_mode), 1}, 3562306a36Sopenharmony_ci {"ps_state", item_size(ps_state), 3662306a36Sopenharmony_ci item_addr(ps_state), 1}, 3762306a36Sopenharmony_ci {"is_deep_sleep", item_size(is_deep_sleep), 3862306a36Sopenharmony_ci item_addr(is_deep_sleep), 1}, 3962306a36Sopenharmony_ci {"wakeup_dev_req", item_size(pm_wakeup_card_req), 4062306a36Sopenharmony_ci item_addr(pm_wakeup_card_req), 1}, 4162306a36Sopenharmony_ci {"wakeup_tries", item_size(pm_wakeup_fw_try), 4262306a36Sopenharmony_ci item_addr(pm_wakeup_fw_try), 1}, 4362306a36Sopenharmony_ci {"hs_configured", item_size(is_hs_configured), 4462306a36Sopenharmony_ci item_addr(is_hs_configured), 1}, 4562306a36Sopenharmony_ci {"hs_activated", item_size(hs_activated), 4662306a36Sopenharmony_ci item_addr(hs_activated), 1}, 4762306a36Sopenharmony_ci {"num_tx_timeout", item_size(num_tx_timeout), 4862306a36Sopenharmony_ci item_addr(num_tx_timeout), 1}, 4962306a36Sopenharmony_ci {"is_cmd_timedout", item_size(is_cmd_timedout), 5062306a36Sopenharmony_ci item_addr(is_cmd_timedout), 1}, 5162306a36Sopenharmony_ci {"timeout_cmd_id", item_size(timeout_cmd_id), 5262306a36Sopenharmony_ci item_addr(timeout_cmd_id), 1}, 5362306a36Sopenharmony_ci {"timeout_cmd_act", item_size(timeout_cmd_act), 5462306a36Sopenharmony_ci item_addr(timeout_cmd_act), 1}, 5562306a36Sopenharmony_ci {"last_cmd_id", item_size(last_cmd_id), 5662306a36Sopenharmony_ci item_addr(last_cmd_id), DBG_CMD_NUM}, 5762306a36Sopenharmony_ci {"last_cmd_act", item_size(last_cmd_act), 5862306a36Sopenharmony_ci item_addr(last_cmd_act), DBG_CMD_NUM}, 5962306a36Sopenharmony_ci {"last_cmd_index", item_size(last_cmd_index), 6062306a36Sopenharmony_ci item_addr(last_cmd_index), 1}, 6162306a36Sopenharmony_ci {"last_cmd_resp_id", item_size(last_cmd_resp_id), 6262306a36Sopenharmony_ci item_addr(last_cmd_resp_id), DBG_CMD_NUM}, 6362306a36Sopenharmony_ci {"last_cmd_resp_index", item_size(last_cmd_resp_index), 6462306a36Sopenharmony_ci item_addr(last_cmd_resp_index), 1}, 6562306a36Sopenharmony_ci {"last_event", item_size(last_event), 6662306a36Sopenharmony_ci item_addr(last_event), DBG_CMD_NUM}, 6762306a36Sopenharmony_ci {"last_event_index", item_size(last_event_index), 6862306a36Sopenharmony_ci item_addr(last_event_index), 1}, 6962306a36Sopenharmony_ci {"last_mp_wr_bitmap", item_size(last_mp_wr_bitmap), 7062306a36Sopenharmony_ci item_addr(last_mp_wr_bitmap), MWIFIEX_DBG_SDIO_MP_NUM}, 7162306a36Sopenharmony_ci {"last_mp_wr_ports", item_size(last_mp_wr_ports), 7262306a36Sopenharmony_ci item_addr(last_mp_wr_ports), MWIFIEX_DBG_SDIO_MP_NUM}, 7362306a36Sopenharmony_ci {"last_mp_wr_len", item_size(last_mp_wr_len), 7462306a36Sopenharmony_ci item_addr(last_mp_wr_len), MWIFIEX_DBG_SDIO_MP_NUM}, 7562306a36Sopenharmony_ci {"last_mp_curr_wr_port", item_size(last_mp_curr_wr_port), 7662306a36Sopenharmony_ci item_addr(last_mp_curr_wr_port), MWIFIEX_DBG_SDIO_MP_NUM}, 7762306a36Sopenharmony_ci {"last_sdio_mp_index", item_size(last_sdio_mp_index), 7862306a36Sopenharmony_ci item_addr(last_sdio_mp_index), 1}, 7962306a36Sopenharmony_ci {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), 8062306a36Sopenharmony_ci item_addr(num_cmd_host_to_card_failure), 1}, 8162306a36Sopenharmony_ci {"num_cmd_sleep_cfm_fail", 8262306a36Sopenharmony_ci item_size(num_cmd_sleep_cfm_host_to_card_failure), 8362306a36Sopenharmony_ci item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, 8462306a36Sopenharmony_ci {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), 8562306a36Sopenharmony_ci item_addr(num_tx_host_to_card_failure), 1}, 8662306a36Sopenharmony_ci {"num_evt_deauth", item_size(num_event_deauth), 8762306a36Sopenharmony_ci item_addr(num_event_deauth), 1}, 8862306a36Sopenharmony_ci {"num_evt_disassoc", item_size(num_event_disassoc), 8962306a36Sopenharmony_ci item_addr(num_event_disassoc), 1}, 9062306a36Sopenharmony_ci {"num_evt_link_lost", item_size(num_event_link_lost), 9162306a36Sopenharmony_ci item_addr(num_event_link_lost), 1}, 9262306a36Sopenharmony_ci {"num_cmd_deauth", item_size(num_cmd_deauth), 9362306a36Sopenharmony_ci item_addr(num_cmd_deauth), 1}, 9462306a36Sopenharmony_ci {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), 9562306a36Sopenharmony_ci item_addr(num_cmd_assoc_success), 1}, 9662306a36Sopenharmony_ci {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), 9762306a36Sopenharmony_ci item_addr(num_cmd_assoc_failure), 1}, 9862306a36Sopenharmony_ci {"cmd_sent", item_size(cmd_sent), 9962306a36Sopenharmony_ci item_addr(cmd_sent), 1}, 10062306a36Sopenharmony_ci {"data_sent", item_size(data_sent), 10162306a36Sopenharmony_ci item_addr(data_sent), 1}, 10262306a36Sopenharmony_ci {"cmd_resp_received", item_size(cmd_resp_received), 10362306a36Sopenharmony_ci item_addr(cmd_resp_received), 1}, 10462306a36Sopenharmony_ci {"event_received", item_size(event_received), 10562306a36Sopenharmony_ci item_addr(event_received), 1}, 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* variables defined in struct mwifiex_adapter */ 10862306a36Sopenharmony_ci {"cmd_pending", adapter_item_size(cmd_pending), 10962306a36Sopenharmony_ci adapter_item_addr(cmd_pending), 1}, 11062306a36Sopenharmony_ci {"tx_pending", adapter_item_size(tx_pending), 11162306a36Sopenharmony_ci adapter_item_addr(tx_pending), 1}, 11262306a36Sopenharmony_ci {"rx_pending", adapter_item_size(rx_pending), 11362306a36Sopenharmony_ci adapter_item_addr(rx_pending), 1}, 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int num_of_items = ARRAY_SIZE(items); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* 11962306a36Sopenharmony_ci * Firmware initialization complete callback handler. 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * This function wakes up the function waiting on the init 12262306a36Sopenharmony_ci * wait queue for the firmware initialization to complete. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ciint mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) 12862306a36Sopenharmony_ci if (adapter->if_ops.init_fw_port) 12962306a36Sopenharmony_ci adapter->if_ops.init_fw_port(adapter); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci adapter->init_wait_q_woken = true; 13262306a36Sopenharmony_ci wake_up_interruptible(&adapter->init_wait_q); 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* 13762306a36Sopenharmony_ci * This function sends init/shutdown command 13862306a36Sopenharmony_ci * to firmware. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ciint mwifiex_init_shutdown_fw(struct mwifiex_private *priv, 14162306a36Sopenharmony_ci u32 func_init_shutdown) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci u16 cmd; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (func_init_shutdown == MWIFIEX_FUNC_INIT) { 14662306a36Sopenharmony_ci cmd = HostCmd_CMD_FUNC_INIT; 14762306a36Sopenharmony_ci } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) { 14862306a36Sopenharmony_ci cmd = HostCmd_CMD_FUNC_SHUTDOWN; 14962306a36Sopenharmony_ci } else { 15062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 15162306a36Sopenharmony_ci "unsupported parameter\n"); 15262306a36Sopenharmony_ci return -1; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * IOCTL request handler to set/get debug information. 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * This function collates/sets the information from/to different driver 16362306a36Sopenharmony_ci * structures. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ciint mwifiex_get_debug_info(struct mwifiex_private *priv, 16662306a36Sopenharmony_ci struct mwifiex_debug_info *info) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (info) { 17162306a36Sopenharmony_ci info->debug_mask = adapter->debug_mask; 17262306a36Sopenharmony_ci memcpy(info->packets_out, 17362306a36Sopenharmony_ci priv->wmm.packets_out, 17462306a36Sopenharmony_ci sizeof(priv->wmm.packets_out)); 17562306a36Sopenharmony_ci info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size; 17662306a36Sopenharmony_ci info->tx_buf_size = (u32) adapter->tx_buf_size; 17762306a36Sopenharmony_ci info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv, 17862306a36Sopenharmony_ci info->rx_tbl); 17962306a36Sopenharmony_ci info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv, 18062306a36Sopenharmony_ci info->tx_tbl); 18162306a36Sopenharmony_ci info->tdls_peer_num = mwifiex_get_tdls_list(priv, 18262306a36Sopenharmony_ci info->tdls_list); 18362306a36Sopenharmony_ci info->ps_mode = adapter->ps_mode; 18462306a36Sopenharmony_ci info->ps_state = adapter->ps_state; 18562306a36Sopenharmony_ci info->is_deep_sleep = adapter->is_deep_sleep; 18662306a36Sopenharmony_ci info->pm_wakeup_card_req = adapter->pm_wakeup_card_req; 18762306a36Sopenharmony_ci info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try; 18862306a36Sopenharmony_ci info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED, 18962306a36Sopenharmony_ci &adapter->work_flags); 19062306a36Sopenharmony_ci info->hs_activated = adapter->hs_activated; 19162306a36Sopenharmony_ci info->is_cmd_timedout = test_bit(MWIFIEX_IS_CMD_TIMEDOUT, 19262306a36Sopenharmony_ci &adapter->work_flags); 19362306a36Sopenharmony_ci info->num_cmd_host_to_card_failure 19462306a36Sopenharmony_ci = adapter->dbg.num_cmd_host_to_card_failure; 19562306a36Sopenharmony_ci info->num_cmd_sleep_cfm_host_to_card_failure 19662306a36Sopenharmony_ci = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure; 19762306a36Sopenharmony_ci info->num_tx_host_to_card_failure 19862306a36Sopenharmony_ci = adapter->dbg.num_tx_host_to_card_failure; 19962306a36Sopenharmony_ci info->num_event_deauth = adapter->dbg.num_event_deauth; 20062306a36Sopenharmony_ci info->num_event_disassoc = adapter->dbg.num_event_disassoc; 20162306a36Sopenharmony_ci info->num_event_link_lost = adapter->dbg.num_event_link_lost; 20262306a36Sopenharmony_ci info->num_cmd_deauth = adapter->dbg.num_cmd_deauth; 20362306a36Sopenharmony_ci info->num_cmd_assoc_success = 20462306a36Sopenharmony_ci adapter->dbg.num_cmd_assoc_success; 20562306a36Sopenharmony_ci info->num_cmd_assoc_failure = 20662306a36Sopenharmony_ci adapter->dbg.num_cmd_assoc_failure; 20762306a36Sopenharmony_ci info->num_tx_timeout = adapter->dbg.num_tx_timeout; 20862306a36Sopenharmony_ci info->timeout_cmd_id = adapter->dbg.timeout_cmd_id; 20962306a36Sopenharmony_ci info->timeout_cmd_act = adapter->dbg.timeout_cmd_act; 21062306a36Sopenharmony_ci memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id, 21162306a36Sopenharmony_ci sizeof(adapter->dbg.last_cmd_id)); 21262306a36Sopenharmony_ci memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act, 21362306a36Sopenharmony_ci sizeof(adapter->dbg.last_cmd_act)); 21462306a36Sopenharmony_ci info->last_cmd_index = adapter->dbg.last_cmd_index; 21562306a36Sopenharmony_ci memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id, 21662306a36Sopenharmony_ci sizeof(adapter->dbg.last_cmd_resp_id)); 21762306a36Sopenharmony_ci info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index; 21862306a36Sopenharmony_ci memcpy(info->last_event, adapter->dbg.last_event, 21962306a36Sopenharmony_ci sizeof(adapter->dbg.last_event)); 22062306a36Sopenharmony_ci info->last_event_index = adapter->dbg.last_event_index; 22162306a36Sopenharmony_ci memcpy(info->last_mp_wr_bitmap, adapter->dbg.last_mp_wr_bitmap, 22262306a36Sopenharmony_ci sizeof(adapter->dbg.last_mp_wr_bitmap)); 22362306a36Sopenharmony_ci memcpy(info->last_mp_wr_ports, adapter->dbg.last_mp_wr_ports, 22462306a36Sopenharmony_ci sizeof(adapter->dbg.last_mp_wr_ports)); 22562306a36Sopenharmony_ci memcpy(info->last_mp_curr_wr_port, 22662306a36Sopenharmony_ci adapter->dbg.last_mp_curr_wr_port, 22762306a36Sopenharmony_ci sizeof(adapter->dbg.last_mp_curr_wr_port)); 22862306a36Sopenharmony_ci memcpy(info->last_mp_wr_len, adapter->dbg.last_mp_wr_len, 22962306a36Sopenharmony_ci sizeof(adapter->dbg.last_mp_wr_len)); 23062306a36Sopenharmony_ci info->last_sdio_mp_index = adapter->dbg.last_sdio_mp_index; 23162306a36Sopenharmony_ci info->data_sent = adapter->data_sent; 23262306a36Sopenharmony_ci info->cmd_sent = adapter->cmd_sent; 23362306a36Sopenharmony_ci info->cmd_resp_received = adapter->cmd_resp_received; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ciint mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf, 24062306a36Sopenharmony_ci struct mwifiex_debug_info *info) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci char *p = buf; 24362306a36Sopenharmony_ci struct mwifiex_debug_data *d = &items[0]; 24462306a36Sopenharmony_ci size_t size, addr; 24562306a36Sopenharmony_ci long val; 24662306a36Sopenharmony_ci int i, j; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (!info) 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci for (i = 0; i < num_of_items; i++) { 25262306a36Sopenharmony_ci p += sprintf(p, "%s=", d[i].name); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci size = d[i].size / d[i].num; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (i < (num_of_items - 3)) 25762306a36Sopenharmony_ci addr = d[i].addr + (size_t)info; 25862306a36Sopenharmony_ci else /* The last 3 items are struct mwifiex_adapter variables */ 25962306a36Sopenharmony_ci addr = d[i].addr + (size_t)priv->adapter; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci for (j = 0; j < d[i].num; j++) { 26262306a36Sopenharmony_ci switch (size) { 26362306a36Sopenharmony_ci case 1: 26462306a36Sopenharmony_ci val = *((u8 *)addr); 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci case 2: 26762306a36Sopenharmony_ci val = get_unaligned((u16 *)addr); 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci case 4: 27062306a36Sopenharmony_ci val = get_unaligned((u32 *)addr); 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci case 8: 27362306a36Sopenharmony_ci val = get_unaligned((long long *)addr); 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci default: 27662306a36Sopenharmony_ci val = -1; 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci p += sprintf(p, "%#lx ", val); 28162306a36Sopenharmony_ci addr += size; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci p += sprintf(p, "\n"); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (info->tx_tbl_num) { 28862306a36Sopenharmony_ci p += sprintf(p, "Tx BA stream table:\n"); 28962306a36Sopenharmony_ci for (i = 0; i < info->tx_tbl_num; i++) 29062306a36Sopenharmony_ci p += sprintf(p, "tid = %d, ra = %pM\n", 29162306a36Sopenharmony_ci info->tx_tbl[i].tid, info->tx_tbl[i].ra); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (info->rx_tbl_num) { 29562306a36Sopenharmony_ci p += sprintf(p, "Rx reorder table:\n"); 29662306a36Sopenharmony_ci for (i = 0; i < info->rx_tbl_num; i++) { 29762306a36Sopenharmony_ci p += sprintf(p, "tid = %d, ta = %pM, ", 29862306a36Sopenharmony_ci info->rx_tbl[i].tid, 29962306a36Sopenharmony_ci info->rx_tbl[i].ta); 30062306a36Sopenharmony_ci p += sprintf(p, "start_win = %d, ", 30162306a36Sopenharmony_ci info->rx_tbl[i].start_win); 30262306a36Sopenharmony_ci p += sprintf(p, "win_size = %d, buffer: ", 30362306a36Sopenharmony_ci info->rx_tbl[i].win_size); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci for (j = 0; j < info->rx_tbl[i].win_size; j++) 30662306a36Sopenharmony_ci p += sprintf(p, "%c ", 30762306a36Sopenharmony_ci info->rx_tbl[i].buffer[j] ? 30862306a36Sopenharmony_ci '1' : '0'); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci p += sprintf(p, "\n"); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (info->tdls_peer_num) { 31562306a36Sopenharmony_ci p += sprintf(p, "TDLS peer table:\n"); 31662306a36Sopenharmony_ci for (i = 0; i < info->tdls_peer_num; i++) { 31762306a36Sopenharmony_ci p += sprintf(p, "peer = %pM", 31862306a36Sopenharmony_ci info->tdls_list[i].peer_addr); 31962306a36Sopenharmony_ci p += sprintf(p, "\n"); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return p - buf; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int 32762306a36Sopenharmony_cimwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, 32862306a36Sopenharmony_ci struct rxpd *rx_pd) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci u16 stype; 33162306a36Sopenharmony_ci u8 category, action_code, *addr2; 33262306a36Sopenharmony_ci struct ieee80211_hdr *ieee_hdr = (void *)payload; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci switch (stype) { 33762306a36Sopenharmony_ci case IEEE80211_STYPE_ACTION: 33862306a36Sopenharmony_ci category = *(payload + sizeof(struct ieee80211_hdr)); 33962306a36Sopenharmony_ci switch (category) { 34062306a36Sopenharmony_ci case WLAN_CATEGORY_PUBLIC: 34162306a36Sopenharmony_ci action_code = *(payload + sizeof(struct ieee80211_hdr) 34262306a36Sopenharmony_ci + 1); 34362306a36Sopenharmony_ci if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { 34462306a36Sopenharmony_ci addr2 = ieee_hdr->addr2; 34562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 34662306a36Sopenharmony_ci "TDLS discovery response %pM nf=%d, snr=%d\n", 34762306a36Sopenharmony_ci addr2, rx_pd->nf, rx_pd->snr); 34862306a36Sopenharmony_ci mwifiex_auto_tdls_update_peer_signal(priv, 34962306a36Sopenharmony_ci addr2, 35062306a36Sopenharmony_ci rx_pd->snr, 35162306a36Sopenharmony_ci rx_pd->nf); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci case WLAN_CATEGORY_BACK: 35562306a36Sopenharmony_ci /*we dont indicate BACK action frames to cfg80211*/ 35662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 35762306a36Sopenharmony_ci "drop BACK action frames"); 35862306a36Sopenharmony_ci return -1; 35962306a36Sopenharmony_ci default: 36062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 36162306a36Sopenharmony_ci "unknown public action frame category %d\n", 36262306a36Sopenharmony_ci category); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci default: 36662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 36762306a36Sopenharmony_ci "unknown mgmt frame subtype %#x\n", stype); 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci/* 37462306a36Sopenharmony_ci * This function processes the received management packet and send it 37562306a36Sopenharmony_ci * to the kernel. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ciint 37862306a36Sopenharmony_cimwifiex_process_mgmt_packet(struct mwifiex_private *priv, 37962306a36Sopenharmony_ci struct sk_buff *skb) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct rxpd *rx_pd; 38262306a36Sopenharmony_ci u16 pkt_len; 38362306a36Sopenharmony_ci struct ieee80211_hdr *ieee_hdr; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (!skb) 38662306a36Sopenharmony_ci return -1; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (!priv->mgmt_frame_mask || 38962306a36Sopenharmony_ci priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) { 39062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 39162306a36Sopenharmony_ci "do not receive mgmt frames on uninitialized intf"); 39262306a36Sopenharmony_ci return -1; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci rx_pd = (struct rxpd *)skb->data; 39662306a36Sopenharmony_ci pkt_len = le16_to_cpu(rx_pd->rx_pkt_length); 39762306a36Sopenharmony_ci if (pkt_len < sizeof(struct ieee80211_hdr) + sizeof(pkt_len)) { 39862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "invalid rx_pkt_length"); 39962306a36Sopenharmony_ci return -1; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset)); 40362306a36Sopenharmony_ci skb_pull(skb, sizeof(pkt_len)); 40462306a36Sopenharmony_ci pkt_len -= sizeof(pkt_len); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ieee_hdr = (void *)skb->data; 40762306a36Sopenharmony_ci if (ieee80211_is_mgmt(ieee_hdr->frame_control)) { 40862306a36Sopenharmony_ci if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr, 40962306a36Sopenharmony_ci pkt_len, rx_pd)) 41062306a36Sopenharmony_ci return -1; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci /* Remove address4 */ 41362306a36Sopenharmony_ci memmove(skb->data + sizeof(struct ieee80211_hdr_3addr), 41462306a36Sopenharmony_ci skb->data + sizeof(struct ieee80211_hdr), 41562306a36Sopenharmony_ci pkt_len - sizeof(struct ieee80211_hdr)); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci pkt_len -= ETH_ALEN; 41862306a36Sopenharmony_ci rx_pd->rx_pkt_length = cpu_to_le16(pkt_len); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq, 42162306a36Sopenharmony_ci CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len, 42262306a36Sopenharmony_ci 0); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci/* 42862306a36Sopenharmony_ci * This function processes the received packet before sending it to the 42962306a36Sopenharmony_ci * kernel. 43062306a36Sopenharmony_ci * 43162306a36Sopenharmony_ci * It extracts the SKB from the received buffer and sends it to kernel. 43262306a36Sopenharmony_ci * In case the received buffer does not contain the data in SKB format, 43362306a36Sopenharmony_ci * the function creates a blank SKB, fills it with the data from the 43462306a36Sopenharmony_ci * received buffer and then sends this new SKB to the kernel. 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_ciint mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct mwifiex_sta_node *src_node; 43962306a36Sopenharmony_ci struct ethhdr *p_ethhdr; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (!skb) 44262306a36Sopenharmony_ci return -1; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci priv->stats.rx_bytes += skb->len; 44562306a36Sopenharmony_ci priv->stats.rx_packets++; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 44862306a36Sopenharmony_ci p_ethhdr = (void *)skb->data; 44962306a36Sopenharmony_ci src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source); 45062306a36Sopenharmony_ci if (src_node) { 45162306a36Sopenharmony_ci src_node->stats.last_rx = jiffies; 45262306a36Sopenharmony_ci src_node->stats.rx_bytes += skb->len; 45362306a36Sopenharmony_ci src_node->stats.rx_packets++; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci skb->dev = priv->netdev; 45862306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, priv->netdev); 45962306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* This is required only in case of 11n and USB/PCIE as we alloc 46262306a36Sopenharmony_ci * a buffer of 4K only if its 11N (to be able to receive 4K 46362306a36Sopenharmony_ci * AMSDU packets). In case of SD we allocate buffers based 46462306a36Sopenharmony_ci * on the size of packet and hence this is not needed. 46562306a36Sopenharmony_ci * 46662306a36Sopenharmony_ci * Modifying the truesize here as our allocation for each 46762306a36Sopenharmony_ci * skb is 4K but we only receive 2K packets and this cause 46862306a36Sopenharmony_ci * the kernel to start dropping packets in case where 46962306a36Sopenharmony_ci * application has allocated buffer based on 2K size i.e. 47062306a36Sopenharmony_ci * if there a 64K packet received (in IP fragments and 47162306a36Sopenharmony_ci * application allocates 64K to receive this packet but 47262306a36Sopenharmony_ci * this packet would almost double up because we allocate 47362306a36Sopenharmony_ci * each 1.5K fragment in 4K and pass it up. As soon as the 47462306a36Sopenharmony_ci * 64K limit hits kernel will start to drop rest of the 47562306a36Sopenharmony_ci * fragments. Currently we fail the Filesndl-ht.scr script 47662306a36Sopenharmony_ci * for UDP, hence this fix 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci if ((priv->adapter->iface_type == MWIFIEX_USB || 47962306a36Sopenharmony_ci priv->adapter->iface_type == MWIFIEX_PCIE) && 48062306a36Sopenharmony_ci (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)) 48162306a36Sopenharmony_ci skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci netif_rx(skb); 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci/* 48862306a36Sopenharmony_ci * IOCTL completion callback handler. 48962306a36Sopenharmony_ci * 49062306a36Sopenharmony_ci * This function is called when a pending IOCTL is completed. 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * If work queue support is enabled, the function wakes up the 49362306a36Sopenharmony_ci * corresponding waiting function. Otherwise, it processes the 49462306a36Sopenharmony_ci * IOCTL response and frees the response buffer. 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ciint mwifiex_complete_cmd(struct mwifiex_adapter *adapter, 49762306a36Sopenharmony_ci struct cmd_ctrl_node *cmd_node) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci WARN_ON(!cmd_node->wait_q_enabled); 50062306a36Sopenharmony_ci mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n", 50162306a36Sopenharmony_ci adapter->cmd_wait_q.status); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci *cmd_node->condition = true; 50462306a36Sopenharmony_ci wake_up_interruptible(&adapter->cmd_wait_q.wait); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/* This function will return the pointer to station entry in station list 51062306a36Sopenharmony_ci * table which matches specified mac address. 51162306a36Sopenharmony_ci * This function should be called after acquiring RA list spinlock. 51262306a36Sopenharmony_ci * NULL is returned if station entry is not found in associated STA list. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_cistruct mwifiex_sta_node * 51562306a36Sopenharmony_cimwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct mwifiex_sta_node *node; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (!mac) 52062306a36Sopenharmony_ci return NULL; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci list_for_each_entry(node, &priv->sta_list, list) { 52362306a36Sopenharmony_ci if (!memcmp(node->mac_addr, mac, ETH_ALEN)) 52462306a36Sopenharmony_ci return node; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return NULL; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic struct mwifiex_sta_node * 53162306a36Sopenharmony_cimwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct mwifiex_sta_node *node; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci list_for_each_entry(node, &priv->sta_list, list) { 53662306a36Sopenharmony_ci if (node->tdls_status == status) 53762306a36Sopenharmony_ci return node; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return NULL; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/* If tdls channel switching is on-going, tx data traffic should be 54462306a36Sopenharmony_ci * blocked until the switching stage completed. 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_ciu8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) 55162306a36Sopenharmony_ci return false; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING); 55462306a36Sopenharmony_ci if (sta_ptr) 55562306a36Sopenharmony_ci return true; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return false; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ciu8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci struct mwifiex_sta_node *sta_ptr; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) 56562306a36Sopenharmony_ci return false; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN); 56862306a36Sopenharmony_ci if (sta_ptr) 56962306a36Sopenharmony_ci return true; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return false; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci/* If tdls channel switching is on-going or tdls operate on off-channel, 57562306a36Sopenharmony_ci * cmd path should be blocked until tdls switched to base-channel. 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ciu8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) 58062306a36Sopenharmony_ci return true; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (mwifiex_is_tdls_chan_switching(priv) || 58362306a36Sopenharmony_ci mwifiex_is_tdls_off_chan(priv)) 58462306a36Sopenharmony_ci return false; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci return true; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/* This function will add a sta_node entry to associated station list 59062306a36Sopenharmony_ci * table with the given mac address. 59162306a36Sopenharmony_ci * If entry exist already, existing entry is returned. 59262306a36Sopenharmony_ci * If received mac address is NULL, NULL is returned. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_cistruct mwifiex_sta_node * 59562306a36Sopenharmony_cimwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct mwifiex_sta_node *node; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (!mac) 60062306a36Sopenharmony_ci return NULL; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 60362306a36Sopenharmony_ci node = mwifiex_get_sta_entry(priv, mac); 60462306a36Sopenharmony_ci if (node) 60562306a36Sopenharmony_ci goto done; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_ATOMIC); 60862306a36Sopenharmony_ci if (!node) 60962306a36Sopenharmony_ci goto done; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci memcpy(node->mac_addr, mac, ETH_ALEN); 61262306a36Sopenharmony_ci list_add_tail(&node->list, &priv->sta_list); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cidone: 61562306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 61662306a36Sopenharmony_ci return node; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci/* This function will search for HT IE in association request IEs 62062306a36Sopenharmony_ci * and set station HT parameters accordingly. 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_civoid 62362306a36Sopenharmony_cimwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies, 62462306a36Sopenharmony_ci int ies_len, struct mwifiex_sta_node *node) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct ieee_types_header *ht_cap_ie; 62762306a36Sopenharmony_ci const struct ieee80211_ht_cap *ht_cap; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (!ies) 63062306a36Sopenharmony_ci return; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, 63362306a36Sopenharmony_ci ies_len); 63462306a36Sopenharmony_ci if (ht_cap_ie) { 63562306a36Sopenharmony_ci ht_cap = (void *)(ht_cap_ie + 1); 63662306a36Sopenharmony_ci node->is_11n_enabled = 1; 63762306a36Sopenharmony_ci node->max_amsdu = le16_to_cpu(ht_cap->cap_info) & 63862306a36Sopenharmony_ci IEEE80211_HT_CAP_MAX_AMSDU ? 63962306a36Sopenharmony_ci MWIFIEX_TX_DATA_BUF_SIZE_8K : 64062306a36Sopenharmony_ci MWIFIEX_TX_DATA_BUF_SIZE_4K; 64162306a36Sopenharmony_ci } else { 64262306a36Sopenharmony_ci node->is_11n_enabled = 0; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci return; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci/* This function will delete a station entry from station list */ 64962306a36Sopenharmony_civoid mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct mwifiex_sta_node *node; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci node = mwifiex_get_sta_entry(priv, mac); 65662306a36Sopenharmony_ci if (node) { 65762306a36Sopenharmony_ci list_del(&node->list); 65862306a36Sopenharmony_ci kfree(node); 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 66262306a36Sopenharmony_ci return; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci/* This function will delete all stations from associated station list. */ 66662306a36Sopenharmony_civoid mwifiex_del_all_sta_list(struct mwifiex_private *priv) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct mwifiex_sta_node *node, *tmp; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci spin_lock_bh(&priv->sta_list_spinlock); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci list_for_each_entry_safe(node, tmp, &priv->sta_list, list) { 67362306a36Sopenharmony_ci list_del(&node->list); 67462306a36Sopenharmony_ci kfree(node); 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->sta_list); 67862306a36Sopenharmony_ci spin_unlock_bh(&priv->sta_list_spinlock); 67962306a36Sopenharmony_ci return; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci/* This function adds histogram data to histogram array*/ 68362306a36Sopenharmony_civoid mwifiex_hist_data_add(struct mwifiex_private *priv, 68462306a36Sopenharmony_ci u8 rx_rate, s8 snr, s8 nflr) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct mwifiex_histogram_data *phist_data = priv->hist_data; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES) 68962306a36Sopenharmony_ci mwifiex_hist_data_reset(priv); 69062306a36Sopenharmony_ci mwifiex_hist_data_set(priv, rx_rate, snr, nflr); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/* function to add histogram record */ 69462306a36Sopenharmony_civoid mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr, 69562306a36Sopenharmony_ci s8 nflr) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct mwifiex_histogram_data *phist_data = priv->hist_data; 69862306a36Sopenharmony_ci s8 nf = -nflr; 69962306a36Sopenharmony_ci s8 rssi = snr - nflr; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci atomic_inc(&phist_data->num_samples); 70262306a36Sopenharmony_ci atomic_inc(&phist_data->rx_rate[rx_rate]); 70362306a36Sopenharmony_ci atomic_inc(&phist_data->snr[snr + 128]); 70462306a36Sopenharmony_ci atomic_inc(&phist_data->noise_flr[nf + 128]); 70562306a36Sopenharmony_ci atomic_inc(&phist_data->sig_str[rssi + 128]); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci/* function to reset histogram data during init/reset */ 70962306a36Sopenharmony_civoid mwifiex_hist_data_reset(struct mwifiex_private *priv) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci int ix; 71262306a36Sopenharmony_ci struct mwifiex_histogram_data *phist_data = priv->hist_data; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci atomic_set(&phist_data->num_samples, 0); 71562306a36Sopenharmony_ci for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++) 71662306a36Sopenharmony_ci atomic_set(&phist_data->rx_rate[ix], 0); 71762306a36Sopenharmony_ci for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++) 71862306a36Sopenharmony_ci atomic_set(&phist_data->snr[ix], 0); 71962306a36Sopenharmony_ci for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++) 72062306a36Sopenharmony_ci atomic_set(&phist_data->noise_flr[ix], 0); 72162306a36Sopenharmony_ci for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++) 72262306a36Sopenharmony_ci atomic_set(&phist_data->sig_str[ix], 0); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_civoid *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct sk_buff *skb; 72862306a36Sopenharmony_ci int buf_len, pad; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci buf_len = rx_len + MWIFIEX_RX_HEADROOM + MWIFIEX_DMA_ALIGN_SZ; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci skb = __dev_alloc_skb(buf_len, flags); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (!skb) 73562306a36Sopenharmony_ci return NULL; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci skb_reserve(skb, MWIFIEX_RX_HEADROOM); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci pad = MWIFIEX_ALIGN_ADDR(skb->data, MWIFIEX_DMA_ALIGN_SZ) - 74062306a36Sopenharmony_ci (long)skb->data; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci skb_reserve(skb, pad); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return skb; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_civoid mwifiex_fw_dump_event(struct mwifiex_private *priv) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci mwifiex_send_cmd(priv, HostCmd_CMD_FW_DUMP_EVENT, HostCmd_ACT_GEN_SET, 75162306a36Sopenharmony_ci 0, NULL, true); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_fw_dump_event); 754