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