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