xref: /wlan-dirver/qca-wifi-host-cmn/utils/epping/src/epping_txrx.c (revision e895717ffb3135ac0adea1ae8dcc5eccb07affa4)
1 /*
2  * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*========================================================================
21 
22    \file  epping_txrx.c
23 
24    \brief WLAN End Point Ping test tool implementation
25 
26    ========================================================================*/
27 
28 /*--------------------------------------------------------------------------
29    Include Files
30    ------------------------------------------------------------------------*/
31 #include <cds_api.h>
32 #include <cds_sched.h>
33 #include <linux/etherdevice.h>
34 #include <linux/firmware.h>
35 #include <wni_api.h>
36 #include <wlan_ptt_sock_svc.h>
37 #include <linux/wireless.h>
38 #include <net/cfg80211.h>
39 #include <pld_common.h>
40 #include <linux/rtnetlink.h>
41 #include <linux/semaphore.h>
42 #include <linux/ctype.h>
43 #include "epping_main.h"
44 #include "epping_internal.h"
45 #include "qdf_net_if.h"
46 
47 static int epping_start_adapter(epping_adapter_t *adapter);
48 static void epping_stop_adapter(epping_adapter_t *adapter);
49 
50 static void epping_timer_expire(void *data)
51 {
52 	struct net_device *dev = (struct net_device *)data;
53 	epping_adapter_t *adapter;
54 
55 	if (!dev) {
56 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
57 			   "%s: netdev = NULL", __func__);
58 		return;
59 	}
60 
61 	adapter = netdev_priv(dev);
62 	if (!adapter) {
63 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
64 			   "%s: adapter = NULL", __func__);
65 		return;
66 	}
67 	adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
68 	epping_tx_timer_expire(adapter);
69 }
70 
71 static int epping_ndev_open(struct net_device *dev)
72 {
73 	epping_adapter_t *adapter;
74 	int ret = 0;
75 
76 	adapter = netdev_priv(dev);
77 	epping_start_adapter(adapter);
78 	return ret;
79 }
80 
81 static int epping_ndev_stop(struct net_device *dev)
82 {
83 	epping_adapter_t *adapter;
84 	int ret = 0;
85 
86 	adapter = netdev_priv(dev);
87 	if (!adapter) {
88 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
89 			   "%s: EPPING adapter context is Null", __func__);
90 		ret = -ENODEV;
91 		goto end;
92 	}
93 	epping_stop_adapter(adapter);
94 end:
95 	return ret;
96 }
97 
98 static void epping_ndev_uninit(struct net_device *dev)
99 {
100 	epping_adapter_t *adapter;
101 
102 	adapter = netdev_priv(dev);
103 	if (!adapter) {
104 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
105 			   "%s: EPPING adapter context is Null", __func__);
106 		goto end;
107 	}
108 	epping_stop_adapter(adapter);
109 end:
110 	return;
111 }
112 
113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
114 static void epping_tx_queue_timeout(struct net_device *dev,
115 				    unsigned int txqueue)
116 #else
117 static void epping_tx_queue_timeout(struct net_device *dev)
118 #endif
119 {
120 	epping_adapter_t *adapter;
121 
122 	adapter = netdev_priv(dev);
123 	if (!adapter) {
124 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
125 			   "%s: EPPING adapter context is Null", __func__);
126 		goto end;
127 	}
128 
129 	EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
130 		   "%s: Transmission timeout occurred, adapter->started= %d",
131 		   __func__, adapter->started);
132 
133 	/* Getting here implies we disabled the TX queues
134 	 * for too long. Since this is epping
135 	 * (not because of disassociation or low resource scenarios),
136 	 * try to restart the queue
137 	 */
138 	if (adapter->started)
139 		netif_wake_queue(dev);
140 end:
141 	return;
142 
143 }
144 
145 static netdev_tx_t epping_hard_start_xmit(struct sk_buff *skb,
146 					  struct net_device *dev)
147 {
148 	epping_adapter_t *adapter;
149 	int ret = 0;
150 
151 	adapter = netdev_priv(dev);
152 	if (!adapter) {
153 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
154 			   "%s: EPPING adapter context is Null", __func__);
155 		kfree_skb(skb);
156 		ret = -ENODEV;
157 		goto end;
158 	}
159 	qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__);
160 	ret = epping_tx_send(skb, adapter);
161 end:
162 	return NETDEV_TX_OK;
163 }
164 
165 static struct net_device_stats *epping_get_stats(struct net_device *dev)
166 {
167 	epping_adapter_t *adapter = netdev_priv(dev);
168 
169 	if (!adapter) {
170 		EPPING_LOG(QDF_TRACE_LEVEL_ERROR, "%s: adapter = NULL",
171 			   __func__);
172 		return NULL;
173 	}
174 
175 	return &adapter->stats;
176 }
177 
178 static int epping_ndev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
179 {
180 	epping_adapter_t *adapter;
181 	int ret = 0;
182 
183 	adapter = netdev_priv(dev);
184 	if (!adapter) {
185 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
186 			   "%s: EPPING adapter context is Null", __func__);
187 		ret = -ENODEV;
188 		goto end;
189 	}
190 	if (dev != adapter->dev) {
191 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
192 			   "%s: HDD adapter/dev inconsistency", __func__);
193 		ret = -ENODEV;
194 		goto end;
195 	}
196 
197 	if ((!ifr) || (!ifr->ifr_data)) {
198 		ret = -EINVAL;
199 		goto end;
200 	}
201 
202 	switch (cmd) {
203 	case (SIOCDEVPRIVATE + 1):
204 		EPPING_LOG(QDF_TRACE_LEVEL_ERROR,
205 			   "%s: do not support ioctl %d (SIOCDEVPRIVATE + 1)",
206 			   __func__, cmd);
207 		break;
208 	default:
209 		EPPING_LOG(QDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d",
210 			   __func__, cmd);
211 		ret = -EINVAL;
212 		break;
213 	}
214 
215 end:
216 	return ret;
217 }
218 
219 static int epping_set_mac_address(struct net_device *dev, void *addr)
220 {
221 	epping_adapter_t *adapter = netdev_priv(dev);
222 	struct sockaddr *psta_mac_addr = addr;
223 	qdf_mem_copy(&adapter->macAddressCurrent,
224 		     psta_mac_addr->sa_data, ETH_ALEN);
225 	qdf_net_update_net_device_dev_addr(dev, psta_mac_addr->sa_data,
226 					   ETH_ALEN);
227 	return 0;
228 }
229 
230 static void epping_stop_adapter(epping_adapter_t *adapter)
231 {
232 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
233 
234 	if (!qdf_ctx) {
235 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
236 			   "%s: qdf_ctx is NULL\n", __func__);
237 		return;
238 	}
239 
240 	if (adapter && adapter->started) {
241 		EPPING_LOG(LOG1, FL("Disabling queues"));
242 		netif_tx_disable(adapter->dev);
243 		netif_carrier_off(adapter->dev);
244 		adapter->started = false;
245 		pld_request_bus_bandwidth(qdf_ctx->dev,
246 					  PLD_BUS_WIDTH_LOW);
247 	}
248 }
249 
250 static int epping_start_adapter(epping_adapter_t *adapter)
251 {
252 	qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
253 
254 	if (!qdf_ctx) {
255 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
256 			   "%s: qdf_ctx is NULL", __func__);
257 		return -EINVAL;
258 	}
259 
260 	if (!adapter) {
261 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
262 			   "%s: adapter= NULL\n", __func__);
263 		return -EINVAL;
264 	}
265 	if (!adapter->started) {
266 		pld_request_bus_bandwidth(qdf_ctx->dev,
267 					  PLD_BUS_WIDTH_HIGH);
268 		netif_carrier_on(adapter->dev);
269 		EPPING_LOG(LOG1, FL("Enabling queues"));
270 		netif_tx_start_all_queues(adapter->dev);
271 		adapter->started = true;
272 	} else {
273 		EPPING_LOG(QDF_TRACE_LEVEL_WARN,
274 			   "%s: adapter %pK already started\n", __func__,
275 			   adapter);
276 	}
277 	return 0;
278 }
279 
280 static int epping_register_adapter(epping_adapter_t *adapter, bool rtnl_held)
281 {
282 	int ret = 0;
283 
284 	if (!rtnl_held)
285 		ret = register_netdev(adapter->dev);
286 	else
287 		ret = register_netdevice(adapter->dev);
288 	if (ret != 0) {
289 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
290 			   "%s: unable to register device\n",
291 			   adapter->dev->name);
292 	} else {
293 		adapter->registered = true;
294 	}
295 	return ret;
296 }
297 
298 static void epping_unregister_adapter(epping_adapter_t *adapter)
299 {
300 	if (adapter) {
301 		epping_stop_adapter(adapter);
302 		if (adapter->registered) {
303 			unregister_netdev(adapter->dev);
304 			adapter->registered = false;
305 		}
306 	} else {
307 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
308 			   "%s: adapter = NULL, unable to unregister device\n",
309 			   __func__);
310 	}
311 }
312 
313 void epping_destroy_adapter(epping_adapter_t *adapter)
314 {
315 	struct net_device *dev = NULL;
316 	epping_context_t *pEpping_ctx;
317 
318 	if (!adapter || !adapter->pEpping_ctx) {
319 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
320 			   "%s: adapter = NULL\n", __func__);
321 		return;
322 	}
323 
324 	dev = adapter->dev;
325 	pEpping_ctx = adapter->pEpping_ctx;
326 	epping_unregister_adapter(adapter);
327 
328 	qdf_spinlock_destroy(&adapter->data_lock);
329 	qdf_timer_free(&adapter->epping_timer);
330 	adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
331 
332 	while (qdf_nbuf_queue_len(&adapter->nodrop_queue)) {
333 		qdf_nbuf_t tmp_nbuf = NULL;
334 		tmp_nbuf = qdf_nbuf_queue_remove(&adapter->nodrop_queue);
335 		if (tmp_nbuf)
336 			qdf_nbuf_free(tmp_nbuf);
337 	}
338 
339 	free_netdev(dev);
340 	if (!pEpping_ctx)
341 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
342 			   "%s: pEpping_ctx = NULL\n", __func__);
343 	else
344 		pEpping_ctx->epping_adapter = NULL;
345 }
346 
347 static struct net_device_ops epping_drv_ops = {
348 	.ndo_open = epping_ndev_open,
349 	.ndo_stop = epping_ndev_stop,
350 	.ndo_uninit = epping_ndev_uninit,
351 	.ndo_start_xmit = epping_hard_start_xmit,
352 	.ndo_tx_timeout = epping_tx_queue_timeout,
353 	.ndo_get_stats = epping_get_stats,
354 	.ndo_do_ioctl = epping_ndev_ioctl,
355 	.ndo_set_mac_address = epping_set_mac_address,
356 	.ndo_select_queue = NULL,
357 };
358 
359 #define EPPING_TX_QUEUE_MAX_LEN 128     /* need to be power of 2 */
360 
361 epping_adapter_t *epping_add_adapter(epping_context_t *pEpping_ctx,
362 				     tSirMacAddr macAddr,
363 				     enum QDF_OPMODE device_mode,
364 				     bool rtnl_held)
365 {
366 	struct net_device *dev;
367 	epping_adapter_t *adapter;
368 
369 	dev = alloc_netdev(sizeof(epping_adapter_t), "wifi%d",
370 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
371 			   NET_NAME_UNKNOWN,
372 #endif
373 			   ether_setup);
374 	if (!dev) {
375 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
376 			   "%s: Cannot allocate epping_adapter_t\n", __func__);
377 		return NULL;
378 	}
379 
380 	adapter = netdev_priv(dev);
381 	qdf_mem_zero(adapter, sizeof(*adapter));
382 	adapter->dev = dev;
383 	adapter->pEpping_ctx = pEpping_ctx;
384 	adapter->device_mode = device_mode;    /* station, SAP, etc */
385 	qdf_net_update_net_device_dev_addr(dev,
386 					   (void *)macAddr,
387 					   sizeof(tSirMacAddr));
388 	qdf_mem_copy(adapter->macAddressCurrent.bytes,
389 		     macAddr, sizeof(tSirMacAddr));
390 	qdf_spinlock_create(&adapter->data_lock);
391 	qdf_nbuf_queue_init(&adapter->nodrop_queue);
392 	adapter->epping_timer_state = EPPING_TX_TIMER_STOPPED;
393 	qdf_timer_init(epping_get_qdf_ctx(), &adapter->epping_timer,
394 		epping_timer_expire, dev, QDF_TIMER_TYPE_SW);
395 	dev->type = ARPHRD_IEEE80211;
396 	dev->needed_headroom += 24;
397 	dev->netdev_ops = &epping_drv_ops;
398 	dev->watchdog_timeo = 5 * HZ;   /* XXX */
399 	dev->tx_queue_len = EPPING_TXBUF - 1;      /* 1 for mgmt frame */
400 	if (epping_register_adapter(adapter, rtnl_held) == 0) {
401 		EPPING_LOG(LOG1, FL("Disabling queues"));
402 		netif_tx_disable(dev);
403 		netif_carrier_off(dev);
404 		return adapter;
405 	} else {
406 		epping_destroy_adapter(adapter);
407 		return NULL;
408 	}
409 }
410 
411 int epping_connect_service(epping_context_t *pEpping_ctx)
412 {
413 	int status, i;
414 	struct htc_service_connect_req connect;
415 	struct htc_service_connect_resp response;
416 
417 	qdf_mem_zero(&connect, sizeof(connect));
418 	qdf_mem_zero(&response, sizeof(response));
419 
420 	/* these fields are the same for all service endpoints */
421 	connect.EpCallbacks.pContext = pEpping_ctx;
422 	connect.EpCallbacks.EpTxCompleteMultiple = NULL;
423 	connect.EpCallbacks.EpRecv = epping_rx;
424 	/* epping_tx_complete use Multiple version */
425 	connect.EpCallbacks.EpTxComplete  = epping_tx_complete;
426 	connect.MaxSendQueueDepth = 64;
427 
428 #ifdef HIF_SDIO
429 	connect.EpCallbacks.EpRecvRefill = epping_refill;
430 	connect.EpCallbacks.EpSendFull =
431 		epping_tx_queue_full /* ar6000_tx_queue_full */;
432 #elif defined(HIF_USB) || defined(HIF_PCI) || defined(HIF_SNOC) || \
433       defined(HIF_IPCI)
434 	connect.EpCallbacks.EpRecvRefill = NULL /* provided by HIF */;
435 	connect.EpCallbacks.EpSendFull = NULL /* provided by HIF */;
436 	/* disable flow control for hw flow control */
437 	connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
438 #endif
439 
440 	/* connect to service */
441 	connect.service_id = WMI_DATA_BE_SVC;
442 	status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response);
443 	if (QDF_IS_STATUS_ERROR(status)) {
444 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
445 			   "Failed to connect to Endpoint Ping BE service status:%d\n",
446 			   status);
447 		return status;
448 	} else {
449 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
450 			   "eppingtest BE endpoint:%d\n", response.Endpoint);
451 	}
452 	pEpping_ctx->EppingEndpoint[0] = response.Endpoint;
453 
454 #if defined(HIF_PCI) || defined(HIF_USB) || defined(HIF_SNOC) || \
455     defined(HIF_IPCI)
456 	connect.service_id = WMI_DATA_BK_SVC;
457 	status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response);
458 	if (QDF_IS_STATUS_ERROR(status)) {
459 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
460 			   "Failed to connect to Endpoint Ping BK service status:%d\n",
461 			   status);
462 		return status;
463 	} else {
464 		EPPING_LOG(QDF_TRACE_LEVEL_FATAL,
465 			   "eppingtest BK endpoint:%d\n", response.Endpoint);
466 	}
467 	pEpping_ctx->EppingEndpoint[1] = response.Endpoint;
468 	/* Since we do not create other two SVC use BK endpoint
469 	 * for rest ACs (2, 3) */
470 	for (i = 2; i < EPPING_MAX_NUM_EPIDS; i++) {
471 		pEpping_ctx->EppingEndpoint[i] = response.Endpoint;
472 	}
473 #else
474 	/* we only use one endpoint for high latenance bus.
475 	 * Map all AC's EPIDs to the same endpoint ID returned by HTC */
476 	for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) {
477 		pEpping_ctx->EppingEndpoint[i] = response.Endpoint;
478 	}
479 #endif
480 	return 0;
481 }
482