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
epping_timer_expire(void * data)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
epping_ndev_open(struct net_device * dev)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
epping_ndev_stop(struct net_device * dev)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
epping_ndev_uninit(struct net_device * dev)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))
epping_tx_queue_timeout(struct net_device * dev,unsigned int txqueue)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
epping_hard_start_xmit(struct sk_buff * skb,struct net_device * dev)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
epping_get_stats(struct net_device * dev)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
epping_ndev_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)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
epping_set_mac_address(struct net_device * dev,void * addr)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
epping_stop_adapter(epping_adapter_t * adapter)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
epping_start_adapter(epping_adapter_t * adapter)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
epping_register_adapter(epping_adapter_t * adapter,bool rtnl_held)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
epping_unregister_adapter(epping_adapter_t * adapter)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
epping_destroy_adapter(epping_adapter_t * adapter)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
epping_add_adapter(epping_context_t * pEpping_ctx,tSirMacAddr macAddr,enum QDF_OPMODE device_mode,bool rtnl_held)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
epping_connect_service(epping_context_t * pEpping_ctx)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