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