xref: /wlan-driver/qca-wifi-host-cmn/utils/epping/src/epping_tx.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /*========================================================================
21*5113495bSYour Name 
22*5113495bSYour Name    \file  epping_tx.c
23*5113495bSYour Name 
24*5113495bSYour Name    \brief WLAN End Point Ping test tool implementation
25*5113495bSYour Name 
26*5113495bSYour Name    ========================================================================*/
27*5113495bSYour Name 
28*5113495bSYour Name /*--------------------------------------------------------------------------
29*5113495bSYour Name    Include Files
30*5113495bSYour Name    ------------------------------------------------------------------------*/
31*5113495bSYour Name #include <cds_api.h>
32*5113495bSYour Name #include <cds_sched.h>
33*5113495bSYour Name #include <linux/etherdevice.h>
34*5113495bSYour Name #include <linux/firmware.h>
35*5113495bSYour Name #include <wni_api.h>
36*5113495bSYour Name #include <wlan_ptt_sock_svc.h>
37*5113495bSYour Name #include <linux/wireless.h>
38*5113495bSYour Name #include <net/cfg80211.h>
39*5113495bSYour Name #include <linux/rtnetlink.h>
40*5113495bSYour Name #include <linux/semaphore.h>
41*5113495bSYour Name #include <linux/ctype.h>
42*5113495bSYour Name #include "epping_main.h"
43*5113495bSYour Name #include "epping_internal.h"
44*5113495bSYour Name #include "epping_test.h"
45*5113495bSYour Name 
46*5113495bSYour Name #define TX_RETRY_TIMEOUT_IN_MS 1
47*5113495bSYour Name 
48*5113495bSYour Name static bool enb_tx_dump;
49*5113495bSYour Name 
epping_tx_dup_pkt(epping_adapter_t * adapter,HTC_ENDPOINT_ID eid,qdf_nbuf_t skb)50*5113495bSYour Name void epping_tx_dup_pkt(epping_adapter_t *adapter,
51*5113495bSYour Name 		       HTC_ENDPOINT_ID eid, qdf_nbuf_t skb)
52*5113495bSYour Name {
53*5113495bSYour Name 	struct epping_cookie *cookie = NULL;
54*5113495bSYour Name 	int skb_len, ret;
55*5113495bSYour Name 	qdf_nbuf_t new_skb;
56*5113495bSYour Name 
57*5113495bSYour Name 	cookie = epping_alloc_cookie(adapter->pEpping_ctx);
58*5113495bSYour Name 	if (!cookie) {
59*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
60*5113495bSYour Name 			   "%s: epping_alloc_cookie returns no resource\n",
61*5113495bSYour Name 			   __func__);
62*5113495bSYour Name 		return;
63*5113495bSYour Name 	}
64*5113495bSYour Name 	new_skb = qdf_nbuf_copy(skb);
65*5113495bSYour Name 	if (!new_skb) {
66*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
67*5113495bSYour Name 			   "%s: qdf_nbuf_copy returns no resource\n", __func__);
68*5113495bSYour Name 		epping_free_cookie(adapter->pEpping_ctx, cookie);
69*5113495bSYour Name 		return;
70*5113495bSYour Name 	}
71*5113495bSYour Name 	SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
72*5113495bSYour Name 			       cookie, qdf_nbuf_data(skb),
73*5113495bSYour Name 			       qdf_nbuf_len(new_skb), eid, 0);
74*5113495bSYour Name 	SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, new_skb);
75*5113495bSYour Name 	skb_len = (int)qdf_nbuf_len(new_skb);
76*5113495bSYour Name 	/* send the packet */
77*5113495bSYour Name 	ret = htc_send_pkt(adapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt);
78*5113495bSYour Name 	if (ret != QDF_STATUS_SUCCESS) {
79*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
80*5113495bSYour Name 			   "%s: htc_send_pkt failed, ret = %d\n", __func__, ret);
81*5113495bSYour Name 		epping_free_cookie(adapter->pEpping_ctx, cookie);
82*5113495bSYour Name 		qdf_nbuf_free(new_skb);
83*5113495bSYour Name 		return;
84*5113495bSYour Name 	}
85*5113495bSYour Name 	adapter->stats.tx_bytes += skb_len;
86*5113495bSYour Name 	++adapter->stats.tx_packets;
87*5113495bSYour Name 	if (((adapter->stats.tx_packets +
88*5113495bSYour Name 	      adapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 &&
89*5113495bSYour Name 	    (adapter->stats.tx_packets || adapter->stats.tx_dropped)) {
90*5113495bSYour Name 		epping_log_stats(adapter, __func__);
91*5113495bSYour Name 	}
92*5113495bSYour Name }
93*5113495bSYour Name 
epping_tx_send_int(qdf_nbuf_t skb,epping_adapter_t * adapter)94*5113495bSYour Name static int epping_tx_send_int(qdf_nbuf_t skb, epping_adapter_t *adapter)
95*5113495bSYour Name {
96*5113495bSYour Name 	EPPING_HEADER *eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb);
97*5113495bSYour Name 	HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED;
98*5113495bSYour Name 	struct epping_cookie *cookie = NULL;
99*5113495bSYour Name 	uint8_t ac = 0;
100*5113495bSYour Name 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
101*5113495bSYour Name 	int skb_len;
102*5113495bSYour Name 	EPPING_HEADER tmpHdr = *eppingHdr;
103*5113495bSYour Name 
104*5113495bSYour Name 	/* allocate resource for this packet */
105*5113495bSYour Name 	cookie = epping_alloc_cookie(adapter->pEpping_ctx);
106*5113495bSYour Name 	/* no resource */
107*5113495bSYour Name 	if (!cookie) {
108*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
109*5113495bSYour Name 			   "%s: epping_alloc_cookie returns no resource\n",
110*5113495bSYour Name 			   __func__);
111*5113495bSYour Name 		return A_ERROR;
112*5113495bSYour Name 	}
113*5113495bSYour Name 
114*5113495bSYour Name 	if (enb_tx_dump)
115*5113495bSYour Name 		epping_hex_dump((void *)eppingHdr, skb->len, __func__);
116*5113495bSYour Name 	/*
117*5113495bSYour Name 	 * a quirk of linux, the payload of the frame is 32-bit aligned and thus
118*5113495bSYour Name 	 * the addition of the HTC header will mis-align the start of the HTC
119*5113495bSYour Name 	 * frame, so we add some padding which will be stripped off in the target
120*5113495bSYour Name 	 */
121*5113495bSYour Name 	if (EPPING_ALIGNMENT_PAD > 0) {
122*5113495bSYour Name 		A_NETBUF_PUSH(skb, EPPING_ALIGNMENT_PAD);
123*5113495bSYour Name 	}
124*5113495bSYour Name 	/* prepare ep/HTC information */
125*5113495bSYour Name 	ac = eppingHdr->StreamNo_h;
126*5113495bSYour Name 	eid = adapter->pEpping_ctx->EppingEndpoint[ac];
127*5113495bSYour Name 	if (eid < 0 || eid >= EPPING_MAX_NUM_EPIDS) {
128*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
129*5113495bSYour Name 			   "%s: invalid eid = %d, ac = %d\n", __func__, eid,
130*5113495bSYour Name 			   ac);
131*5113495bSYour Name 		return A_ERROR;
132*5113495bSYour Name 	}
133*5113495bSYour Name 	if (tmpHdr.Cmd_h == EPPING_CMD_RESET_RECV_CNT ||
134*5113495bSYour Name 	    tmpHdr.Cmd_h == EPPING_CMD_CONT_RX_START) {
135*5113495bSYour Name 		epping_set_kperf_flag(adapter, eid, tmpHdr.CmdBuffer_t[0]);
136*5113495bSYour Name 	}
137*5113495bSYour Name 	SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt,
138*5113495bSYour Name 			       cookie, qdf_nbuf_data(skb), qdf_nbuf_len(skb),
139*5113495bSYour Name 			       eid, 0);
140*5113495bSYour Name 	SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, skb);
141*5113495bSYour Name 	skb_len = skb->len;
142*5113495bSYour Name 	/* send the packet */
143*5113495bSYour Name 	ret = htc_send_pkt(adapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt);
144*5113495bSYour Name 	epping_log_packet(adapter, &tmpHdr, ret, __func__);
145*5113495bSYour Name 	if (ret != QDF_STATUS_SUCCESS) {
146*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
147*5113495bSYour Name 			   "%s: htc_send_pkt failed, status = %d\n", __func__,
148*5113495bSYour Name 			   ret);
149*5113495bSYour Name 		epping_free_cookie(adapter->pEpping_ctx, cookie);
150*5113495bSYour Name 		return A_ERROR;
151*5113495bSYour Name 	}
152*5113495bSYour Name 	adapter->stats.tx_bytes += skb_len;
153*5113495bSYour Name 	++adapter->stats.tx_packets;
154*5113495bSYour Name 	if (((adapter->stats.tx_packets +
155*5113495bSYour Name 	      adapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 &&
156*5113495bSYour Name 	    (adapter->stats.tx_packets || adapter->stats.tx_dropped)) {
157*5113495bSYour Name 		epping_log_stats(adapter, __func__);
158*5113495bSYour Name 	}
159*5113495bSYour Name 
160*5113495bSYour Name 	return 0;
161*5113495bSYour Name }
162*5113495bSYour Name 
epping_tx_timer_expire(epping_adapter_t * adapter)163*5113495bSYour Name void epping_tx_timer_expire(epping_adapter_t *adapter)
164*5113495bSYour Name {
165*5113495bSYour Name 	qdf_nbuf_t nodrop_skb;
166*5113495bSYour Name 
167*5113495bSYour Name 	EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: queue len: %d\n", __func__,
168*5113495bSYour Name 		   qdf_nbuf_queue_len(&adapter->nodrop_queue));
169*5113495bSYour Name 
170*5113495bSYour Name 	if (!qdf_nbuf_queue_len(&adapter->nodrop_queue)) {
171*5113495bSYour Name 		/* nodrop queue is empty so no need to arm timer */
172*5113495bSYour Name 		adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
173*5113495bSYour Name 		return;
174*5113495bSYour Name 	}
175*5113495bSYour Name 
176*5113495bSYour Name 	/* try to flush nodrop queue */
177*5113495bSYour Name 	while ((nodrop_skb = qdf_nbuf_queue_remove(&adapter->nodrop_queue))) {
178*5113495bSYour Name 		htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, true);
179*5113495bSYour Name 		if (epping_tx_send_int(nodrop_skb, adapter)) {
180*5113495bSYour Name 			EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
181*5113495bSYour Name 				   "%s: nodrop: %pK xmit fail in timer\n",
182*5113495bSYour Name 				   __func__, nodrop_skb);
183*5113495bSYour Name 			/* fail to xmit so put the nodrop packet to the nodrop queue */
184*5113495bSYour Name 			qdf_nbuf_queue_insert_head(&adapter->nodrop_queue,
185*5113495bSYour Name 						   nodrop_skb);
186*5113495bSYour Name 			break;
187*5113495bSYour Name 		} else {
188*5113495bSYour Name 			htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, false);
189*5113495bSYour Name 			EPPING_LOG(QDF_TRACE_LEVEL_INFO,
190*5113495bSYour Name 				   "%s: nodrop: %pK xmit ok in timer\n",
191*5113495bSYour Name 				   __func__, nodrop_skb);
192*5113495bSYour Name 		}
193*5113495bSYour Name 	}
194*5113495bSYour Name 
195*5113495bSYour Name 	/* if nodrop queue is not empty, continue to arm timer */
196*5113495bSYour Name 	if (nodrop_skb) {
197*5113495bSYour Name 		qdf_spin_lock_bh(&adapter->data_lock);
198*5113495bSYour Name 		/* if nodrop queue is not empty, continue to arm timer */
199*5113495bSYour Name 		if (adapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) {
200*5113495bSYour Name 			adapter->epping_timer_state = EPPING_TX_TIMER_RUNNING;
201*5113495bSYour Name 			qdf_timer_mod(&adapter->epping_timer,
202*5113495bSYour Name 					      TX_RETRY_TIMEOUT_IN_MS);
203*5113495bSYour Name 		}
204*5113495bSYour Name 		qdf_spin_unlock_bh(&adapter->data_lock);
205*5113495bSYour Name 	} else {
206*5113495bSYour Name 		adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
207*5113495bSYour Name 	}
208*5113495bSYour Name }
209*5113495bSYour Name 
epping_tx_send(qdf_nbuf_t skb,epping_adapter_t * adapter)210*5113495bSYour Name int epping_tx_send(qdf_nbuf_t skb, epping_adapter_t *adapter)
211*5113495bSYour Name {
212*5113495bSYour Name 	qdf_nbuf_t nodrop_skb;
213*5113495bSYour Name 	EPPING_HEADER *eppingHdr;
214*5113495bSYour Name 	uint8_t ac = 0;
215*5113495bSYour Name 
216*5113495bSYour Name 	eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb);
217*5113495bSYour Name 
218*5113495bSYour Name 	if (!IS_EPPING_PACKET(eppingHdr)) {
219*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
220*5113495bSYour Name 			   "%s: Received non endpoint ping packets\n", __func__);
221*5113495bSYour Name 		/* no packet to send, cleanup */
222*5113495bSYour Name 		qdf_nbuf_free(skb);
223*5113495bSYour Name 		return -ENOMEM;
224*5113495bSYour Name 	}
225*5113495bSYour Name 
226*5113495bSYour Name 	/* the stream ID is mapped to an access class */
227*5113495bSYour Name 	ac = eppingHdr->StreamNo_h;
228*5113495bSYour Name 	/* hard coded two ep ids */
229*5113495bSYour Name 	if (ac != 0 && ac != 1) {
230*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
231*5113495bSYour Name 			   "%s: ac %d is not mapped to mboxping service\n",
232*5113495bSYour Name 			   __func__, ac);
233*5113495bSYour Name 		qdf_nbuf_free(skb);
234*5113495bSYour Name 		return -ENOMEM;
235*5113495bSYour Name 	}
236*5113495bSYour Name 
237*5113495bSYour Name 	/*
238*5113495bSYour Name 	 * some EPPING packets cannot be dropped no matter what access class
239*5113495bSYour Name 	 * it was sent on. A special care has been taken:
240*5113495bSYour Name 	 * 1. when there is no TX resource, queue the control packets to
241*5113495bSYour Name 	 *    a special queue
242*5113495bSYour Name 	 * 2. when there is TX resource, send the queued control packets first
243*5113495bSYour Name 	 *    and then other packets
244*5113495bSYour Name 	 * 3. a timer launches to check if there is queued control packets and
245*5113495bSYour Name 	 *    flush them
246*5113495bSYour Name 	 */
247*5113495bSYour Name 
248*5113495bSYour Name 	/* check the nodrop queue first */
249*5113495bSYour Name 	while ((nodrop_skb = qdf_nbuf_queue_remove(&adapter->nodrop_queue))) {
250*5113495bSYour Name 		htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, true);
251*5113495bSYour Name 		if (epping_tx_send_int(nodrop_skb, adapter)) {
252*5113495bSYour Name 			EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
253*5113495bSYour Name 				   "%s: nodrop: %pK xmit fail\n", __func__,
254*5113495bSYour Name 				   nodrop_skb);
255*5113495bSYour Name 			/* fail to xmit so put the nodrop packet to the nodrop queue */
256*5113495bSYour Name 			qdf_nbuf_queue_insert_head(&adapter->nodrop_queue,
257*5113495bSYour Name 						   nodrop_skb);
258*5113495bSYour Name 			/* no cookie so free the current skb */
259*5113495bSYour Name 			goto tx_fail;
260*5113495bSYour Name 		} else {
261*5113495bSYour Name 			htc_set_nodrop_pkt(adapter->pEpping_ctx->HTCHandle, false);
262*5113495bSYour Name 			EPPING_LOG(QDF_TRACE_LEVEL_INFO,
263*5113495bSYour Name 				   "%s: nodrop: %pK xmit ok\n", __func__,
264*5113495bSYour Name 				   nodrop_skb);
265*5113495bSYour Name 		}
266*5113495bSYour Name 	}
267*5113495bSYour Name 
268*5113495bSYour Name 	/* send the original packet */
269*5113495bSYour Name 	if (epping_tx_send_int(skb, adapter))
270*5113495bSYour Name 		goto tx_fail;
271*5113495bSYour Name 
272*5113495bSYour Name 	return 0;
273*5113495bSYour Name 
274*5113495bSYour Name tx_fail:
275*5113495bSYour Name 	if (!IS_EPING_PACKET_NO_DROP(eppingHdr)) {
276*5113495bSYour Name 		/* allow to drop the skb so drop it */
277*5113495bSYour Name 		qdf_nbuf_free(skb);
278*5113495bSYour Name 		++adapter->stats.tx_dropped;
279*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
280*5113495bSYour Name 			   "%s: Tx skb %pK dropped, stats.tx_dropped = %ld\n",
281*5113495bSYour Name 			   __func__, skb, adapter->stats.tx_dropped);
282*5113495bSYour Name 		return -ENOMEM;
283*5113495bSYour Name 	} else {
284*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
285*5113495bSYour Name 			   "%s: nodrop: %pK queued\n", __func__, skb);
286*5113495bSYour Name 		qdf_nbuf_queue_add(&adapter->nodrop_queue, skb);
287*5113495bSYour Name 		qdf_spin_lock_bh(&adapter->data_lock);
288*5113495bSYour Name 		if (adapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) {
289*5113495bSYour Name 			adapter->epping_timer_state = EPPING_TX_TIMER_RUNNING;
290*5113495bSYour Name 			qdf_timer_mod(&adapter->epping_timer,
291*5113495bSYour Name 					      TX_RETRY_TIMEOUT_IN_MS);
292*5113495bSYour Name 		}
293*5113495bSYour Name 		qdf_spin_unlock_bh(&adapter->data_lock);
294*5113495bSYour Name 	}
295*5113495bSYour Name 
296*5113495bSYour Name 	return 0;
297*5113495bSYour Name }
298*5113495bSYour Name 
299*5113495bSYour Name #ifdef HIF_SDIO
epping_tx_queue_full(void * Context,HTC_PACKET * pPacket)300*5113495bSYour Name enum htc_send_full_action epping_tx_queue_full(void *Context,
301*5113495bSYour Name 						HTC_PACKET *pPacket)
302*5113495bSYour Name {
303*5113495bSYour Name 	/*
304*5113495bSYour Name 	 * Call netif_stop_queue frequently will impact the mboxping tx t-put.
305*5113495bSYour Name 	 * Return HTC_SEND_FULL_KEEP directly in epping_tx_queue_full to avoid.
306*5113495bSYour Name 	 */
307*5113495bSYour Name 	return HTC_SEND_FULL_KEEP;
308*5113495bSYour Name }
309*5113495bSYour Name #endif /* HIF_SDIO */
epping_tx_complete(void * ctx,HTC_PACKET * htc_pkt)310*5113495bSYour Name void epping_tx_complete(void *ctx, HTC_PACKET *htc_pkt)
311*5113495bSYour Name {
312*5113495bSYour Name 	epping_context_t *pEpping_ctx = (epping_context_t *) ctx;
313*5113495bSYour Name 	epping_adapter_t *adapter = pEpping_ctx->epping_adapter;
314*5113495bSYour Name 	struct net_device *dev = adapter->dev;
315*5113495bSYour Name 	QDF_STATUS status;
316*5113495bSYour Name 	HTC_ENDPOINT_ID eid;
317*5113495bSYour Name 	qdf_nbuf_t pktSkb;
318*5113495bSYour Name 	struct epping_cookie *cookie;
319*5113495bSYour Name 	A_BOOL flushing = false;
320*5113495bSYour Name 	qdf_nbuf_queue_t skb_queue;
321*5113495bSYour Name 
322*5113495bSYour Name 	if (!htc_pkt)
323*5113495bSYour Name 		return;
324*5113495bSYour Name 
325*5113495bSYour Name 	qdf_nbuf_queue_init(&skb_queue);
326*5113495bSYour Name 
327*5113495bSYour Name 	qdf_spin_lock_bh(&adapter->data_lock);
328*5113495bSYour Name 
329*5113495bSYour Name 	status = htc_pkt->Status;
330*5113495bSYour Name 	eid = htc_pkt->Endpoint;
331*5113495bSYour Name 	pktSkb = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt);
332*5113495bSYour Name 	cookie = htc_pkt->pPktContext;
333*5113495bSYour Name 
334*5113495bSYour Name 	if (!pktSkb) {
335*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
336*5113495bSYour Name 			   "%s: NULL skb from hc packet", __func__);
337*5113495bSYour Name 		QDF_BUG(0);
338*5113495bSYour Name 	} else {
339*5113495bSYour Name 		if (htc_pkt->pBuffer != qdf_nbuf_data(pktSkb)) {
340*5113495bSYour Name 			EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
341*5113495bSYour Name 				   "%s: htc_pkt buffer not equal to skb->data",
342*5113495bSYour Name 				   __func__);
343*5113495bSYour Name 			QDF_BUG(0);
344*5113495bSYour Name 		}
345*5113495bSYour Name 		/* add this to the list, use faster non-lock API */
346*5113495bSYour Name 		qdf_nbuf_queue_add(&skb_queue, pktSkb);
347*5113495bSYour Name 
348*5113495bSYour Name 		if (QDF_IS_STATUS_SUCCESS(status)) {
349*5113495bSYour Name 			if (htc_pkt->ActualLength !=
350*5113495bSYour Name 				qdf_nbuf_len(pktSkb)) {
351*5113495bSYour Name 				EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
352*5113495bSYour Name 					   "%s: htc_pkt length not equal to skb->len",
353*5113495bSYour Name 					   __func__);
354*5113495bSYour Name 				QDF_BUG(0);
355*5113495bSYour Name 			}
356*5113495bSYour Name 		}
357*5113495bSYour Name 	}
358*5113495bSYour Name 
359*5113495bSYour Name 	EPPING_LOG(QDF_TRACE_LEVEL_INFO,
360*5113495bSYour Name 		   "%s skb=%pK data=%pK len=0x%x eid=%d ",
361*5113495bSYour Name 		   __func__, pktSkb, htc_pkt->pBuffer,
362*5113495bSYour Name 		   htc_pkt->ActualLength, eid);
363*5113495bSYour Name 
364*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
365*5113495bSYour Name 		if (status == QDF_STATUS_E_CANCELED) {
366*5113495bSYour Name 			/* a packet was flushed  */
367*5113495bSYour Name 			flushing = true;
368*5113495bSYour Name 		}
369*5113495bSYour Name 		if (status != QDF_STATUS_E_RESOURCES) {
370*5113495bSYour Name 			EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
371*5113495bSYour Name 				   "%s() -TX ERROR, status: 0x%x",
372*5113495bSYour Name 				   __func__, status);
373*5113495bSYour Name 		}
374*5113495bSYour Name 	} else {
375*5113495bSYour Name 		EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: OK\n", __func__);
376*5113495bSYour Name 		flushing = false;
377*5113495bSYour Name 	}
378*5113495bSYour Name 
379*5113495bSYour Name 	epping_free_cookie(adapter->pEpping_ctx, cookie);
380*5113495bSYour Name 	qdf_spin_unlock_bh(&adapter->data_lock);
381*5113495bSYour Name 
382*5113495bSYour Name 	/* free all skbs in our local list */
383*5113495bSYour Name 	while (qdf_nbuf_queue_len(&skb_queue)) {
384*5113495bSYour Name 		/* use non-lock version */
385*5113495bSYour Name 		pktSkb = qdf_nbuf_queue_remove(&skb_queue);
386*5113495bSYour Name 		if (!pktSkb)
387*5113495bSYour Name 			break;
388*5113495bSYour Name 		qdf_nbuf_tx_free(pktSkb, QDF_NBUF_PKT_ERROR);
389*5113495bSYour Name 		pEpping_ctx->total_tx_acks++;
390*5113495bSYour Name 	}
391*5113495bSYour Name 
392*5113495bSYour Name 	if (!flushing) {
393*5113495bSYour Name 		netif_wake_queue(dev);
394*5113495bSYour Name 	}
395*5113495bSYour Name }
396