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