wil6210: fix race condition between BACK event and Rx data
[deliverable/linux.git] / drivers / net / wireless / ath / wil6210 / main.c
1 /*
2 * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <linux/moduleparam.h>
18 #include <linux/if_arp.h>
19 #include <linux/etherdevice.h>
20
21 #include "wil6210.h"
22 #include "txrx.h"
23 #include "wmi.h"
24
25 #define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
26 #define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
27
28 static bool no_fw_recovery;
29 module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
30 MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
31
32 static bool no_fw_load = true;
33 module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
34 MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
35
36 #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
37 #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
38
39 /*
40 * Due to a hardware issue,
41 * one has to read/write to/from NIC in 32-bit chunks;
42 * regular memcpy_fromio and siblings will
43 * not work on 64-bit platform - it uses 64-bit transactions
44 *
45 * Force 32-bit transactions to enable NIC on 64-bit platforms
46 *
47 * To avoid byte swap on big endian host, __raw_{read|write}l
48 * should be used - {read|write}l would swap bytes to provide
49 * little endian on PCI value in host endianness.
50 */
51 void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
52 size_t count)
53 {
54 u32 *d = dst;
55 const volatile u32 __iomem *s = src;
56
57 /* size_t is unsigned, if (count%4 != 0) it will wrap */
58 for (count += 4; count > 4; count -= 4)
59 *d++ = __raw_readl(s++);
60 }
61
62 void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
63 size_t count)
64 {
65 volatile u32 __iomem *d = dst;
66 const u32 *s = src;
67
68 for (count += 4; count > 4; count -= 4)
69 __raw_writel(*s++, d++);
70 }
71
72 static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
73 {
74 uint i;
75 struct net_device *ndev = wil_to_ndev(wil);
76 struct wireless_dev *wdev = wil->wdev;
77 struct wil_sta_info *sta = &wil->sta[cid];
78
79 wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
80 sta->status);
81
82 sta->data_port_open = false;
83 if (sta->status != wil_sta_unused) {
84 wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
85 switch (wdev->iftype) {
86 case NL80211_IFTYPE_AP:
87 case NL80211_IFTYPE_P2P_GO:
88 /* AP-like interface */
89 cfg80211_del_sta(ndev, sta->addr, GFP_KERNEL);
90 break;
91 default:
92 break;
93 }
94 sta->status = wil_sta_unused;
95 }
96
97 for (i = 0; i < WIL_STA_TID_NUM; i++) {
98 struct wil_tid_ampdu_rx *r;
99 unsigned long flags;
100
101 spin_lock_irqsave(&sta->tid_rx_lock, flags);
102
103 r = sta->tid_rx[i];
104 sta->tid_rx[i] = NULL;
105 wil_tid_ampdu_rx_free(wil, r);
106
107 spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
108 }
109 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
110 if (wil->vring2cid_tid[i][0] == cid)
111 wil_vring_fini_tx(wil, i);
112 }
113 memset(&sta->stats, 0, sizeof(sta->stats));
114 }
115
116 static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
117 {
118 int cid = -ENOENT;
119 struct net_device *ndev = wil_to_ndev(wil);
120 struct wireless_dev *wdev = wil->wdev;
121
122 might_sleep();
123 if (bssid) {
124 cid = wil_find_cid(wil, bssid);
125 wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
126 } else {
127 wil_dbg_misc(wil, "%s(all)\n", __func__);
128 }
129
130 if (cid >= 0) /* disconnect 1 peer */
131 wil_disconnect_cid(wil, cid);
132 else /* disconnect all */
133 for (cid = 0; cid < WIL6210_MAX_CID; cid++)
134 wil_disconnect_cid(wil, cid);
135
136 /* link state */
137 switch (wdev->iftype) {
138 case NL80211_IFTYPE_STATION:
139 case NL80211_IFTYPE_P2P_CLIENT:
140 wil_link_off(wil);
141 if (test_bit(wil_status_fwconnected, &wil->status)) {
142 clear_bit(wil_status_fwconnected, &wil->status);
143 cfg80211_disconnected(ndev,
144 WLAN_STATUS_UNSPECIFIED_FAILURE,
145 NULL, 0, GFP_KERNEL);
146 } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
147 cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
148 WLAN_STATUS_UNSPECIFIED_FAILURE,
149 GFP_KERNEL);
150 }
151 clear_bit(wil_status_fwconnecting, &wil->status);
152 break;
153 default:
154 break;
155 }
156 }
157
158 static void wil_disconnect_worker(struct work_struct *work)
159 {
160 struct wil6210_priv *wil = container_of(work,
161 struct wil6210_priv, disconnect_worker);
162
163 mutex_lock(&wil->mutex);
164 _wil6210_disconnect(wil, NULL);
165 mutex_unlock(&wil->mutex);
166 }
167
168 static void wil_connect_timer_fn(ulong x)
169 {
170 struct wil6210_priv *wil = (void *)x;
171
172 wil_dbg_misc(wil, "Connect timeout\n");
173
174 /* reschedule to thread context - disconnect won't
175 * run from atomic context
176 */
177 schedule_work(&wil->disconnect_worker);
178 }
179
180 static void wil_scan_timer_fn(ulong x)
181 {
182 struct wil6210_priv *wil = (void *)x;
183
184 clear_bit(wil_status_fwready, &wil->status);
185 wil_err(wil, "Scan timeout detected, start fw error recovery\n");
186 schedule_work(&wil->fw_error_worker);
187 }
188
189 static void wil_fw_error_worker(struct work_struct *work)
190 {
191 struct wil6210_priv *wil = container_of(work,
192 struct wil6210_priv, fw_error_worker);
193 struct wireless_dev *wdev = wil->wdev;
194
195 wil_dbg_misc(wil, "fw error worker\n");
196
197 if (no_fw_recovery)
198 return;
199
200 /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
201 * passed since last recovery attempt
202 */
203 if (time_is_after_jiffies(wil->last_fw_recovery +
204 WIL6210_FW_RECOVERY_TO))
205 wil->recovery_count++;
206 else
207 wil->recovery_count = 1; /* fw was alive for a long time */
208
209 if (wil->recovery_count > WIL6210_FW_RECOVERY_RETRIES) {
210 wil_err(wil, "too many recovery attempts (%d), giving up\n",
211 wil->recovery_count);
212 return;
213 }
214
215 wil->last_fw_recovery = jiffies;
216
217 mutex_lock(&wil->mutex);
218 switch (wdev->iftype) {
219 case NL80211_IFTYPE_STATION:
220 case NL80211_IFTYPE_P2P_CLIENT:
221 case NL80211_IFTYPE_MONITOR:
222 wil_info(wil, "fw error recovery started (try %d)...\n",
223 wil->recovery_count);
224 wil_reset(wil);
225
226 /* need to re-allocate Rx ring after reset */
227 wil_rx_init(wil);
228 break;
229 case NL80211_IFTYPE_AP:
230 case NL80211_IFTYPE_P2P_GO:
231 /* recovery in these modes is done by upper layers */
232 break;
233 default:
234 break;
235 }
236 mutex_unlock(&wil->mutex);
237 }
238
239 static int wil_find_free_vring(struct wil6210_priv *wil)
240 {
241 int i;
242
243 for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
244 if (!wil->vring_tx[i].va)
245 return i;
246 }
247 return -EINVAL;
248 }
249
250 static void wil_connect_worker(struct work_struct *work)
251 {
252 int rc;
253 struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
254 connect_worker);
255 int cid = wil->pending_connect_cid;
256 int ringid = wil_find_free_vring(wil);
257
258 if (cid < 0) {
259 wil_err(wil, "No connection pending\n");
260 return;
261 }
262
263 wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
264
265 rc = wil_vring_init_tx(wil, ringid, WIL6210_TX_RING_SIZE, cid, 0);
266 wil->pending_connect_cid = -1;
267 if (rc == 0) {
268 wil->sta[cid].status = wil_sta_connected;
269 wil_link_on(wil);
270 } else {
271 wil->sta[cid].status = wil_sta_unused;
272 }
273 }
274
275 int wil_priv_init(struct wil6210_priv *wil)
276 {
277 uint i;
278
279 wil_dbg_misc(wil, "%s()\n", __func__);
280
281 memset(wil->sta, 0, sizeof(wil->sta));
282 for (i = 0; i < WIL6210_MAX_CID; i++)
283 spin_lock_init(&wil->sta[i].tid_rx_lock);
284
285 mutex_init(&wil->mutex);
286 mutex_init(&wil->wmi_mutex);
287
288 init_completion(&wil->wmi_ready);
289
290 wil->pending_connect_cid = -1;
291 setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
292 setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
293
294 INIT_WORK(&wil->connect_worker, wil_connect_worker);
295 INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
296 INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
297 INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
298
299 INIT_LIST_HEAD(&wil->pending_wmi_ev);
300 spin_lock_init(&wil->wmi_ev_lock);
301
302 wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
303 if (!wil->wmi_wq)
304 return -EAGAIN;
305
306 wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
307 if (!wil->wmi_wq_conn) {
308 destroy_workqueue(wil->wmi_wq);
309 return -EAGAIN;
310 }
311
312 wil->last_fw_recovery = jiffies;
313
314 return 0;
315 }
316
317 void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
318 {
319 wil_dbg_misc(wil, "%s()\n", __func__);
320
321 del_timer_sync(&wil->connect_timer);
322 _wil6210_disconnect(wil, bssid);
323 }
324
325 void wil_priv_deinit(struct wil6210_priv *wil)
326 {
327 wil_dbg_misc(wil, "%s()\n", __func__);
328
329 del_timer_sync(&wil->scan_timer);
330 cancel_work_sync(&wil->disconnect_worker);
331 cancel_work_sync(&wil->fw_error_worker);
332 mutex_lock(&wil->mutex);
333 wil6210_disconnect(wil, NULL);
334 mutex_unlock(&wil->mutex);
335 wmi_event_flush(wil);
336 destroy_workqueue(wil->wmi_wq_conn);
337 destroy_workqueue(wil->wmi_wq);
338 }
339
340 /* target operations */
341 /* register read */
342 #define R(a) ioread32(wil->csr + HOSTADDR(a))
343 /* register write. wmb() to make sure it is completed */
344 #define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
345 /* register set = read, OR, write */
346 #define S(a, v) W(a, R(a) | v)
347 /* register clear = read, AND with inverted, write */
348 #define C(a, v) W(a, R(a) & ~v)
349
350 static inline void wil_halt_cpu(struct wil6210_priv *wil)
351 {
352 W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
353 W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST);
354 }
355
356 static inline void wil_release_cpu(struct wil6210_priv *wil)
357 {
358 /* Start CPU */
359 W(RGF_USER_USER_CPU_0, 1);
360 }
361
362 static int wil_target_reset(struct wil6210_priv *wil)
363 {
364 int delay = 0;
365 u32 hw_state;
366 u32 rev_id;
367 bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
368
369 wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
370
371 wil->hw_version = R(RGF_USER_FW_REV_ID);
372 rev_id = wil->hw_version & 0xff;
373
374 /* Clear MAC link up */
375 S(RGF_HP_CTRL, BIT(15));
376 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD);
377 S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
378
379 wil_halt_cpu(wil);
380 C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
381
382 if (is_sparrow) {
383 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
384 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
385 }
386
387 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
388 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
389 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
390 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
391
392 if (is_sparrow) {
393 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
394 W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
395 }
396
397 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
398 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
399 W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
400 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
401
402 if (is_sparrow) {
403 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
404 /* reset A2 PCIE AHB */
405 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
406 } else {
407 W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
408 if (rev_id == 1) {
409 /* reset A1 BOTH PCIE AHB & PCIE RGF */
410 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
411 } else {
412 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
413 W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
414 }
415 }
416
417 /* TODO: check order here!!! Erez code is different */
418 W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
419
420 /* wait until device ready. typical time is 200..250 msec */
421 do {
422 msleep(RST_DELAY);
423 hw_state = R(RGF_USER_HW_MACHINE_STATE);
424 if (delay++ > RST_COUNT) {
425 wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
426 hw_state);
427 return -ETIME;
428 }
429 } while (hw_state != HW_MACHINE_BOOT_DONE);
430
431 /* TODO: Erez check rev_id != 1 */
432 if (!is_sparrow && (rev_id != 1))
433 W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
434
435 C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
436
437 wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
438 return 0;
439 }
440
441 #undef R
442 #undef W
443 #undef S
444 #undef C
445
446 void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
447 {
448 le32_to_cpus(&r->base);
449 le16_to_cpus(&r->entry_size);
450 le16_to_cpus(&r->size);
451 le32_to_cpus(&r->tail);
452 le32_to_cpus(&r->head);
453 }
454
455 static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
456 {
457 ulong to = msecs_to_jiffies(1000);
458 ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
459
460 if (0 == left) {
461 wil_err(wil, "Firmware not ready\n");
462 return -ETIME;
463 } else {
464 wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n",
465 jiffies_to_msecs(to-left), wil->hw_version);
466 }
467 return 0;
468 }
469
470 /*
471 * We reset all the structures, and we reset the UMAC.
472 * After calling this routine, you're expected to reload
473 * the firmware.
474 */
475 int wil_reset(struct wil6210_priv *wil)
476 {
477 int rc;
478
479 wil_dbg_misc(wil, "%s()\n", __func__);
480
481 WARN_ON(!mutex_is_locked(&wil->mutex));
482
483 cancel_work_sync(&wil->disconnect_worker);
484 wil6210_disconnect(wil, NULL);
485
486 wil->status = 0; /* prevent NAPI from being scheduled */
487 if (test_bit(wil_status_napi_en, &wil->status))
488 napi_synchronize(&wil->napi_rx);
489
490 if (wil->scan_request) {
491 wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
492 wil->scan_request);
493 del_timer_sync(&wil->scan_timer);
494 cfg80211_scan_done(wil->scan_request, true);
495 wil->scan_request = NULL;
496 }
497
498 wil6210_disable_irq(wil);
499
500 wmi_event_flush(wil);
501
502 flush_workqueue(wil->wmi_wq_conn);
503 flush_workqueue(wil->wmi_wq);
504
505 rc = wil_target_reset(wil);
506 wil_rx_fini(wil);
507 if (rc)
508 return rc;
509
510 if (!no_fw_load) {
511 wil_info(wil, "Use firmware <%s>\n", WIL_FW_NAME);
512 wil_halt_cpu(wil);
513 /* Loading f/w from the file */
514 rc = wil_request_firmware(wil, WIL_FW_NAME);
515 if (rc)
516 return rc;
517
518 /* clear any interrupts which on-card-firmware may have set */
519 wil6210_clear_irq(wil);
520 { /* CAF_ICR - clear and mask */
521 u32 a = HOSTADDR(RGF_CAF_ICR) +
522 offsetof(struct RGF_ICR, ICR);
523 u32 m = HOSTADDR(RGF_CAF_ICR) +
524 offsetof(struct RGF_ICR, IMV);
525 u32 icr = ioread32(wil->csr + a);
526
527 iowrite32(icr, wil->csr + a); /* W1C */
528 iowrite32(~0, wil->csr + m);
529 wmb(); /* wait for completion */
530 }
531 wil_release_cpu(wil);
532 } else {
533 wil_info(wil, "Use firmware from on-card flash\n");
534 }
535
536 /* init after reset */
537 wil->pending_connect_cid = -1;
538 reinit_completion(&wil->wmi_ready);
539
540 wil6210_enable_irq(wil);
541
542 /* we just started MAC, wait for FW ready */
543 rc = wil_wait_for_fw_ready(wil);
544
545 return rc;
546 }
547
548 void wil_fw_error_recovery(struct wil6210_priv *wil)
549 {
550 wil_dbg_misc(wil, "starting fw error recovery\n");
551 schedule_work(&wil->fw_error_worker);
552 }
553
554 void wil_link_on(struct wil6210_priv *wil)
555 {
556 struct net_device *ndev = wil_to_ndev(wil);
557
558 wil_dbg_misc(wil, "%s()\n", __func__);
559
560 netif_carrier_on(ndev);
561 wil_dbg_misc(wil, "netif_tx_wake : link on\n");
562 netif_tx_wake_all_queues(ndev);
563 }
564
565 void wil_link_off(struct wil6210_priv *wil)
566 {
567 struct net_device *ndev = wil_to_ndev(wil);
568
569 wil_dbg_misc(wil, "%s()\n", __func__);
570
571 netif_tx_stop_all_queues(ndev);
572 wil_dbg_misc(wil, "netif_tx_stop : link off\n");
573 netif_carrier_off(ndev);
574 }
575
576 static int __wil_up(struct wil6210_priv *wil)
577 {
578 struct net_device *ndev = wil_to_ndev(wil);
579 struct wireless_dev *wdev = wil->wdev;
580 int rc;
581
582 WARN_ON(!mutex_is_locked(&wil->mutex));
583
584 rc = wil_reset(wil);
585 if (rc)
586 return rc;
587
588 /* Rx VRING. After MAC and beacon */
589 rc = wil_rx_init(wil);
590 if (rc)
591 return rc;
592
593 switch (wdev->iftype) {
594 case NL80211_IFTYPE_STATION:
595 wil_dbg_misc(wil, "type: STATION\n");
596 ndev->type = ARPHRD_ETHER;
597 break;
598 case NL80211_IFTYPE_AP:
599 wil_dbg_misc(wil, "type: AP\n");
600 ndev->type = ARPHRD_ETHER;
601 break;
602 case NL80211_IFTYPE_P2P_CLIENT:
603 wil_dbg_misc(wil, "type: P2P_CLIENT\n");
604 ndev->type = ARPHRD_ETHER;
605 break;
606 case NL80211_IFTYPE_P2P_GO:
607 wil_dbg_misc(wil, "type: P2P_GO\n");
608 ndev->type = ARPHRD_ETHER;
609 break;
610 case NL80211_IFTYPE_MONITOR:
611 wil_dbg_misc(wil, "type: Monitor\n");
612 ndev->type = ARPHRD_IEEE80211_RADIOTAP;
613 /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
614 break;
615 default:
616 return -EOPNOTSUPP;
617 }
618
619 /* MAC address - pre-requisite for other commands */
620 wmi_set_mac_address(wil, ndev->dev_addr);
621
622
623 napi_enable(&wil->napi_rx);
624 napi_enable(&wil->napi_tx);
625 set_bit(wil_status_napi_en, &wil->status);
626
627 if (wil->platform_ops.bus_request)
628 wil->platform_ops.bus_request(wil->platform_handle,
629 WIL_MAX_BUS_REQUEST_KBPS);
630
631 return 0;
632 }
633
634 int wil_up(struct wil6210_priv *wil)
635 {
636 int rc;
637
638 wil_dbg_misc(wil, "%s()\n", __func__);
639
640 mutex_lock(&wil->mutex);
641 rc = __wil_up(wil);
642 mutex_unlock(&wil->mutex);
643
644 return rc;
645 }
646
647 static int __wil_down(struct wil6210_priv *wil)
648 {
649 int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
650 WAIT_FOR_DISCONNECT_INTERVAL_MS;
651
652 WARN_ON(!mutex_is_locked(&wil->mutex));
653
654 if (wil->platform_ops.bus_request)
655 wil->platform_ops.bus_request(wil->platform_handle, 0);
656
657 clear_bit(wil_status_napi_en, &wil->status);
658 napi_disable(&wil->napi_rx);
659 napi_disable(&wil->napi_tx);
660
661 if (wil->scan_request) {
662 wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
663 wil->scan_request);
664 del_timer_sync(&wil->scan_timer);
665 cfg80211_scan_done(wil->scan_request, true);
666 wil->scan_request = NULL;
667 }
668
669 if (test_bit(wil_status_fwconnected, &wil->status) ||
670 test_bit(wil_status_fwconnecting, &wil->status))
671 wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
672
673 /* make sure wil is idle (not connected) */
674 mutex_unlock(&wil->mutex);
675 while (iter--) {
676 int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
677 !test_bit(wil_status_fwconnecting, &wil->status);
678 if (idle)
679 break;
680 msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
681 }
682 mutex_lock(&wil->mutex);
683
684 if (!iter)
685 wil_err(wil, "timeout waiting for idle FW/HW\n");
686
687 wil_rx_fini(wil);
688
689 return 0;
690 }
691
692 int wil_down(struct wil6210_priv *wil)
693 {
694 int rc;
695
696 wil_dbg_misc(wil, "%s()\n", __func__);
697
698 mutex_lock(&wil->mutex);
699 rc = __wil_down(wil);
700 mutex_unlock(&wil->mutex);
701
702 return rc;
703 }
704
705 int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
706 {
707 int i;
708 int rc = -ENOENT;
709
710 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
711 if ((wil->sta[i].status != wil_sta_unused) &&
712 ether_addr_equal(wil->sta[i].addr, mac)) {
713 rc = i;
714 break;
715 }
716 }
717
718 return rc;
719 }
This page took 0.044696 seconds and 5 git commands to generate.