.. | .. |
---|
| 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); |
---|