| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: ISC |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. |
|---|
| 3 | | - * Copyright (c) 2018, The Linux Foundation. All rights reserved. |
|---|
| 4 | | - * |
|---|
| 5 | | - * Permission to use, copy, modify, and/or distribute this software for any |
|---|
| 6 | | - * purpose with or without fee is hereby granted, provided that the above |
|---|
| 7 | | - * copyright notice and this permission notice appear in all copies. |
|---|
| 8 | | - * |
|---|
| 9 | | - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|---|
| 10 | | - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|---|
| 11 | | - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|---|
| 12 | | - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|---|
| 13 | | - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|---|
| 14 | | - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|---|
| 15 | | - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|---|
| 4 | + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. |
|---|
| 16 | 5 | */ |
|---|
| 17 | 6 | |
|---|
| 18 | 7 | #include <linux/moduleparam.h> |
|---|
| 19 | 8 | #include <linux/if_arp.h> |
|---|
| 20 | 9 | #include <linux/etherdevice.h> |
|---|
| 10 | +#include <linux/rtnetlink.h> |
|---|
| 21 | 11 | |
|---|
| 22 | 12 | #include "wil6210.h" |
|---|
| 23 | 13 | #include "txrx.h" |
|---|
| .. | .. |
|---|
| 80 | 70 | module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444); |
|---|
| 81 | 71 | MODULE_PARM_DESC(mtu_max, " Max MTU value."); |
|---|
| 82 | 72 | |
|---|
| 83 | | -static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; |
|---|
| 73 | +static uint rx_ring_order; |
|---|
| 84 | 74 | static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; |
|---|
| 85 | 75 | static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; |
|---|
| 86 | 76 | |
|---|
| .. | .. |
|---|
| 183 | 173 | } |
|---|
| 184 | 174 | } |
|---|
| 185 | 175 | |
|---|
| 176 | +/* Device memory access is prohibited while reset or suspend. |
|---|
| 177 | + * wil_mem_access_lock protects accessing device memory in these cases |
|---|
| 178 | + */ |
|---|
| 179 | +int wil_mem_access_lock(struct wil6210_priv *wil) |
|---|
| 180 | +{ |
|---|
| 181 | + if (!down_read_trylock(&wil->mem_lock)) |
|---|
| 182 | + return -EBUSY; |
|---|
| 183 | + |
|---|
| 184 | + if (test_bit(wil_status_suspending, wil->status) || |
|---|
| 185 | + test_bit(wil_status_suspended, wil->status)) { |
|---|
| 186 | + up_read(&wil->mem_lock); |
|---|
| 187 | + return -EBUSY; |
|---|
| 188 | + } |
|---|
| 189 | + |
|---|
| 190 | + return 0; |
|---|
| 191 | +} |
|---|
| 192 | + |
|---|
| 193 | +void wil_mem_access_unlock(struct wil6210_priv *wil) |
|---|
| 194 | +{ |
|---|
| 195 | + up_read(&wil->mem_lock); |
|---|
| 196 | +} |
|---|
| 197 | + |
|---|
| 186 | 198 | static void wil_ring_fini_tx(struct wil6210_priv *wil, int id) |
|---|
| 187 | 199 | { |
|---|
| 188 | 200 | struct wil_ring *ring = &wil->ring_tx[id]; |
|---|
| .. | .. |
|---|
| 214 | 226 | wil->txrx_ops.ring_fini_tx(wil, ring); |
|---|
| 215 | 227 | } |
|---|
| 216 | 228 | |
|---|
| 217 | | -static void wil_disconnect_cid(struct wil6210_vif *vif, int cid, |
|---|
| 218 | | - u16 reason_code, bool from_event) |
|---|
| 229 | +static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) |
|---|
| 230 | +{ |
|---|
| 231 | + int i; |
|---|
| 232 | + |
|---|
| 233 | + for (i = 0; i < wil->max_assoc_sta; i++) { |
|---|
| 234 | + if (wil->sta[i].mid == mid && |
|---|
| 235 | + wil->sta[i].status == wil_sta_connected) |
|---|
| 236 | + return true; |
|---|
| 237 | + } |
|---|
| 238 | + |
|---|
| 239 | + return false; |
|---|
| 240 | +} |
|---|
| 241 | + |
|---|
| 242 | +static void wil_disconnect_cid_complete(struct wil6210_vif *vif, int cid, |
|---|
| 243 | + u16 reason_code) |
|---|
| 219 | 244 | __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) |
|---|
| 220 | 245 | { |
|---|
| 221 | 246 | uint i; |
|---|
| .. | .. |
|---|
| 226 | 251 | int min_ring_id = wil_get_min_tx_ring_id(wil); |
|---|
| 227 | 252 | |
|---|
| 228 | 253 | might_sleep(); |
|---|
| 229 | | - wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n", |
|---|
| 254 | + wil_dbg_misc(wil, |
|---|
| 255 | + "disconnect_cid_complete: CID %d, MID %d, status %d\n", |
|---|
| 230 | 256 | cid, sta->mid, sta->status); |
|---|
| 231 | | - /* inform upper/lower layers */ |
|---|
| 257 | + /* inform upper layers */ |
|---|
| 232 | 258 | if (sta->status != wil_sta_unused) { |
|---|
| 233 | 259 | if (vif->mid != sta->mid) { |
|---|
| 234 | 260 | wil_err(wil, "STA MID mismatch with VIF MID(%d)\n", |
|---|
| 235 | 261 | vif->mid); |
|---|
| 236 | | - /* let FW override sta->mid but be more strict with |
|---|
| 237 | | - * user space requests |
|---|
| 238 | | - */ |
|---|
| 239 | | - if (!from_event) |
|---|
| 240 | | - return; |
|---|
| 241 | | - } |
|---|
| 242 | | - if (!from_event) { |
|---|
| 243 | | - bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ? |
|---|
| 244 | | - disable_ap_sme : false; |
|---|
| 245 | | - wmi_disconnect_sta(vif, sta->addr, reason_code, |
|---|
| 246 | | - true, del_sta); |
|---|
| 247 | 262 | } |
|---|
| 248 | 263 | |
|---|
| 249 | 264 | switch (wdev->iftype) { |
|---|
| .. | .. |
|---|
| 283 | 298 | sta->stats.tx_latency_min_us = U32_MAX; |
|---|
| 284 | 299 | } |
|---|
| 285 | 300 | |
|---|
| 286 | | -static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) |
|---|
| 287 | | -{ |
|---|
| 288 | | - int i; |
|---|
| 289 | | - |
|---|
| 290 | | - for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { |
|---|
| 291 | | - if (wil->sta[i].mid == mid && |
|---|
| 292 | | - wil->sta[i].status == wil_sta_connected) |
|---|
| 293 | | - return true; |
|---|
| 294 | | - } |
|---|
| 295 | | - |
|---|
| 296 | | - return false; |
|---|
| 297 | | -} |
|---|
| 298 | | - |
|---|
| 299 | | -static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, |
|---|
| 300 | | - u16 reason_code, bool from_event) |
|---|
| 301 | +static void _wil6210_disconnect_complete(struct wil6210_vif *vif, |
|---|
| 302 | + const u8 *bssid, u16 reason_code) |
|---|
| 301 | 303 | { |
|---|
| 302 | 304 | struct wil6210_priv *wil = vif_to_wil(vif); |
|---|
| 303 | 305 | int cid = -ENOENT; |
|---|
| 304 | 306 | struct net_device *ndev; |
|---|
| 305 | 307 | struct wireless_dev *wdev; |
|---|
| 306 | 308 | |
|---|
| 307 | | - if (unlikely(!vif)) |
|---|
| 308 | | - return; |
|---|
| 309 | | - |
|---|
| 310 | 309 | ndev = vif_to_ndev(vif); |
|---|
| 311 | 310 | wdev = vif_to_wdev(vif); |
|---|
| 312 | 311 | |
|---|
| 313 | 312 | might_sleep(); |
|---|
| 314 | | - wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid, |
|---|
| 315 | | - reason_code, from_event ? "+" : "-"); |
|---|
| 313 | + wil_info(wil, "disconnect_complete: bssid=%pM, reason=%d\n", |
|---|
| 314 | + bssid, reason_code); |
|---|
| 316 | 315 | |
|---|
| 317 | 316 | /* Cases are: |
|---|
| 318 | 317 | * - disconnect single STA, still connected |
|---|
| .. | .. |
|---|
| 327 | 326 | if (bssid && !is_broadcast_ether_addr(bssid) && |
|---|
| 328 | 327 | !ether_addr_equal_unaligned(ndev->dev_addr, bssid)) { |
|---|
| 329 | 328 | cid = wil_find_cid(wil, vif->mid, bssid); |
|---|
| 330 | | - wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", |
|---|
| 329 | + wil_dbg_misc(wil, |
|---|
| 330 | + "Disconnect complete %pM, CID=%d, reason=%d\n", |
|---|
| 331 | 331 | bssid, cid, reason_code); |
|---|
| 332 | | - if (cid >= 0) /* disconnect 1 peer */ |
|---|
| 333 | | - wil_disconnect_cid(vif, cid, reason_code, from_event); |
|---|
| 332 | + if (wil_cid_valid(wil, cid)) /* disconnect 1 peer */ |
|---|
| 333 | + wil_disconnect_cid_complete(vif, cid, reason_code); |
|---|
| 334 | 334 | } else { /* all */ |
|---|
| 335 | | - wil_dbg_misc(wil, "Disconnect all\n"); |
|---|
| 336 | | - for (cid = 0; cid < WIL6210_MAX_CID; cid++) |
|---|
| 337 | | - wil_disconnect_cid(vif, cid, reason_code, from_event); |
|---|
| 335 | + wil_dbg_misc(wil, "Disconnect complete all\n"); |
|---|
| 336 | + for (cid = 0; cid < wil->max_assoc_sta; cid++) |
|---|
| 337 | + wil_disconnect_cid_complete(vif, cid, reason_code); |
|---|
| 338 | 338 | } |
|---|
| 339 | 339 | |
|---|
| 340 | 340 | /* link state */ |
|---|
| .. | .. |
|---|
| 361 | 361 | vif->bss = NULL; |
|---|
| 362 | 362 | } |
|---|
| 363 | 363 | clear_bit(wil_vif_fwconnecting, vif->status); |
|---|
| 364 | + clear_bit(wil_vif_ft_roam, vif->status); |
|---|
| 365 | + vif->ptk_rekey_state = WIL_REKEY_IDLE; |
|---|
| 366 | + |
|---|
| 364 | 367 | break; |
|---|
| 365 | 368 | case NL80211_IFTYPE_AP: |
|---|
| 366 | 369 | case NL80211_IFTYPE_P2P_GO: |
|---|
| .. | .. |
|---|
| 376 | 379 | default: |
|---|
| 377 | 380 | break; |
|---|
| 378 | 381 | } |
|---|
| 382 | +} |
|---|
| 383 | + |
|---|
| 384 | +static int wil_disconnect_cid(struct wil6210_vif *vif, int cid, |
|---|
| 385 | + u16 reason_code) |
|---|
| 386 | +{ |
|---|
| 387 | + struct wil6210_priv *wil = vif_to_wil(vif); |
|---|
| 388 | + struct wireless_dev *wdev = vif_to_wdev(vif); |
|---|
| 389 | + struct wil_sta_info *sta = &wil->sta[cid]; |
|---|
| 390 | + bool del_sta = false; |
|---|
| 391 | + |
|---|
| 392 | + might_sleep(); |
|---|
| 393 | + wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n", |
|---|
| 394 | + cid, sta->mid, sta->status); |
|---|
| 395 | + |
|---|
| 396 | + if (sta->status == wil_sta_unused) |
|---|
| 397 | + return 0; |
|---|
| 398 | + |
|---|
| 399 | + if (vif->mid != sta->mid) { |
|---|
| 400 | + wil_err(wil, "STA MID mismatch with VIF MID(%d)\n", vif->mid); |
|---|
| 401 | + return -EINVAL; |
|---|
| 402 | + } |
|---|
| 403 | + |
|---|
| 404 | + /* inform lower layers */ |
|---|
| 405 | + if (wdev->iftype == NL80211_IFTYPE_AP && disable_ap_sme) |
|---|
| 406 | + del_sta = true; |
|---|
| 407 | + |
|---|
| 408 | + /* disconnect by sending command disconnect/del_sta and wait |
|---|
| 409 | + * synchronously for WMI_DISCONNECT_EVENTID event. |
|---|
| 410 | + */ |
|---|
| 411 | + return wmi_disconnect_sta(vif, sta->addr, reason_code, del_sta); |
|---|
| 412 | +} |
|---|
| 413 | + |
|---|
| 414 | +static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, |
|---|
| 415 | + u16 reason_code) |
|---|
| 416 | +{ |
|---|
| 417 | + struct wil6210_priv *wil; |
|---|
| 418 | + struct net_device *ndev; |
|---|
| 419 | + int cid = -ENOENT; |
|---|
| 420 | + |
|---|
| 421 | + if (unlikely(!vif)) |
|---|
| 422 | + return; |
|---|
| 423 | + |
|---|
| 424 | + wil = vif_to_wil(vif); |
|---|
| 425 | + ndev = vif_to_ndev(vif); |
|---|
| 426 | + |
|---|
| 427 | + might_sleep(); |
|---|
| 428 | + wil_info(wil, "disconnect bssid=%pM, reason=%d\n", bssid, reason_code); |
|---|
| 429 | + |
|---|
| 430 | + /* Cases are: |
|---|
| 431 | + * - disconnect single STA, still connected |
|---|
| 432 | + * - disconnect single STA, already disconnected |
|---|
| 433 | + * - disconnect all |
|---|
| 434 | + * |
|---|
| 435 | + * For "disconnect all", there are 3 options: |
|---|
| 436 | + * - bssid == NULL |
|---|
| 437 | + * - bssid is broadcast address (ff:ff:ff:ff:ff:ff) |
|---|
| 438 | + * - bssid is our MAC address |
|---|
| 439 | + */ |
|---|
| 440 | + if (bssid && !is_broadcast_ether_addr(bssid) && |
|---|
| 441 | + !ether_addr_equal_unaligned(ndev->dev_addr, bssid)) { |
|---|
| 442 | + cid = wil_find_cid(wil, vif->mid, bssid); |
|---|
| 443 | + wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", |
|---|
| 444 | + bssid, cid, reason_code); |
|---|
| 445 | + if (wil_cid_valid(wil, cid)) /* disconnect 1 peer */ |
|---|
| 446 | + wil_disconnect_cid(vif, cid, reason_code); |
|---|
| 447 | + } else { /* all */ |
|---|
| 448 | + wil_dbg_misc(wil, "Disconnect all\n"); |
|---|
| 449 | + for (cid = 0; cid < wil->max_assoc_sta; cid++) |
|---|
| 450 | + wil_disconnect_cid(vif, cid, reason_code); |
|---|
| 451 | + } |
|---|
| 452 | + |
|---|
| 453 | + /* call event handler manually after processing wmi_call, |
|---|
| 454 | + * to avoid deadlock - disconnect event handler acquires |
|---|
| 455 | + * wil->mutex while it is already held here |
|---|
| 456 | + */ |
|---|
| 457 | + _wil6210_disconnect_complete(vif, bssid, reason_code); |
|---|
| 379 | 458 | } |
|---|
| 380 | 459 | |
|---|
| 381 | 460 | void wil_disconnect_worker(struct work_struct *work) |
|---|
| .. | .. |
|---|
| 483 | 562 | if (wil_wait_for_recovery(wil) != 0) |
|---|
| 484 | 563 | return; |
|---|
| 485 | 564 | |
|---|
| 565 | + rtnl_lock(); |
|---|
| 486 | 566 | mutex_lock(&wil->mutex); |
|---|
| 487 | 567 | /* Needs adaptation for multiple VIFs |
|---|
| 488 | 568 | * need to go over all VIFs and consider the appropriate |
|---|
| 489 | | - * recovery. |
|---|
| 569 | + * recovery because each one can have different iftype. |
|---|
| 490 | 570 | */ |
|---|
| 491 | 571 | switch (wdev->iftype) { |
|---|
| 492 | 572 | case NL80211_IFTYPE_STATION: |
|---|
| .. | .. |
|---|
| 498 | 578 | break; |
|---|
| 499 | 579 | case NL80211_IFTYPE_AP: |
|---|
| 500 | 580 | case NL80211_IFTYPE_P2P_GO: |
|---|
| 501 | | - wil_info(wil, "No recovery for AP-like interface\n"); |
|---|
| 502 | | - /* recovery in these modes is done by upper layers */ |
|---|
| 581 | + if (no_fw_recovery) /* upper layers do recovery */ |
|---|
| 582 | + break; |
|---|
| 583 | + /* silent recovery, upper layers will see disconnect */ |
|---|
| 584 | + __wil_down(wil); |
|---|
| 585 | + __wil_up(wil); |
|---|
| 586 | + mutex_unlock(&wil->mutex); |
|---|
| 587 | + wil_cfg80211_ap_recovery(wil); |
|---|
| 588 | + mutex_lock(&wil->mutex); |
|---|
| 589 | + wil_info(wil, "... completed\n"); |
|---|
| 503 | 590 | break; |
|---|
| 504 | 591 | default: |
|---|
| 505 | 592 | wil_err(wil, "No recovery - unknown interface type %d\n", |
|---|
| 506 | 593 | wdev->iftype); |
|---|
| 507 | 594 | break; |
|---|
| 508 | 595 | } |
|---|
| 596 | + |
|---|
| 509 | 597 | mutex_unlock(&wil->mutex); |
|---|
| 598 | + rtnl_unlock(); |
|---|
| 510 | 599 | } |
|---|
| 511 | 600 | |
|---|
| 512 | 601 | static int wil_find_free_ring(struct wil6210_priv *wil) |
|---|
| .. | .. |
|---|
| 586 | 675 | int i; |
|---|
| 587 | 676 | struct wil6210_vif *vif; |
|---|
| 588 | 677 | |
|---|
| 589 | | - for (i = 0; i < wil->max_vifs; i++) { |
|---|
| 678 | + for (i = 0; i < GET_MAX_VIFS(wil); i++) { |
|---|
| 590 | 679 | vif = wil->vifs[i]; |
|---|
| 591 | 680 | if (vif) |
|---|
| 592 | 681 | wil_bcast_fini(vif); |
|---|
| .. | .. |
|---|
| 625 | 714 | INIT_LIST_HEAD(&wil->pending_wmi_ev); |
|---|
| 626 | 715 | spin_lock_init(&wil->wmi_ev_lock); |
|---|
| 627 | 716 | spin_lock_init(&wil->net_queue_lock); |
|---|
| 717 | + spin_lock_init(&wil->eap_lock); |
|---|
| 718 | + |
|---|
| 628 | 719 | init_waitqueue_head(&wil->wq); |
|---|
| 720 | + init_rwsem(&wil->mem_lock); |
|---|
| 629 | 721 | |
|---|
| 630 | 722 | wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); |
|---|
| 631 | 723 | if (!wil->wmi_wq) |
|---|
| .. | .. |
|---|
| 653 | 745 | |
|---|
| 654 | 746 | wil->reply_mid = U8_MAX; |
|---|
| 655 | 747 | wil->max_vifs = 1; |
|---|
| 748 | + wil->max_assoc_sta = max_assoc_sta; |
|---|
| 656 | 749 | |
|---|
| 657 | 750 | /* edma configuration can be updated via debugfs before allocation */ |
|---|
| 658 | 751 | wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS; |
|---|
| .. | .. |
|---|
| 669 | 762 | */ |
|---|
| 670 | 763 | wil->rx_buff_id_count = WIL_RX_BUFF_ARR_SIZE_DEFAULT; |
|---|
| 671 | 764 | |
|---|
| 672 | | - wil->amsdu_en = 1; |
|---|
| 765 | + wil->amsdu_en = true; |
|---|
| 673 | 766 | |
|---|
| 674 | 767 | return 0; |
|---|
| 675 | 768 | |
|---|
| .. | .. |
|---|
| 692 | 785 | * @vif: virtual interface context |
|---|
| 693 | 786 | * @bssid: peer to disconnect, NULL to disconnect all |
|---|
| 694 | 787 | * @reason_code: Reason code for the Disassociation frame |
|---|
| 695 | | - * @from_event: whether is invoked from FW event handler |
|---|
| 696 | 788 | * |
|---|
| 697 | | - * Disconnect and release associated resources. If invoked not from the |
|---|
| 698 | | - * FW event handler, issue WMI command(s) to trigger MAC disconnect. |
|---|
| 789 | + * Disconnect and release associated resources. Issue WMI |
|---|
| 790 | + * command(s) to trigger MAC disconnect. When command was issued |
|---|
| 791 | + * successfully, call the wil6210_disconnect_complete function |
|---|
| 792 | + * to handle the event synchronously |
|---|
| 699 | 793 | */ |
|---|
| 700 | 794 | void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, |
|---|
| 701 | | - u16 reason_code, bool from_event) |
|---|
| 795 | + u16 reason_code) |
|---|
| 702 | 796 | { |
|---|
| 703 | 797 | struct wil6210_priv *wil = vif_to_wil(vif); |
|---|
| 704 | 798 | |
|---|
| 705 | | - wil_dbg_misc(wil, "disconnect\n"); |
|---|
| 799 | + wil_dbg_misc(wil, "disconnecting\n"); |
|---|
| 706 | 800 | |
|---|
| 707 | 801 | del_timer_sync(&vif->connect_timer); |
|---|
| 708 | | - _wil6210_disconnect(vif, bssid, reason_code, from_event); |
|---|
| 802 | + _wil6210_disconnect(vif, bssid, reason_code); |
|---|
| 803 | +} |
|---|
| 804 | + |
|---|
| 805 | +/** |
|---|
| 806 | + * wil6210_disconnect_complete - handle disconnect event |
|---|
| 807 | + * @vif: virtual interface context |
|---|
| 808 | + * @bssid: peer to disconnect, NULL to disconnect all |
|---|
| 809 | + * @reason_code: Reason code for the Disassociation frame |
|---|
| 810 | + * |
|---|
| 811 | + * Release associated resources and indicate upper layers the |
|---|
| 812 | + * connection is terminated. |
|---|
| 813 | + */ |
|---|
| 814 | +void wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid, |
|---|
| 815 | + u16 reason_code) |
|---|
| 816 | +{ |
|---|
| 817 | + struct wil6210_priv *wil = vif_to_wil(vif); |
|---|
| 818 | + |
|---|
| 819 | + wil_dbg_misc(wil, "got disconnect\n"); |
|---|
| 820 | + |
|---|
| 821 | + del_timer_sync(&vif->connect_timer); |
|---|
| 822 | + _wil6210_disconnect_complete(vif, bssid, reason_code); |
|---|
| 709 | 823 | } |
|---|
| 710 | 824 | |
|---|
| 711 | 825 | void wil_priv_deinit(struct wil6210_priv *wil) |
|---|
| .. | .. |
|---|
| 717 | 831 | wmi_event_flush(wil); |
|---|
| 718 | 832 | destroy_workqueue(wil->wq_service); |
|---|
| 719 | 833 | destroy_workqueue(wil->wmi_wq); |
|---|
| 834 | + kfree(wil->brd_info); |
|---|
| 720 | 835 | } |
|---|
| 721 | 836 | |
|---|
| 722 | 837 | static void wil_shutdown_bl(struct wil6210_priv *wil) |
|---|
| .. | .. |
|---|
| 1158 | 1273 | wil->max_agg_wsize = WIL_MAX_AGG_WSIZE; |
|---|
| 1159 | 1274 | wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE; |
|---|
| 1160 | 1275 | } |
|---|
| 1276 | + |
|---|
| 1277 | + update_supported_bands(wil); |
|---|
| 1161 | 1278 | } |
|---|
| 1162 | 1279 | |
|---|
| 1163 | 1280 | void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) |
|---|
| .. | .. |
|---|
| 1290 | 1407 | u8 mac[8]; |
|---|
| 1291 | 1408 | int mac_addr; |
|---|
| 1292 | 1409 | |
|---|
| 1293 | | - if (wil->hw_version >= HW_VER_TALYN_MB) |
|---|
| 1294 | | - mac_addr = RGF_OTP_MAC_TALYN_MB; |
|---|
| 1295 | | - else |
|---|
| 1296 | | - mac_addr = RGF_OTP_MAC; |
|---|
| 1410 | + /* OEM MAC has precedence */ |
|---|
| 1411 | + mac_addr = RGF_OTP_OEM_MAC; |
|---|
| 1412 | + wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr), sizeof(mac)); |
|---|
| 1297 | 1413 | |
|---|
| 1298 | | - wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr), |
|---|
| 1299 | | - sizeof(mac)); |
|---|
| 1414 | + if (is_valid_ether_addr(mac)) { |
|---|
| 1415 | + wil_info(wil, "using OEM MAC %pM\n", mac); |
|---|
| 1416 | + } else { |
|---|
| 1417 | + if (wil->hw_version >= HW_VER_TALYN_MB) |
|---|
| 1418 | + mac_addr = RGF_OTP_MAC_TALYN_MB; |
|---|
| 1419 | + else |
|---|
| 1420 | + mac_addr = RGF_OTP_MAC; |
|---|
| 1421 | + |
|---|
| 1422 | + wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr), |
|---|
| 1423 | + sizeof(mac)); |
|---|
| 1424 | + } |
|---|
| 1425 | + |
|---|
| 1300 | 1426 | if (!is_valid_ether_addr(mac)) { |
|---|
| 1301 | 1427 | wil_err(wil, "Invalid MAC %pM\n", mac); |
|---|
| 1302 | 1428 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 1360 | 1486 | |
|---|
| 1361 | 1487 | lockdep_assert_held(&wil->vif_mutex); |
|---|
| 1362 | 1488 | |
|---|
| 1363 | | - for (i = 0; i < wil->max_vifs; i++) { |
|---|
| 1489 | + for (i = 0; i < GET_MAX_VIFS(wil); i++) { |
|---|
| 1364 | 1490 | struct wil6210_vif *vif = wil->vifs[i]; |
|---|
| 1365 | 1491 | |
|---|
| 1366 | 1492 | if (vif) |
|---|
| .. | .. |
|---|
| 1388 | 1514 | |
|---|
| 1389 | 1515 | static void wil_pre_fw_config(struct wil6210_priv *wil) |
|---|
| 1390 | 1516 | { |
|---|
| 1517 | + wil_clear_fw_log_addr(wil); |
|---|
| 1391 | 1518 | /* Mark FW as loaded from host */ |
|---|
| 1392 | 1519 | wil_s(wil, RGF_USER_USAGE_6, 1); |
|---|
| 1393 | 1520 | |
|---|
| .. | .. |
|---|
| 1400 | 1527 | if (wil->hw_version < HW_VER_TALYN_MB) { |
|---|
| 1401 | 1528 | wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); |
|---|
| 1402 | 1529 | wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); |
|---|
| 1403 | | - } else { |
|---|
| 1404 | | - wil_s(wil, |
|---|
| 1405 | | - RGF_CAF_ICR_TALYN_MB + offsetof(struct RGF_ICR, ICR), 0); |
|---|
| 1406 | | - wil_w(wil, RGF_CAF_ICR_TALYN_MB + |
|---|
| 1407 | | - offsetof(struct RGF_ICR, IMV), ~0); |
|---|
| 1408 | 1530 | } |
|---|
| 1409 | 1531 | /* clear PAL_UNIT_ICR (potential D0->D3 leftover) |
|---|
| 1410 | 1532 | * In Talyn-MB host cannot access this register due to |
|---|
| .. | .. |
|---|
| 1428 | 1550 | struct wireless_dev *wdev; |
|---|
| 1429 | 1551 | int i, rc; |
|---|
| 1430 | 1552 | |
|---|
| 1431 | | - for (i = 0; i < wil->max_vifs; i++) { |
|---|
| 1553 | + for (i = 0; i < GET_MAX_VIFS(wil); i++) { |
|---|
| 1432 | 1554 | vif = wil->vifs[i]; |
|---|
| 1433 | 1555 | if (!vif) |
|---|
| 1434 | 1556 | continue; |
|---|
| .. | .. |
|---|
| 1447 | 1569 | } |
|---|
| 1448 | 1570 | |
|---|
| 1449 | 1571 | return 0; |
|---|
| 1572 | +} |
|---|
| 1573 | + |
|---|
| 1574 | +/* |
|---|
| 1575 | + * Clear FW and ucode log start addr to indicate FW log is not ready. The host |
|---|
| 1576 | + * driver clears the addresses before FW starts and FW initializes the address |
|---|
| 1577 | + * when it is ready to send logs. |
|---|
| 1578 | + */ |
|---|
| 1579 | +void wil_clear_fw_log_addr(struct wil6210_priv *wil) |
|---|
| 1580 | +{ |
|---|
| 1581 | + /* FW log addr */ |
|---|
| 1582 | + wil_w(wil, RGF_USER_USAGE_1, 0); |
|---|
| 1583 | + /* ucode log addr */ |
|---|
| 1584 | + wil_w(wil, RGF_USER_USAGE_2, 0); |
|---|
| 1585 | + wil_dbg_misc(wil, "Cleared FW and ucode log address"); |
|---|
| 1450 | 1586 | } |
|---|
| 1451 | 1587 | |
|---|
| 1452 | 1588 | /* |
|---|
| .. | .. |
|---|
| 1480 | 1616 | if (wil->hw_version == HW_VER_UNKNOWN) |
|---|
| 1481 | 1617 | return -ENODEV; |
|---|
| 1482 | 1618 | |
|---|
| 1483 | | - if (test_bit(WIL_PLATFORM_CAPA_T_PWR_ON_0, wil->platform_capa)) { |
|---|
| 1619 | + if (test_bit(WIL_PLATFORM_CAPA_T_PWR_ON_0, wil->platform_capa) && |
|---|
| 1620 | + wil->hw_version < HW_VER_TALYN_MB) { |
|---|
| 1484 | 1621 | wil_dbg_misc(wil, "Notify FW to set T_POWER_ON=0\n"); |
|---|
| 1485 | 1622 | wil_s(wil, RGF_USER_USAGE_8, BIT_USER_SUPPORT_T_POWER_ON_0); |
|---|
| 1486 | 1623 | } |
|---|
| .. | .. |
|---|
| 1499 | 1636 | } |
|---|
| 1500 | 1637 | |
|---|
| 1501 | 1638 | set_bit(wil_status_resetting, wil->status); |
|---|
| 1502 | | - if (test_bit(wil_status_collecting_dumps, wil->status)) { |
|---|
| 1503 | | - /* Device collects crash dump, cancel the reset. |
|---|
| 1504 | | - * following crash dump collection, reset would take place. |
|---|
| 1505 | | - */ |
|---|
| 1506 | | - wil_dbg_misc(wil, "reject reset while collecting crash dump\n"); |
|---|
| 1507 | | - rc = -EBUSY; |
|---|
| 1508 | | - goto out; |
|---|
| 1509 | | - } |
|---|
| 1510 | | - |
|---|
| 1511 | 1639 | mutex_lock(&wil->vif_mutex); |
|---|
| 1512 | 1640 | wil_abort_scan_all_vifs(wil, false); |
|---|
| 1513 | 1641 | mutex_unlock(&wil->vif_mutex); |
|---|
| 1514 | 1642 | |
|---|
| 1515 | | - for (i = 0; i < wil->max_vifs; i++) { |
|---|
| 1643 | + for (i = 0; i < GET_MAX_VIFS(wil); i++) { |
|---|
| 1516 | 1644 | vif = wil->vifs[i]; |
|---|
| 1517 | 1645 | if (vif) { |
|---|
| 1518 | 1646 | cancel_work_sync(&vif->disconnect_worker); |
|---|
| 1519 | 1647 | wil6210_disconnect(vif, NULL, |
|---|
| 1520 | | - WLAN_REASON_DEAUTH_LEAVING, false); |
|---|
| 1648 | + WLAN_REASON_DEAUTH_LEAVING); |
|---|
| 1649 | + vif->ptk_rekey_state = WIL_REKEY_IDLE; |
|---|
| 1521 | 1650 | } |
|---|
| 1522 | 1651 | } |
|---|
| 1523 | 1652 | wil_bcast_fini_all(wil); |
|---|
| 1524 | 1653 | |
|---|
| 1525 | 1654 | /* Disable device led before reset*/ |
|---|
| 1526 | 1655 | wmi_led_cfg(wil, false); |
|---|
| 1656 | + |
|---|
| 1657 | + down_write(&wil->mem_lock); |
|---|
| 1527 | 1658 | |
|---|
| 1528 | 1659 | /* prevent NAPI from being scheduled and prevent wmi commands */ |
|---|
| 1529 | 1660 | mutex_lock(&wil->wmi_mutex); |
|---|
| .. | .. |
|---|
| 1573 | 1704 | |
|---|
| 1574 | 1705 | if (wil->secured_boot) { |
|---|
| 1575 | 1706 | wil_err(wil, "secured boot is not supported\n"); |
|---|
| 1707 | + up_write(&wil->mem_lock); |
|---|
| 1576 | 1708 | return -ENOTSUPP; |
|---|
| 1577 | 1709 | } |
|---|
| 1578 | 1710 | |
|---|
| .. | .. |
|---|
| 1590 | 1722 | rc = wil_request_firmware(wil, wil->wil_fw_name, true); |
|---|
| 1591 | 1723 | if (rc) |
|---|
| 1592 | 1724 | goto out; |
|---|
| 1593 | | - if (wil->brd_file_addr) |
|---|
| 1725 | + if (wil->num_of_brd_entries) |
|---|
| 1594 | 1726 | rc = wil_request_board(wil, board_file); |
|---|
| 1595 | 1727 | else |
|---|
| 1596 | 1728 | rc = wil_request_firmware(wil, board_file, true); |
|---|
| .. | .. |
|---|
| 1607 | 1739 | reinit_completion(&wil->halp.comp); |
|---|
| 1608 | 1740 | |
|---|
| 1609 | 1741 | clear_bit(wil_status_resetting, wil->status); |
|---|
| 1742 | + |
|---|
| 1743 | + up_write(&wil->mem_lock); |
|---|
| 1610 | 1744 | |
|---|
| 1611 | 1745 | if (load_fw) { |
|---|
| 1612 | 1746 | wil_unmask_irq(wil); |
|---|
| .. | .. |
|---|
| 1657 | 1791 | return rc; |
|---|
| 1658 | 1792 | |
|---|
| 1659 | 1793 | out: |
|---|
| 1794 | + up_write(&wil->mem_lock); |
|---|
| 1660 | 1795 | clear_bit(wil_status_resetting, wil->status); |
|---|
| 1661 | 1796 | return rc; |
|---|
| 1662 | 1797 | } |
|---|
| .. | .. |
|---|
| 1687 | 1822 | return rc; |
|---|
| 1688 | 1823 | |
|---|
| 1689 | 1824 | /* Rx RING. After MAC and beacon */ |
|---|
| 1825 | + if (rx_ring_order == 0) |
|---|
| 1826 | + rx_ring_order = wil->hw_version < HW_VER_TALYN_MB ? |
|---|
| 1827 | + WIL_RX_RING_SIZE_ORDER_DEFAULT : |
|---|
| 1828 | + WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT; |
|---|
| 1829 | + |
|---|
| 1690 | 1830 | rc = wil->txrx_ops.rx_init(wil, rx_ring_order); |
|---|
| 1691 | 1831 | if (rc) |
|---|
| 1692 | 1832 | return rc; |
|---|
| .. | .. |
|---|
| 1749 | 1889 | |
|---|
| 1750 | 1890 | int __wil_down(struct wil6210_priv *wil) |
|---|
| 1751 | 1891 | { |
|---|
| 1892 | + int rc; |
|---|
| 1752 | 1893 | WARN_ON(!mutex_is_locked(&wil->mutex)); |
|---|
| 1753 | 1894 | |
|---|
| 1754 | 1895 | set_bit(wil_status_resetting, wil->status); |
|---|
| .. | .. |
|---|
| 1768 | 1909 | wil_abort_scan_all_vifs(wil, false); |
|---|
| 1769 | 1910 | mutex_unlock(&wil->vif_mutex); |
|---|
| 1770 | 1911 | |
|---|
| 1771 | | - return wil_reset(wil, false); |
|---|
| 1912 | + rc = wil_reset(wil, false); |
|---|
| 1913 | + |
|---|
| 1914 | + return rc; |
|---|
| 1772 | 1915 | } |
|---|
| 1773 | 1916 | |
|---|
| 1774 | 1917 | int wil_down(struct wil6210_priv *wil) |
|---|
| .. | .. |
|---|
| 1790 | 1933 | int i; |
|---|
| 1791 | 1934 | int rc = -ENOENT; |
|---|
| 1792 | 1935 | |
|---|
| 1793 | | - for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { |
|---|
| 1936 | + for (i = 0; i < wil->max_assoc_sta; i++) { |
|---|
| 1794 | 1937 | if (wil->sta[i].mid == mid && |
|---|
| 1795 | 1938 | wil->sta[i].status != wil_sta_unused && |
|---|
| 1796 | 1939 | ether_addr_equal(wil->sta[i].addr, mac)) { |
|---|
| .. | .. |
|---|
| 1806 | 1949 | { |
|---|
| 1807 | 1950 | unsigned long rc; |
|---|
| 1808 | 1951 | unsigned long to_jiffies = msecs_to_jiffies(WAIT_FOR_HALP_VOTE_MS); |
|---|
| 1952 | + |
|---|
| 1953 | + if (wil->hw_version >= HW_VER_TALYN_MB) |
|---|
| 1954 | + return; |
|---|
| 1809 | 1955 | |
|---|
| 1810 | 1956 | mutex_lock(&wil->halp.lock); |
|---|
| 1811 | 1957 | |
|---|
| .. | .. |
|---|
| 1838 | 1984 | |
|---|
| 1839 | 1985 | void wil_halp_unvote(struct wil6210_priv *wil) |
|---|
| 1840 | 1986 | { |
|---|
| 1987 | + if (wil->hw_version >= HW_VER_TALYN_MB) |
|---|
| 1988 | + return; |
|---|
| 1989 | + |
|---|
| 1841 | 1990 | WARN_ON(wil->halp.ref_cnt == 0); |
|---|
| 1842 | 1991 | |
|---|
| 1843 | 1992 | mutex_lock(&wil->halp.lock); |
|---|