18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: generic TX/RX data handling 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 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * This function processes the received buffer. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Main responsibility of this function is to parse the RxPD to 318c2ecf20Sopenharmony_ci * identify the correct interface this packet is headed for and 328c2ecf20Sopenharmony_ci * forwarding it to the associated handling function, where the 338c2ecf20Sopenharmony_ci * packet will be further processed and sent to kernel/upper layer 348c2ecf20Sopenharmony_ci * if required. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ciint mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, 378c2ecf20Sopenharmony_ci struct sk_buff *skb) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct mwifiex_private *priv = 408c2ecf20Sopenharmony_ci mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 418c2ecf20Sopenharmony_ci struct rxpd *local_rx_pd; 428c2ecf20Sopenharmony_ci struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); 438c2ecf20Sopenharmony_ci int ret; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci local_rx_pd = (struct rxpd *) (skb->data); 468c2ecf20Sopenharmony_ci /* Get the BSS number from rxpd, get corresponding priv */ 478c2ecf20Sopenharmony_ci priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & 488c2ecf20Sopenharmony_ci BSS_NUM_MASK, local_rx_pd->bss_type); 498c2ecf20Sopenharmony_ci if (!priv) 508c2ecf20Sopenharmony_ci priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (!priv) { 538c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 548c2ecf20Sopenharmony_ci "data: priv not found. Drop RX packet\n"); 558c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 568c2ecf20Sopenharmony_ci return -1; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci mwifiex_dbg_dump(adapter, DAT_D, "rx pkt:", skb->data, 608c2ecf20Sopenharmony_ci min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN)); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci memset(rx_info, 0, sizeof(*rx_info)); 638c2ecf20Sopenharmony_ci rx_info->bss_num = priv->bss_num; 648c2ecf20Sopenharmony_ci rx_info->bss_type = priv->bss_type; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) 678c2ecf20Sopenharmony_ci ret = mwifiex_process_uap_rx_packet(priv, skb); 688c2ecf20Sopenharmony_ci else 698c2ecf20Sopenharmony_ci ret = mwifiex_process_sta_rx_packet(priv, skb); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return ret; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * This function sends a packet to device. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * It processes the packet to add the TxPD, checks condition and 798c2ecf20Sopenharmony_ci * sends the processed packet to firmware for transmission. 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * On successful completion, the function calls the completion callback 828c2ecf20Sopenharmony_ci * and logs the time. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ciint mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, 858c2ecf20Sopenharmony_ci struct mwifiex_tx_param *tx_param) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci int hroom, ret = -1; 888c2ecf20Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 898c2ecf20Sopenharmony_ci u8 *head_ptr; 908c2ecf20Sopenharmony_ci struct txpd *local_tx_pd = NULL; 918c2ecf20Sopenharmony_ci struct mwifiex_sta_node *dest_node; 928c2ecf20Sopenharmony_ci struct ethhdr *hdr = (void *)skb->data; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci hroom = adapter->intf_hdr_len; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) { 978c2ecf20Sopenharmony_ci dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest); 988c2ecf20Sopenharmony_ci if (dest_node) { 998c2ecf20Sopenharmony_ci dest_node->stats.tx_bytes += skb->len; 1008c2ecf20Sopenharmony_ci dest_node->stats.tx_packets++; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci head_ptr = mwifiex_process_uap_txpd(priv, skb); 1048c2ecf20Sopenharmony_ci } else { 1058c2ecf20Sopenharmony_ci head_ptr = mwifiex_process_sta_txpd(priv, skb); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) { 1098c2ecf20Sopenharmony_ci skb_queue_tail(&adapter->tx_data_q, skb); 1108c2ecf20Sopenharmony_ci atomic_inc(&adapter->tx_queued); 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (head_ptr) { 1158c2ecf20Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) 1168c2ecf20Sopenharmony_ci local_tx_pd = (struct txpd *)(head_ptr + hroom); 1178c2ecf20Sopenharmony_ci if (adapter->iface_type == MWIFIEX_USB) { 1188c2ecf20Sopenharmony_ci ret = adapter->if_ops.host_to_card(adapter, 1198c2ecf20Sopenharmony_ci priv->usb_port, 1208c2ecf20Sopenharmony_ci skb, tx_param); 1218c2ecf20Sopenharmony_ci } else { 1228c2ecf20Sopenharmony_ci ret = adapter->if_ops.host_to_card(adapter, 1238c2ecf20Sopenharmony_ci MWIFIEX_TYPE_DATA, 1248c2ecf20Sopenharmony_ci skb, tx_param); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data, 1288c2ecf20Sopenharmony_ci min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN)); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci switch (ret) { 1318c2ecf20Sopenharmony_ci case -ENOSR: 1328c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, DATA, "data: -ENOSR is returned\n"); 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case -EBUSY: 1358c2ecf20Sopenharmony_ci if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 1368c2ecf20Sopenharmony_ci (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { 1378c2ecf20Sopenharmony_ci priv->adapter->tx_lock_flag = false; 1388c2ecf20Sopenharmony_ci if (local_tx_pd) 1398c2ecf20Sopenharmony_ci local_tx_pd->flags = 0; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n"); 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case -1: 1448c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 1458c2ecf20Sopenharmony_ci "mwifiex_write_data_async failed: 0x%X\n", 1468c2ecf20Sopenharmony_ci ret); 1478c2ecf20Sopenharmony_ci adapter->dbg.num_tx_host_to_card_failure++; 1488c2ecf20Sopenharmony_ci mwifiex_write_data_complete(adapter, skb, 0, ret); 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case -EINPROGRESS: 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case 0: 1538c2ecf20Sopenharmony_ci mwifiex_write_data_complete(adapter, skb, 0, ret); 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci default: 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int mwifiex_host_to_card(struct mwifiex_adapter *adapter, 1638c2ecf20Sopenharmony_ci struct sk_buff *skb, 1648c2ecf20Sopenharmony_ci struct mwifiex_tx_param *tx_param) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct txpd *local_tx_pd = NULL; 1678c2ecf20Sopenharmony_ci u8 *head_ptr = skb->data; 1688c2ecf20Sopenharmony_ci int ret = 0; 1698c2ecf20Sopenharmony_ci struct mwifiex_private *priv; 1708c2ecf20Sopenharmony_ci struct mwifiex_txinfo *tx_info; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci tx_info = MWIFIEX_SKB_TXCB(skb); 1738c2ecf20Sopenharmony_ci priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num, 1748c2ecf20Sopenharmony_ci tx_info->bss_type); 1758c2ecf20Sopenharmony_ci if (!priv) { 1768c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 1778c2ecf20Sopenharmony_ci "data: priv not found. Drop TX packet\n"); 1788c2ecf20Sopenharmony_ci adapter->dbg.num_tx_host_to_card_failure++; 1798c2ecf20Sopenharmony_ci mwifiex_write_data_complete(adapter, skb, 0, 0); 1808c2ecf20Sopenharmony_ci return ret; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) 1838c2ecf20Sopenharmony_ci local_tx_pd = (struct txpd *)(head_ptr + adapter->intf_hdr_len); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (adapter->iface_type == MWIFIEX_USB) { 1868c2ecf20Sopenharmony_ci ret = adapter->if_ops.host_to_card(adapter, 1878c2ecf20Sopenharmony_ci priv->usb_port, 1888c2ecf20Sopenharmony_ci skb, tx_param); 1898c2ecf20Sopenharmony_ci } else { 1908c2ecf20Sopenharmony_ci ret = adapter->if_ops.host_to_card(adapter, 1918c2ecf20Sopenharmony_ci MWIFIEX_TYPE_DATA, 1928c2ecf20Sopenharmony_ci skb, tx_param); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci switch (ret) { 1958c2ecf20Sopenharmony_ci case -ENOSR: 1968c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n"); 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case -EBUSY: 1998c2ecf20Sopenharmony_ci if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 2008c2ecf20Sopenharmony_ci (adapter->pps_uapsd_mode) && 2018c2ecf20Sopenharmony_ci (adapter->tx_lock_flag)) { 2028c2ecf20Sopenharmony_ci priv->adapter->tx_lock_flag = false; 2038c2ecf20Sopenharmony_ci if (local_tx_pd) 2048c2ecf20Sopenharmony_ci local_tx_pd->flags = 0; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci skb_queue_head(&adapter->tx_data_q, skb); 2078c2ecf20Sopenharmony_ci if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) 2088c2ecf20Sopenharmony_ci atomic_add(tx_info->aggr_num, &adapter->tx_queued); 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci atomic_inc(&adapter->tx_queued); 2118c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n"); 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case -1: 2148c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 2158c2ecf20Sopenharmony_ci "mwifiex_write_data_async failed: 0x%X\n", ret); 2168c2ecf20Sopenharmony_ci adapter->dbg.num_tx_host_to_card_failure++; 2178c2ecf20Sopenharmony_ci mwifiex_write_data_complete(adapter, skb, 0, ret); 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci case -EINPROGRESS: 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci case 0: 2228c2ecf20Sopenharmony_ci mwifiex_write_data_complete(adapter, skb, 0, ret); 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci default: 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int 2318c2ecf20Sopenharmony_cimwifiex_dequeue_tx_queue(struct mwifiex_adapter *adapter) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct sk_buff *skb, *skb_next; 2348c2ecf20Sopenharmony_ci struct mwifiex_txinfo *tx_info; 2358c2ecf20Sopenharmony_ci struct mwifiex_tx_param tx_param; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci skb = skb_dequeue(&adapter->tx_data_q); 2388c2ecf20Sopenharmony_ci if (!skb) 2398c2ecf20Sopenharmony_ci return -1; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci tx_info = MWIFIEX_SKB_TXCB(skb); 2428c2ecf20Sopenharmony_ci if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) 2438c2ecf20Sopenharmony_ci atomic_sub(tx_info->aggr_num, &adapter->tx_queued); 2448c2ecf20Sopenharmony_ci else 2458c2ecf20Sopenharmony_ci atomic_dec(&adapter->tx_queued); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (!skb_queue_empty(&adapter->tx_data_q)) 2488c2ecf20Sopenharmony_ci skb_next = skb_peek(&adapter->tx_data_q); 2498c2ecf20Sopenharmony_ci else 2508c2ecf20Sopenharmony_ci skb_next = NULL; 2518c2ecf20Sopenharmony_ci tx_param.next_pkt_len = ((skb_next) ? skb_next->len : 0); 2528c2ecf20Sopenharmony_ci if (!tx_param.next_pkt_len) { 2538c2ecf20Sopenharmony_ci if (!mwifiex_wmm_lists_empty(adapter)) 2548c2ecf20Sopenharmony_ci tx_param.next_pkt_len = 1; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci return mwifiex_host_to_card(adapter, skb, &tx_param); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_civoid 2608c2ecf20Sopenharmony_cimwifiex_process_tx_queue(struct mwifiex_adapter *adapter) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci do { 2638c2ecf20Sopenharmony_ci if (adapter->data_sent || adapter->tx_lock_flag) 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci if (mwifiex_dequeue_tx_queue(adapter)) 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci } while (!skb_queue_empty(&adapter->tx_data_q)); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* 2718c2ecf20Sopenharmony_ci * Packet send completion callback handler. 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * It either frees the buffer directly or forwards it to another 2748c2ecf20Sopenharmony_ci * completion callback which checks conditions, updates statistics, 2758c2ecf20Sopenharmony_ci * wakes up stalled traffic queue if required, and then frees the buffer. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ciint mwifiex_write_data_complete(struct mwifiex_adapter *adapter, 2788c2ecf20Sopenharmony_ci struct sk_buff *skb, int aggr, int status) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct mwifiex_private *priv; 2818c2ecf20Sopenharmony_ci struct mwifiex_txinfo *tx_info; 2828c2ecf20Sopenharmony_ci struct netdev_queue *txq; 2838c2ecf20Sopenharmony_ci int index; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (!skb) 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci tx_info = MWIFIEX_SKB_TXCB(skb); 2898c2ecf20Sopenharmony_ci priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num, 2908c2ecf20Sopenharmony_ci tx_info->bss_type); 2918c2ecf20Sopenharmony_ci if (!priv) 2928c2ecf20Sopenharmony_ci goto done; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci mwifiex_set_trans_start(priv->netdev); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) 2978c2ecf20Sopenharmony_ci atomic_dec_return(&adapter->pending_bridged_pkts); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) 3008c2ecf20Sopenharmony_ci goto done; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (!status) { 3038c2ecf20Sopenharmony_ci priv->stats.tx_packets++; 3048c2ecf20Sopenharmony_ci priv->stats.tx_bytes += tx_info->pkt_len; 3058c2ecf20Sopenharmony_ci if (priv->tx_timeout_cnt) 3068c2ecf20Sopenharmony_ci priv->tx_timeout_cnt = 0; 3078c2ecf20Sopenharmony_ci } else { 3088c2ecf20Sopenharmony_ci priv->stats.tx_errors++; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (aggr) 3128c2ecf20Sopenharmony_ci /* For skb_aggr, do not wake up tx queue */ 3138c2ecf20Sopenharmony_ci goto done; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci atomic_dec(&adapter->tx_pending); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci index = mwifiex_1d_to_wmm_queue[skb->priority]; 3188c2ecf20Sopenharmony_ci if (atomic_dec_return(&priv->wmm_tx_pending[index]) < LOW_TX_PENDING) { 3198c2ecf20Sopenharmony_ci txq = netdev_get_tx_queue(priv->netdev, index); 3208c2ecf20Sopenharmony_ci if (netif_tx_queue_stopped(txq)) { 3218c2ecf20Sopenharmony_ci netif_tx_wake_queue(txq); 3228c2ecf20Sopenharmony_ci mwifiex_dbg(adapter, DATA, "wake queue: %d\n", index); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_cidone: 3268c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_write_data_complete); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_civoid mwifiex_parse_tx_status_event(struct mwifiex_private *priv, 3338c2ecf20Sopenharmony_ci void *event_body) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct tx_status_event *tx_status = (void *)priv->adapter->event_body; 3368c2ecf20Sopenharmony_ci struct sk_buff *ack_skb; 3378c2ecf20Sopenharmony_ci struct mwifiex_txinfo *tx_info; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (!tx_status->tx_token_id) 3408c2ecf20Sopenharmony_ci return; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci spin_lock_bh(&priv->ack_status_lock); 3438c2ecf20Sopenharmony_ci ack_skb = idr_remove(&priv->ack_status_frames, tx_status->tx_token_id); 3448c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->ack_status_lock); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (ack_skb) { 3478c2ecf20Sopenharmony_ci tx_info = MWIFIEX_SKB_TXCB(ack_skb); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS) { 3508c2ecf20Sopenharmony_ci /* consumes ack_skb */ 3518c2ecf20Sopenharmony_ci skb_complete_wifi_ack(ack_skb, !tx_status->status); 3528c2ecf20Sopenharmony_ci } else { 3538c2ecf20Sopenharmony_ci /* Remove broadcast address which was added by driver */ 3548c2ecf20Sopenharmony_ci memmove(ack_skb->data + 3558c2ecf20Sopenharmony_ci sizeof(struct ieee80211_hdr_3addr) + 3568c2ecf20Sopenharmony_ci MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16), 3578c2ecf20Sopenharmony_ci ack_skb->data + 3588c2ecf20Sopenharmony_ci sizeof(struct ieee80211_hdr_3addr) + 3598c2ecf20Sopenharmony_ci MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + 3608c2ecf20Sopenharmony_ci ETH_ALEN, ack_skb->len - 3618c2ecf20Sopenharmony_ci (sizeof(struct ieee80211_hdr_3addr) + 3628c2ecf20Sopenharmony_ci MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + 3638c2ecf20Sopenharmony_ci ETH_ALEN)); 3648c2ecf20Sopenharmony_ci ack_skb->len = ack_skb->len - ETH_ALEN; 3658c2ecf20Sopenharmony_ci /* Remove driver's proprietary header including 2 bytes 3668c2ecf20Sopenharmony_ci * of packet length and pass actual management frame buffer 3678c2ecf20Sopenharmony_ci * to cfg80211. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie, 3708c2ecf20Sopenharmony_ci ack_skb->data + 3718c2ecf20Sopenharmony_ci MWIFIEX_MGMT_FRAME_HEADER_SIZE + 3728c2ecf20Sopenharmony_ci sizeof(u16), ack_skb->len - 3738c2ecf20Sopenharmony_ci (MWIFIEX_MGMT_FRAME_HEADER_SIZE 3748c2ecf20Sopenharmony_ci + sizeof(u16)), 3758c2ecf20Sopenharmony_ci !tx_status->status, GFP_ATOMIC); 3768c2ecf20Sopenharmony_ci dev_kfree_skb_any(ack_skb); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci} 380