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