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