diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-21 17:28:08 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-11-21 17:28:08 +0100 |
commit | fcc79e1714e8c2b8e216dc3149812edd37884eef (patch) | |
tree | 17a51d29db810b81412be040aaf380936b3261b4 /drivers/net/wireless | |
parent | Merge tag 'bpf-next-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/bp... (diff) | |
parent | Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (diff) | |
download | linux-fcc79e1714e8c2b8e216dc3149812edd37884eef.tar.xz linux-fcc79e1714e8c2b8e216dc3149812edd37884eef.zip |
Merge tag 'net-next-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Paolo Abeni:
"The most significant set of changes is the per netns RTNL. The new
behavior is disabled by default, regression risk should be contained.
Notably the new config knob PTP_1588_CLOCK_VMCLOCK will inherit its
default value from PTP_1588_CLOCK_KVM, as the first is intended to be
a more reliable replacement for the latter.
Core:
- Started a very large, in-progress, effort to make the RTNL lock
scope per network-namespace, thus reducing the lock contention
significantly in the containerized use-case, comprising:
- RCU-ified some relevant slices of the FIB control path
- introduce basic per netns locking helpers
- namespacified the IPv4 address hash table
- remove rtnl_register{,_module}() in favour of
rtnl_register_many()
- refactor rtnl_{new,del,set}link() moving as much validation as
possible out of RTNL lock
- convert all phonet doit() and dumpit() handlers to RCU
- convert IPv4 addresses manipulation to per-netns RTNL
- convert virtual interface creation to per-netns RTNL
the per-netns lock infrastructure is guarded by the
CONFIG_DEBUG_NET_SMALL_RTNL knob, disabled by default ad interim.
- Introduce NAPI suspension, to efficiently switching between busy
polling (NAPI processing suspended) and normal processing.
- Migrate the IPv4 routing input, output and control path from direct
ToS usage to DSCP macros. This is a work in progress to make ECN
handling consistent and reliable.
- Add drop reasons support to the IPv4 rotue input path, allowing
better introspection in case of packets drop.
- Make FIB seqnum lockless, dropping RTNL protection for read access.
- Make inet{,v6} addresses hashing less predicable.
- Allow providing timestamp OPT_ID via cmsg, to correlate TX packets
and timestamps
Things we sprinkled into general kernel code:
- Add small file operations for debugfs, to reduce the struct ops
size.
- Refactoring and optimization for the implementation of page_frag
API, This is a preparatory work to consolidate the page_frag
implementation.
Netfilter:
- Optimize set element transactions to reduce memory consumption
- Extended netlink error reporting for attribute parser failure.
- Make legacy xtables configs user selectable, giving users the
option to configure iptables without enabling any other config.
- Address a lot of false-positive RCU issues, pointed by recent CI
improvements.
BPF:
- Put xsk sockets on a struct diet and add various cleanups. Overall,
this helps to bump performance by 12% for some workloads.
- Extend BPF selftests to increase coverage of XDP features in
combination with BPF cpumap.
- Optimize and homogenize bpf_csum_diff helper for all archs and also
add a batch of new BPF selftests for it.
- Extend netkit with an option to delegate skb->{mark,priority}
scrubbing to its BPF program.
- Make the bpf_get_netns_cookie() helper available also to tc(x) BPF
programs.
Protocols:
- Introduces 4-tuple hash for connected udp sockets, speeding-up
significantly connected sockets lookup.
- Add a fastpath for some TCP timers that usually expires after
close, the socket lock contention.
- Add inbound and outbound xfrm state caches to speed up state
lookups.
- Avoid sending MPTCP advertisements on stale subflows, reducing
risks on loosing them.
- Make neighbours table flushing more scalable, maintaining per
device neigh lists.
Driver API:
- Introduce a unified interface to configure transmission H/W
shaping, and expose it to user-space via generic-netlink.
- Add support for per-NAPI config via netlink. This makes napi
configuration persistent across queues removal and re-creation.
Requires driver updates, currently supported drivers are:
nVidia/Mellanox mlx4 and mlx5, Broadcom brcm and Intel ice.
- Add ethtool support for writing SFP / PHY firmware blocks.
- Track RSS context allocation from ethtool core.
- Implement support for mirroring to DSA CPU port, via TC mirror
offload.
- Consolidate FDB updates notification, to avoid duplicates on
device-specific entries.
- Expose DPLL clock quality level to the user-space.
- Support master-slave PHY config via device tree.
Tests and tooling:
- forwarding: introduce deferred commands, to simplify the cleanup
phase
Drivers:
- Updated several drivers - Amazon vNic, Google vNic, Microsoft vNic,
Intel e1000e and Broadcom Tigon3 - to use netdev-genl to link the
IRQs and queues to NAPI IDs, allowing busy polling and better
introspection.
- Ethernet high-speed NICs:
- nVidia/Mellanox:
- mlx5:
- a large refactor to implement support for cross E-Switch
scheduling
- refactor H/W conter management to let it scale better
- H/W GRO cleanups
- Intel (100G, ice)::
- add support for ethtool reset
- implement support for per TX queue H/W shaping
- AMD/Solarflare:
- implement per device queue stats support
- Broadcom (bnxt):
- improve wildcard l4proto on IPv4/IPv6 ntuple rules
- Marvell Octeon:
- Add representor support for each Resource Virtualization Unit
(RVU) device.
- Hisilicon:
- add support for the BMC Gigabit Ethernet
- IBM (EMAC):
- driver cleanup and modernization
- Cisco (VIC):
- raise the queues number limit to 256
- Ethernet virtual:
- Google vNIC:
- implement page pool support
- macsec:
- inherit lower device's features and TSO limits when
offloading
- virtio_net:
- enable premapped mode by default
- support for XDP socket(AF_XDP) zerocopy TX
- wireguard:
- set the TSO max size to be GSO_MAX_SIZE, to aggregate larger
packets.
- Ethernet NICs embedded and virtual:
- Broadcom ASP:
- enable software timestamping
- Freescale:
- add enetc4 PF driver
- MediaTek: Airoha SoC:
- implement BQL support
- RealTek r8169:
- enable TSO by default on r8168/r8125
- implement extended ethtool stats
- Renesas AVB:
- enable TX checksum offload
- Synopsys (stmmac):
- support header splitting for vlan tagged packets
- move common code for DWMAC4 and DWXGMAC into a separate FPE
module.
- add dwmac driver support for T-HEAD TH1520 SoC
- Synopsys (xpcs):
- driver refactor and cleanup
- TI:
- icssg_prueth: add VLAN offload support
- Xilinx emaclite:
- add clock support
- Ethernet switches:
- Microchip:
- implement support for the lan969x Ethernet switch family
- add LAN9646 switch support to KSZ DSA driver
- Ethernet PHYs:
- Marvel: 88q2x: enable auto negotiation
- Microchip: add support for LAN865X Rev B1 and LAN867X Rev C1/C2
- PTP:
- Add support for the Amazon virtual clock device
- Add PtP driver for s390 clocks
- WiFi:
- mac80211
- EHT 1024 aggregation size for transmissions
- new operation to indicate that a new interface is to be added
- support radio separation of multi-band devices
- move wireless extension spy implementation to libiw
- Broadcom:
- brcmfmac: optional LPO clock support
- Microchip:
- add support for Atmel WILC3000
- Qualcomm (ath12k):
- firmware coredump collection support
- add debugfs support for a multitude of statistics
- Qualcomm (ath5k):
- Arcadyan ARV45XX AR2417 & Gigaset SX76[23] AR241[34]A support
- Realtek:
- rtw88: 8821au and 8812au USB adapters support
- rtw89: add thermal protection
- rtw89: fine tune BT-coexsitence to improve user experience
- rtw89: firmware secure boot for WiFi 6 chip
- Bluetooth
- add Qualcomm WCN785x support for ids Foxconn 0xe0fc/0xe0f3 and
0x13d3:0x3623
- add Realtek RTL8852BE support for id Foxconn 0xe123
- add MediaTek MT7920 support for wireless module ids
- btintel_pcie: add handshake between driver and firmware
- btintel_pcie: add recovery mechanism
- btnxpuart: add GPIO support to power save feature"
* tag 'net-next-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1475 commits)
mm: page_frag: fix a compile error when kernel is not compiled
Documentation: tipc: fix formatting issue in tipc.rst
selftests: nic_performance: Add selftest for performance of NIC driver
selftests: nic_link_layer: Add selftest case for speed and duplex states
selftests: nic_link_layer: Add link layer selftest for NIC driver
bnxt_en: Add FW trace coredump segments to the coredump
bnxt_en: Add a new ethtool -W dump flag
bnxt_en: Add 2 parameters to bnxt_fill_coredump_seg_hdr()
bnxt_en: Add functions to copy host context memory
bnxt_en: Do not free FW log context memory
bnxt_en: Manage the FW trace context memory
bnxt_en: Allocate backing store memory for FW trace logs
bnxt_en: Add a 'force' parameter to bnxt_free_ctx_mem()
bnxt_en: Refactor bnxt_free_ctx_mem()
bnxt_en: Add mem_valid bit to struct bnxt_ctx_mem_type
bnxt_en: Update firmware interface spec to 1.10.3.85
selftests/bpf: Add some tests with sockmap SK_PASS
bpf: fix recursive lock when verdict program return SK_PASS
wireguard: device: support big tcp GSO
wireguard: selftests: load nf_conntrack if not present
...
Diffstat (limited to 'drivers/net/wireless')
264 files changed, 22970 insertions, 4816 deletions
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index f0441b3d7dcb..db9f9ebcb62d 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -837,12 +837,12 @@ static void ath10k_ahb_remove(struct platform_device *pdev) } static struct platform_driver ath10k_ahb_driver = { - .driver = { - .name = "ath10k_ahb", + .driver = { + .name = "ath10k_ahb", .of_match_table = ath10k_ahb_of_match, }, - .probe = ath10k_ahb_probe, - .remove_new = ath10k_ahb_remove, + .probe = ath10k_ahb_probe, + .remove = ath10k_ahb_remove, }; int ath10k_ahb_init(void) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 646e1737d4c4..c61b95a928da 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6369,7 +6369,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; struct cfg80211_scan_request *req = &hw_req->req; - struct wmi_start_scan_arg arg; + struct wmi_start_scan_arg *arg = NULL; int ret = 0; int i; u32 scan_timeout; @@ -6402,56 +6402,61 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, if (ret) goto exit; - memset(&arg, 0, sizeof(arg)); - ath10k_wmi_start_scan_init(ar, &arg); - arg.vdev_id = arvif->vdev_id; - arg.scan_id = ATH10K_SCAN_ID; + arg = kzalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) { + ret = -ENOMEM; + goto exit; + } + + ath10k_wmi_start_scan_init(ar, arg); + arg->vdev_id = arvif->vdev_id; + arg->scan_id = ATH10K_SCAN_ID; if (req->ie_len) { - arg.ie_len = req->ie_len; - memcpy(arg.ie, req->ie, arg.ie_len); + arg->ie_len = req->ie_len; + memcpy(arg->ie, req->ie, arg->ie_len); } if (req->n_ssids) { - arg.n_ssids = req->n_ssids; - for (i = 0; i < arg.n_ssids; i++) { - arg.ssids[i].len = req->ssids[i].ssid_len; - arg.ssids[i].ssid = req->ssids[i].ssid; + arg->n_ssids = req->n_ssids; + for (i = 0; i < arg->n_ssids; i++) { + arg->ssids[i].len = req->ssids[i].ssid_len; + arg->ssids[i].ssid = req->ssids[i].ssid; } } else { - arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; + arg->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; } if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { - arg.scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ; - ether_addr_copy(arg.mac_addr.addr, req->mac_addr); - ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); + arg->scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ; + ether_addr_copy(arg->mac_addr.addr, req->mac_addr); + ether_addr_copy(arg->mac_mask.addr, req->mac_addr_mask); } if (req->n_channels) { - arg.n_channels = req->n_channels; - for (i = 0; i < arg.n_channels; i++) - arg.channels[i] = req->channels[i]->center_freq; + arg->n_channels = req->n_channels; + for (i = 0; i < arg->n_channels; i++) + arg->channels[i] = req->channels[i]->center_freq; } /* if duration is set, default dwell times will be overwritten */ if (req->duration) { - arg.dwell_time_active = req->duration; - arg.dwell_time_passive = req->duration; - arg.burst_duration_ms = req->duration; + arg->dwell_time_active = req->duration; + arg->dwell_time_passive = req->duration; + arg->burst_duration_ms = req->duration; - scan_timeout = min_t(u32, arg.max_rest_time * - (arg.n_channels - 1) + (req->duration + + scan_timeout = min_t(u32, arg->max_rest_time * + (arg->n_channels - 1) + (req->duration + ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) * - arg.n_channels, arg.max_scan_time); + arg->n_channels, arg->max_scan_time); } else { - scan_timeout = arg.max_scan_time; + scan_timeout = arg->max_scan_time; } /* Add a 200ms margin to account for event/command processing */ scan_timeout += 200; - ret = ath10k_start_scan(ar, &arg); + ret = ath10k_start_scan(ar, arg); if (ret) { ath10k_warn(ar, "failed to start hw scan: %d\n", ret); spin_lock_bh(&ar->data_lock); @@ -6463,6 +6468,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, msecs_to_jiffies(scan_timeout)); exit: + kfree(arg); + mutex_unlock(&ar->conf_mutex); return ret; } @@ -7899,7 +7906,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; - struct wmi_start_scan_arg arg; + struct wmi_start_scan_arg *arg = NULL; int ret = 0; u32 scan_time_msec; @@ -7936,20 +7943,25 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2; - memset(&arg, 0, sizeof(arg)); - ath10k_wmi_start_scan_init(ar, &arg); - arg.vdev_id = arvif->vdev_id; - arg.scan_id = ATH10K_SCAN_ID; - arg.n_channels = 1; - arg.channels[0] = chan->center_freq; - arg.dwell_time_active = scan_time_msec; - arg.dwell_time_passive = scan_time_msec; - arg.max_scan_time = scan_time_msec; - arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; - arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; - arg.burst_duration_ms = duration; - - ret = ath10k_start_scan(ar, &arg); + arg = kzalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) { + ret = -ENOMEM; + goto exit; + } + + ath10k_wmi_start_scan_init(ar, arg); + arg->vdev_id = arvif->vdev_id; + arg->scan_id = ATH10K_SCAN_ID; + arg->n_channels = 1; + arg->channels[0] = chan->center_freq; + arg->dwell_time_active = scan_time_msec; + arg->dwell_time_passive = scan_time_msec; + arg->max_scan_time = scan_time_msec; + arg->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; + arg->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; + arg->burst_duration_ms = duration; + + ret = ath10k_start_scan(ar, arg); if (ret) { ath10k_warn(ar, "failed to start roc scan: %d\n", ret); spin_lock_bh(&ar->data_lock); @@ -7975,6 +7987,8 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = 0; exit: + kfree(arg); + mutex_unlock(&ar->conf_mutex); return ret; } @@ -8507,9 +8521,10 @@ exit: static void ath10k_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct ath10k *ar = hw->priv; struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; @@ -9121,7 +9136,7 @@ static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss1[ {6, {2633, 2925}, {1215, 1350}, {585, 650} }, {7, {2925, 3250}, {1350, 1500}, {650, 722} }, {8, {3510, 3900}, {1620, 1800}, {780, 867} }, - {9, {3900, 4333}, {1800, 2000}, {780, 867} } + {9, {3900, 4333}, {1800, 2000}, {865, 960} } }; /*MCS parameters with Nss = 2 */ @@ -9136,7 +9151,7 @@ static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss2[ {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, - {9, {7800, 8667}, {3600, 4000}, {1560, 1733} } + {9, {7800, 8667}, {3600, 4000}, {1730, 1920} } }; static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs, @@ -9450,7 +9465,7 @@ static const struct ieee80211_ops ath10k_ops = { .reconfig_complete = ath10k_reconfig_complete, .get_survey = ath10k_get_survey, .set_bitrate_mask = ath10k_mac_op_set_bitrate_mask, - .sta_rc_update = ath10k_sta_rc_update, + .link_sta_rc_update = ath10k_sta_rc_update, .offset_tsf = ath10k_offset_tsf, .ampdu_action = ath10k_ampdu_action, .get_et_sset_count = ath10k_debug_get_et_sset_count, diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 08a6f36a6be9..6805357ee29e 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -3,7 +3,7 @@ * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc. * Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com> - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> @@ -2648,9 +2648,9 @@ static void ath10k_sdio_remove(struct sdio_func *func) netif_napi_del(&ar->napi); - ath10k_core_destroy(ar); - destroy_workqueue(ar_sdio->workqueue); + + ath10k_core_destroy(ar); } static const struct sdio_device_id ath10k_sdio_devices[] = { diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 0fe47d51013c..d436a874cd5a 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1885,11 +1885,11 @@ static void ath10k_snoc_shutdown(struct platform_device *pdev) } static struct platform_driver ath10k_snoc_driver = { - .probe = ath10k_snoc_probe, - .remove_new = ath10k_snoc_remove, + .probe = ath10k_snoc_probe, + .remove = ath10k_snoc_remove, .shutdown = ath10k_snoc_shutdown, .driver = { - .name = "ath10k_snoc", + .name = "ath10k_snoc", .of_match_table = ath10k_snoc_dt_match, }, }; diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 97b12f51ef28..f2fc04596d48 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1000,18 +1000,18 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab) if (!ab->hw_params.fixed_fw_mem) return 0; - ret = ath11k_ahb_setup_msa_resources(ab); - if (ret) { - ath11k_err(ab, "failed to setup msa resources\n"); - return ret; - } - node = of_get_child_by_name(host_dev->of_node, "wifi-firmware"); if (!node) { ab_ahb->fw.use_tz = true; return 0; } + ret = ath11k_ahb_setup_msa_resources(ab); + if (ret) { + ath11k_err(ab, "failed to setup msa resources\n"); + return ret; + } + info.fwnode = &node->fwnode; info.parent = host_dev; info.name = node->name; @@ -1313,12 +1313,12 @@ free_resources: } static struct platform_driver ath11k_ahb_driver = { - .driver = { - .name = "ath11k", + .driver = { + .name = "ath11k", .of_match_table = ath11k_ahb_of_match, }, - .probe = ath11k_ahb_probe, - .remove_new = ath11k_ahb_remove, + .probe = ath11k_ahb_probe, + .remove = ath11k_ahb_remove, .shutdown = ath11k_ahb_shutdown, }; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index ccf4ad35fdc3..be67382c00f6 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -616,7 +616,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = false, .supports_rssi_stats = true, - .fw_wmi_diag_event = false, + .fw_wmi_diag_event = true, .current_cc_support = true, .dbr_debug_support = false, .global_reset = false, diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index f02599bd1c36..61f4b6dd5380 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1351,6 +1351,7 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab) ath11k_hal_free_cont_rdp(ab); ath11k_hal_free_cont_wrp(ab); kfree(hal->srng_config); + hal->srng_config = NULL; } EXPORT_SYMBOL(ath11k_hal_srng_deinit); diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f8068d2e848c..e6acbff06749 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -5079,9 +5079,10 @@ static void ath11k_mac_op_sta_set_4addr(struct ieee80211_hw *hw, static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct ath11k *ar = hw->priv; struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); @@ -9708,7 +9709,7 @@ static const struct ieee80211_ops ath11k_ops = { .sta_state = ath11k_mac_op_sta_state, .sta_set_4addr = ath11k_mac_op_sta_set_4addr, .sta_set_txpwr = ath11k_mac_op_sta_set_txpwr, - .sta_rc_update = ath11k_mac_op_sta_rc_update, + .link_sta_rc_update = ath11k_mac_op_sta_rc_update, .conf_tx = ath11k_mac_op_conf_tx, .set_antenna = ath11k_mac_op_set_antenna, .get_antenna = ath11k_mac_op_get_antenna, diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index f477afd325de..7a22483b35cd 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2180,6 +2180,9 @@ static int ath11k_qmi_request_device_info(struct ath11k_base *ab) ab->mem = bar_addr_va; ab->mem_len = resp.bar_size; + if (!ab->hw_params.ce_remap) + ab->mem_ce = ab->mem; + return 0; out: return ret; diff --git a/drivers/net/wireless/ath/ath11k/wow.c b/drivers/net/wireless/ath/ath11k/wow.c index 99d8ba45a75b..827085a926b2 100644 --- a/drivers/net/wireless/ath/ath11k/wow.c +++ b/drivers/net/wireless/ath/ath11k/wow.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/delay.h> @@ -155,6 +155,7 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new, u8 hdr_8023_bit_mask[ETH_HLEN] = {}; u8 hdr_80211_pattern[WOW_HDR_LEN] = {}; u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {}; + u8 bytemask[WOW_MAX_PATTERN_SIZE] = {}; int total_len = old->pkt_offset + old->pattern_len; int hdr_80211_end_offset; @@ -172,11 +173,17 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new, struct rfc1042_hdr *new_rfc_mask = (struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len); int rfc_len = sizeof(*new_rfc_pattern); + int i; + + /* convert bitmask to bytemask */ + for (i = 0; i < old->pattern_len; i++) + if (old->mask[i / 8] & BIT(i % 8)) + bytemask[i] = 0xff; memcpy(hdr_8023_pattern + old->pkt_offset, old->pattern, ETH_HLEN - old->pkt_offset); memcpy(hdr_8023_bit_mask + old->pkt_offset, - old->mask, ETH_HLEN - old->pkt_offset); + bytemask, ETH_HLEN - old->pkt_offset); /* Copy destination address */ memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN); @@ -232,7 +239,7 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new, (void *)old->pattern + ETH_HLEN - old->pkt_offset, total_len - ETH_HLEN); memcpy((u8 *)new->mask + new->pattern_len, - (void *)old->mask + ETH_HLEN - old->pkt_offset, + bytemask + ETH_HLEN - old->pkt_offset, total_len - ETH_HLEN); new->pattern_len += total_len - ETH_HLEN; @@ -393,35 +400,31 @@ static int ath11k_vif_wow_set_wakeups(struct ath11k_vif *arvif, } for (i = 0; i < wowlan->n_patterns; i++) { - u8 bitmask[WOW_MAX_PATTERN_SIZE] = {}; u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {}; u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {}; struct cfg80211_pkt_pattern new_pattern = {}; - struct cfg80211_pkt_pattern old_pattern = patterns[i]; - int j; new_pattern.pattern = ath_pattern; new_pattern.mask = ath_bitmask; if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE) continue; - /* convert bytemask to bitmask */ - for (j = 0; j < patterns[i].pattern_len; j++) - if (patterns[i].mask[j / 8] & BIT(j % 8)) - bitmask[j] = 0xff; - old_pattern.mask = bitmask; if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode == ATH11K_HW_TXRX_NATIVE_WIFI) { if (patterns[i].pkt_offset < ETH_HLEN) { - u8 pattern_ext[WOW_MAX_PATTERN_SIZE] = {}; - - memcpy(pattern_ext, old_pattern.pattern, - old_pattern.pattern_len); - old_pattern.pattern = pattern_ext; ath11k_wow_convert_8023_to_80211(&new_pattern, - &old_pattern); + &patterns[i]); } else { - new_pattern = old_pattern; + int j; + + new_pattern = patterns[i]; + new_pattern.mask = ath_bitmask; + + /* convert bitmask to bytemask */ + for (j = 0; j < patterns[i].pattern_len; j++) + if (patterns[i].mask[j / 8] & BIT(j % 8)) + ath_bitmask[j] = 0xff; + new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN; } } diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig index f64e7c322216..52a1bb19e3da 100644 --- a/drivers/net/wireless/ath/ath12k/Kconfig +++ b/drivers/net/wireless/ath/ath12k/Kconfig @@ -42,3 +42,13 @@ config ATH12K_TRACING If unsure, say Y to make it easier to debug problems. But if you want optimal performance choose N. + +config ATH12K_COREDUMP + bool "ath12k coredump" + depends on ATH12K + select WANT_DEV_COREDUMP + help + Enable ath12k coredump collection + + If unsure, say Y to make it easier to debug problems. But if + dump collection not required choose N. diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index 5a1ed20d730e..b5bb3e2599cd 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -27,6 +27,7 @@ ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o ath12k-$(CONFIG_ACPI) += acpi.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o ath12k-$(CONFIG_PM) += wow.o +ath12k-$(CONFIG_ATH12K_COREDUMP) += coredump.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h index 857bc5f9e946..1a14b9fb86b8 100644 --- a/drivers/net/wireless/ath/ath12k/ce.h +++ b/drivers/net/wireless/ath/ath12k/ce.h @@ -148,7 +148,7 @@ struct ath12k_ce_pipe { void (*send_cb)(struct ath12k_ce_pipe *pipe); void (*recv_cb)(struct ath12k_base *ab, struct sk_buff *skb); - struct tasklet_struct intr_tq; + struct work_struct intr_wq; struct ath12k_ce_ring *src_ring; struct ath12k_ce_ring *dest_ring; struct ath12k_ce_ring *status_ring; diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 51252e8bc1ae..c57322221e1d 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1004,7 +1004,7 @@ void ath12k_core_halt(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ar->num_created_vdevs = 0; ar->allocated_vdev_map = 0; @@ -1078,6 +1078,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; + wiphy_lock(ah->hw->wiphy); mutex_lock(&ah->hw_mutex); switch (ah->state) { @@ -1086,10 +1087,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) for (j = 0; j < ah->num_radio; j++) { ar = &ah->radio[j]; - - mutex_lock(&ar->conf_mutex); ath12k_core_halt(ar); - mutex_unlock(&ar->conf_mutex); } break; @@ -1110,6 +1108,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) } mutex_unlock(&ah->hw_mutex); + wiphy_unlock(ah->hw->wiphy); } complete(&ab->driver_recovery); @@ -1188,6 +1187,7 @@ static void ath12k_core_reset(struct work_struct *work) ab->is_reset = true; atomic_set(&ab->recovery_count, 0); + ath12k_coredump_collect(ab); ath12k_core_pre_reconfigure_recovery(ab); ath12k_core_post_reconfigure_recovery(ab); @@ -1312,6 +1312,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, INIT_WORK(&ab->restart_work, ath12k_core_restart); INIT_WORK(&ab->reset_work, ath12k_core_reset); INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work); + INIT_WORK(&ab->dump_work, ath12k_coredump_upload); timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 7f2e9a9b4097..3bf31ee5b9fa 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -30,6 +30,7 @@ #include "acpi.h" #include "wow.h" #include "debugfs_htt_stats.h" +#include "coredump.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -94,6 +95,14 @@ static inline enum wme_ac ath12k_tid_to_ac(u32 tid) WME_AC_VO); } +static inline u64 ath12k_le32hilo_to_u64(__le32 hi, __le32 lo) +{ + u64 hi64 = le32_to_cpu(hi); + u64 lo64 = le32_to_cpu(lo); + + return (hi64 << 32) | lo64; +} + enum ath12k_skb_flags { ATH12K_SKB_HW_80211_ENCAP = BIT(0), ATH12K_SKB_CIPHER_SET = BIT(1), @@ -220,8 +229,9 @@ struct ath12k_tx_conf { }; struct ath12k_key_conf { - bool changed; enum set_key_cmd cmd; + struct list_head list; + struct ieee80211_sta *sta; struct ieee80211_key_conf *key; }; @@ -238,10 +248,8 @@ struct ath12k_rekey_data { bool enable_offload; }; -struct ath12k_vif { +struct ath12k_link_vif { u32 vdev_id; - enum wmi_vdev_type vdev_type; - enum wmi_vdev_subtype vdev_subtype; u32 beacon_interval; u32 dtim_period; u16 ast_hash; @@ -251,13 +259,38 @@ struct ath12k_vif { u8 search_type; struct ath12k *ar; - struct ieee80211_vif *vif; int bank_id; u8 vdev_id_check_en; struct wmi_wmm_params_all_arg wmm_params; struct list_head list; + + bool is_created; + bool is_started; + bool is_up; + u8 bssid[ETH_ALEN]; + struct cfg80211_bitrate_mask bitrate_mask; + struct delayed_work connection_loss_work; + int num_legacy_stations; + int rtscts_prot_mode; + int txpower; + bool rsnie_present; + bool wpaie_present; + struct ieee80211_chanctx_conf chanctx; + u8 vdev_stats_id; + u32 punct_bitmap; + u8 link_id; + struct ath12k_vif *ahvif; + struct ath12k_rekey_data rekey_data; +}; + +struct ath12k_vif { + enum wmi_vdev_type vdev_type; + enum wmi_vdev_subtype vdev_subtype; + struct ieee80211_vif *vif; + struct ath12k_hw *ah; + union { struct { u32 uapsd; @@ -275,25 +308,16 @@ struct ath12k_vif { } ap; } u; - bool is_created; - bool is_started; - bool is_up; u32 aid; - u8 bssid[ETH_ALEN]; - struct cfg80211_bitrate_mask bitrate_mask; - struct delayed_work connection_loss_work; - int num_legacy_stations; - int rtscts_prot_mode; - int txpower; - bool rsnie_present; - bool wpaie_present; u32 key_cipher; u8 tx_encap_type; - u8 vdev_stats_id; - u32 punct_bitmap; bool ps; - struct ath12k_vif_cache *cache; - struct ath12k_rekey_data rekey_data; + + struct ath12k_link_vif deflink; + struct ath12k_link_vif __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + struct ath12k_vif_cache *cache[IEEE80211_MLD_MAX_NUM_LINKS]; + /* indicates bitmap of link vif created in FW */ + u16 links_map; /* Must be last - ends in a flexible-array member. * @@ -306,7 +330,7 @@ struct ath12k_vif { struct ath12k_vif_iter { u32 vdev_id; struct ath12k *ar; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; }; #define HAL_AST_IDX_INVALID 0xFFFF @@ -441,27 +465,36 @@ struct ath12k_wbm_tx_stats { u64 wbm_tx_comp_stats[HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX]; }; -struct ath12k_sta { - struct ath12k_vif *arvif; +struct ath12k_link_sta { + struct ath12k_link_vif *arvif; + struct ath12k_sta *ahsta; /* the following are protected by ar->data_lock */ u32 changed; /* IEEE80211_RC_* */ u32 bw; u32 nss; u32 smps; - enum hal_pn_type pn_type; - struct work_struct update_wk; + struct wiphy_work update_wk; struct rate_info txrate; struct rate_info last_txrate; u64 rx_duration; u64 tx_duration; u8 rssi_comb; + u8 link_id; struct ath12k_rx_peer_stats *rx_stats; struct ath12k_wbm_tx_stats *wbm_tx_stats; u32 bw_prev; }; +struct ath12k_sta { + enum hal_pn_type pn_type; + struct ath12k_link_sta deflink; + struct ath12k_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + /* indicates bitmap of link sta created in FW */ + u16 links_map; +}; + #define ATH12K_MIN_5G_FREQ 4150 #define ATH12K_MIN_6G_FREQ 5925 #define ATH12K_MAX_6G_FREQ 7115 @@ -561,13 +594,9 @@ struct ath12k { u32 chan_tx_pwr; u32 num_stations; u32 max_num_stations; - bool monitor_present; - /* To synchronize concurrent synchronous mac80211 callback operations, - * concurrent debugfs configuration and concurrent FW statistics events. - */ - struct mutex conf_mutex; + /* protects the radio specific data like debug stats, ppdu_stats_info stats, - * vdev_stop_status info, scan data, ath12k_sta info, ath12k_vif info, + * vdev_stop_status info, scan data, ath12k_sta info, ath12k_link_vif info, * channel context data, survey info, test mode data. */ spinlock_t data_lock; @@ -666,6 +695,7 @@ struct ath12k_hw { enum ath12k_hw_state state; bool regd_updated; bool use_6ghz_regd; + u8 num_radio; /* Keep last */ @@ -782,6 +812,10 @@ struct ath12k_base { /* HW channel counters frequency value in hertz common to all MACs */ u32 cc_freq_hz; + struct ath12k_dump_file_data *dump_data; + size_t ath12k_coredump_len; + struct work_struct dump_work; + struct ath12k_htc htc; struct ath12k_dp dp; @@ -1024,16 +1058,26 @@ static inline struct ath12k_skb_rxcb *ATH12K_SKB_RXCB(struct sk_buff *skb) return (struct ath12k_skb_rxcb *)skb->cb; } -static inline struct ath12k_vif *ath12k_vif_to_arvif(struct ieee80211_vif *vif) +static inline struct ath12k_vif *ath12k_vif_to_ahvif(struct ieee80211_vif *vif) { return (struct ath12k_vif *)vif->drv_priv; } -static inline struct ath12k_sta *ath12k_sta_to_arsta(struct ieee80211_sta *sta) +static inline struct ath12k_sta *ath12k_sta_to_ahsta(struct ieee80211_sta *sta) { return (struct ath12k_sta *)sta->drv_priv; } +static inline struct ieee80211_sta *ath12k_ahsta_to_sta(struct ath12k_sta *ahsta) +{ + return container_of((void *)ahsta, struct ieee80211_sta, drv_priv); +} + +static inline struct ieee80211_vif *ath12k_ahvif_to_vif(struct ath12k_vif *ahvif) +{ + return container_of((void *)ahvif, struct ieee80211_vif, drv_priv); +} + static inline struct ath12k *ath12k_ab_to_ar(struct ath12k_base *ab, int mac_id) { diff --git a/drivers/net/wireless/ath/ath12k/coredump.c b/drivers/net/wireless/ath/ath12k/coredump.c new file mode 100644 index 000000000000..72d675d15e64 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/coredump.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include <linux/devcoredump.h> +#include "hif.h" +#include "coredump.h" +#include "debug.h" + +enum +ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type(enum ath12k_qmi_target_mem type) +{ + enum ath12k_fw_crash_dump_type dump_type; + + switch (type) { + case HOST_DDR_REGION_TYPE: + dump_type = FW_CRASH_DUMP_REMOTE_MEM_DATA; + break; + case M3_DUMP_REGION_TYPE: + dump_type = FW_CRASH_DUMP_M3_DUMP; + break; + case PAGEABLE_MEM_REGION_TYPE: + dump_type = FW_CRASH_DUMP_PAGEABLE_DATA; + break; + case BDF_MEM_REGION_TYPE: + case CALDB_MEM_REGION_TYPE: + dump_type = FW_CRASH_DUMP_NONE; + break; + default: + dump_type = FW_CRASH_DUMP_TYPE_MAX; + break; + } + + return dump_type; +} + +void ath12k_coredump_upload(struct work_struct *work) +{ + struct ath12k_base *ab = container_of(work, struct ath12k_base, dump_work); + + ath12k_info(ab, "Uploading coredump\n"); + /* dev_coredumpv() takes ownership of the buffer */ + dev_coredumpv(ab->dev, ab->dump_data, ab->ath12k_coredump_len, GFP_KERNEL); + ab->dump_data = NULL; +} + +void ath12k_coredump_collect(struct ath12k_base *ab) +{ + ath12k_hif_coredump_download(ab); +} diff --git a/drivers/net/wireless/ath/ath12k/coredump.h b/drivers/net/wireless/ath/ath12k/coredump.h new file mode 100644 index 000000000000..5d6003b1c12d --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/coredump.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef _ATH12K_COREDUMP_H_ +#define _ATH12K_COREDUMP_H_ + +#define ATH12K_FW_CRASH_DUMP_V2 2 + +enum ath12k_fw_crash_dump_type { + FW_CRASH_DUMP_PAGING_DATA, + FW_CRASH_DUMP_RDDM_DATA, + FW_CRASH_DUMP_REMOTE_MEM_DATA, + FW_CRASH_DUMP_PAGEABLE_DATA, + FW_CRASH_DUMP_M3_DUMP, + FW_CRASH_DUMP_NONE, + + /* keep last */ + FW_CRASH_DUMP_TYPE_MAX, +}; + +#define COREDUMP_TLV_HDR_SIZE 8 + +struct ath12k_tlv_dump_data { + /* see ath11k_fw_crash_dump_type above */ + __le32 type; + + /* in bytes */ + __le32 tlv_len; + + /* pad to 32-bit boundaries as needed */ + u8 tlv_data[]; +} __packed; + +struct ath12k_dump_file_data { + /* "ATH12K-FW-DUMP" */ + char df_magic[16]; + /* total dump len in bytes */ + __le32 len; + /* file dump version */ + __le32 version; + /* pci device id */ + __le32 chip_id; + /* qrtr instance id */ + __le32 qrtr_id; + /* pci domain id */ + __le32 bus_id; + guid_t guid; + /* time-of-day stamp */ + __le64 tv_sec; + /* time-of-day stamp, nano-seconds */ + __le64 tv_nsec; + /* room for growth w/out changing binary format */ + u8 unused[128]; + u8 data[]; +} __packed; + +#ifdef CONFIG_ATH12K_COREDUMP +enum ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type + (enum ath12k_qmi_target_mem type); +void ath12k_coredump_upload(struct work_struct *work); +void ath12k_coredump_collect(struct ath12k_base *ab); +#else +static inline enum ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type + (enum ath12k_qmi_target_mem type) +{ + return FW_CRASH_DUMP_TYPE_MAX; +} + +static inline void ath12k_coredump_upload(struct work_struct *work) +{ +} + +static inline void ath12k_coredump_collect(struct ath12k_base *ab) +{ +} +#endif + +#endif diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 2a977c36af00..d4b32d1a431c 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -15,14 +15,14 @@ static ssize_t ath12k_write_simulate_radar(struct file *file, struct ath12k *ar = file->private_data; int ret; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); ret = ath12k_wmi_simulate_radar(ar); if (ret) goto exit; ret = count; exit: - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index f1b7e74aefe4..c9980c0193d1 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -12,8 +12,8 @@ #include "dp_rx.h" static u32 -print_array_to_buf(u8 *buf, u32 offset, const char *header, - const __le32 *array, u32 array_len, const char *footer) +print_array_to_buf_index(u8 *buf, u32 offset, const char *header, u32 stats_index, + const __le32 *array, u32 array_len, const char *footer) { int index = 0; u8 i; @@ -26,7 +26,7 @@ print_array_to_buf(u8 *buf, u32 offset, const char *header, for (i = 0; i < array_len; i++) { index += scnprintf(buf + offset + index, (ATH12K_HTT_STATS_BUF_SIZE - offset) - index, - " %u:%u,", i, le32_to_cpu(array[i])); + " %u:%u,", stats_index++, le32_to_cpu(array[i])); } /* To overwrite the last trailing comma */ index--; @@ -40,6 +40,54 @@ print_array_to_buf(u8 *buf, u32 offset, const char *header, return index; } +static u32 +print_array_to_buf(u8 *buf, u32 offset, const char *header, + const __le32 *array, u32 array_len, const char *footer) +{ + return print_array_to_buf_index(buf, offset, header, 0, array, array_len, + footer); +} + +static const char *ath12k_htt_be_tx_rx_ru_size_to_str(u8 ru_size) +{ + switch (ru_size) { + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_26: + return "26"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52: + return "52"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52_26: + return "52+26"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106: + return "106"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106_26: + return "106+26"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_242: + return "242"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484: + return "484"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484_242: + return "484+242"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996: + return "996"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484: + return "996+484"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484_242: + return "996+484+242"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2: + return "996x2"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2_484: + return "996x2+484"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3: + return "996x3"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3_484: + return "996x3+484"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x4: + return "996x4"; + default: + return "unknown"; + } +} + static void htt_print_tx_pdev_stats_cmn_tlv(const void *tag_buf, u16 tag_len, struct debug_htt_stats_req *stats_req) @@ -1447,6 +1495,1207 @@ ath12k_htt_print_tx_de_compl_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_tx_selfgen_cmn_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_cmn_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "su_bar = %u\n", + le32_to_cpu(htt_stats_buf->su_bar)); + len += scnprintf(buf + len, buf_len - len, "rts = %u\n", + le32_to_cpu(htt_stats_buf->rts)); + len += scnprintf(buf + len, buf_len - len, "cts2self = %u\n", + le32_to_cpu(htt_stats_buf->cts2self)); + len += scnprintf(buf + len, buf_len - len, "qos_null = %u\n", + le32_to_cpu(htt_stats_buf->qos_null)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_1 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_1)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_2 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_2)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_3 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_3)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_4 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_4)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_5 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_5)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_6 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_6)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_7 = %u\n\n", + le32_to_cpu(htt_stats_buf->delayed_bar_7)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ac_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_ac_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->ac_su_ndpa)); + len += scnprintf(buf + len, buf_len - len, "ac_su_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->ac_su_ndp)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndpa)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndp)); + len += print_array_to_buf_index(buf, len, "ac_mu_mimo_brpollX_tried = ", 1, + htt_stats_buf->ac_mu_mimo_brpoll, + ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ax_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_ax_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->ax_su_ndpa)); + len += scnprintf(buf + len, buf_len - len, "ax_su_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->ax_su_ndp)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndpa)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndp)); + len += print_array_to_buf_index(buf, len, "ax_mu_mimo_brpollX_tried = ", 1, + htt_stats_buf->ax_mu_mimo_brpoll, + ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS, "\n"); + len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger = %u\n", + le32_to_cpu(htt_stats_buf->ax_basic_trigger)); + len += scnprintf(buf + len, buf_len - len, "ax_ulmumimo_total_trigger = %u\n", + le32_to_cpu(htt_stats_buf->ax_ulmumimo_trigger)); + len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger = %u\n", + le32_to_cpu(htt_stats_buf->ax_bsr_trigger)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_bar_trigger)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger = %u\n\n", + le32_to_cpu(htt_stats_buf->ax_mu_rts_trigger)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_be_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_be_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_BE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_queued = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndpa_queued)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndpa)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndp_queued = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndp_queued)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndp)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_queued = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_queued)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_queued = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_queued)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp)); + len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_queued = ", 1, + htt_stats_buf->be_mu_mimo_brpoll_queued, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1, + "\n"); + len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_tried = ", 1, + htt_stats_buf->be_mu_mimo_brpoll, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1, + "\n"); + len += print_array_to_buf(buf, len, "be_ul_mumimo_trigger = ", + htt_stats_buf->be_ul_mumimo_trigger, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n"); + len += scnprintf(buf + len, buf_len - len, "be_basic_trigger = %u\n", + le32_to_cpu(htt_stats_buf->be_basic_trigger)); + len += scnprintf(buf + len, buf_len - len, "be_ulmumimo_total_trigger = %u\n", + le32_to_cpu(htt_stats_buf->be_ulmumimo_trigger)); + len += scnprintf(buf + len, buf_len - len, "be_bsr_trigger = %u\n", + le32_to_cpu(htt_stats_buf->be_bsr_trigger)); + len += scnprintf(buf + len, buf_len - len, "be_mu_bar_trigger = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_bar_trigger)); + len += scnprintf(buf + len, buf_len - len, "be_mu_rts_trigger = %u\n\n", + le32_to_cpu(htt_stats_buf->be_mu_rts_trigger)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ac_err_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_ac_err_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_ERR_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ac_su_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_su_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_su_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp1_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp1_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp2_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp2_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp3_err = %u\n\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp3_err)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ax_err_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_ax_err_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_ERR_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ax_su_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_su_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_su_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndp_err)); + len += print_array_to_buf_index(buf, len, "ax_mu_mimo_brpX_err", 1, + htt_stats_buf->ax_mu_mimo_brp_err, + ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1, + "\n"); + len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_basic_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "ax_ulmumimo_total_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_ulmumimo_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_bsr_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_bar_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger_err = %u\n\n", + le32_to_cpu(htt_stats_buf->ax_mu_rts_trigger_err)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_be_err_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_be_err_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_BE_ERR_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "be_su_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndp_flushed = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndp_flushed)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_flushed = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndpa_flushed)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_flushed = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_flushed)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_flushed = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_flushed)); + len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpX_err", 1, + htt_stats_buf->be_mu_mimo_brp_err, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1, + "\n"); + len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_flushed", 1, + htt_stats_buf->be_mu_mimo_brpoll_flushed, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1, + "\n"); + len += print_array_to_buf(buf, len, "be_mu_mimo_num_cbf_rcvd_on_brp_err", + htt_stats_buf->be_mu_mimo_brp_err_num_cbf_rxd, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_ul_mumimo_trigger_err", + htt_stats_buf->be_ul_mumimo_trigger_err, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n"); + len += scnprintf(buf + len, buf_len - len, "be_basic_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->be_basic_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "be_ulmumimo_total_trig_err = %u\n", + le32_to_cpu(htt_stats_buf->be_ulmumimo_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "be_bsr_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->be_bsr_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "be_mu_bar_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_bar_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "be_mu_rts_trigger_err = %u\n\n", + le32_to_cpu(htt_stats_buf->be_mu_rts_trigger_err)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ac_sched_status_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats) +{ + const struct ath12k_htt_tx_selfgen_ac_sched_status_stats_tlv *htt_stats_buf = + tag_buf; + u8 *buf = stats->buf; + u32 len = stats->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_SELFGEN_AC_SCHED_STATUS_STATS_TLV:\n"); + len += print_array_to_buf(buf, len, "ac_su_ndpa_sch_status", + htt_stats_buf->ac_su_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_su_ndp_sch_status", + htt_stats_buf->ac_su_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_ndpa_sch_status", + htt_stats_buf->ac_mu_mimo_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_ndp_sch_status", + htt_stats_buf->ac_mu_mimo_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_brp_sch_status", + htt_stats_buf->ac_mu_mimo_brp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_su_ndp_sch_flag_err", + htt_stats_buf->ac_su_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_ndp_sch_flag_err", + htt_stats_buf->ac_mu_mimo_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_brp_sch_flag_err", + htt_stats_buf->ac_mu_mimo_brp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n"); + + stats->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ax_sched_status_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats) +{ + const struct ath12k_htt_tx_selfgen_ax_sched_status_stats_tlv *htt_stats_buf = + tag_buf; + u8 *buf = stats->buf; + u32 len = stats->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_SELFGEN_AX_SCHED_STATUS_STATS_TLV:\n"); + len += print_array_to_buf(buf, len, "ax_su_ndpa_sch_status", + htt_stats_buf->ax_su_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_su_ndp_sch_status", + htt_stats_buf->ax_su_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_mimo_ndpa_sch_status", + htt_stats_buf->ax_mu_mimo_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_mimo_ndp_sch_status", + htt_stats_buf->ax_mu_mimo_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_brp_sch_status", + htt_stats_buf->ax_mu_brp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_bar_sch_status", + htt_stats_buf->ax_mu_bar_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_basic_trig_sch_status", + htt_stats_buf->ax_basic_trig_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_su_ndp_sch_flag_err", + htt_stats_buf->ax_su_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_mimo_ndp_sch_flag_err", + htt_stats_buf->ax_mu_mimo_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_brp_sch_flag_err", + htt_stats_buf->ax_mu_brp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_bar_sch_flag_err", + htt_stats_buf->ax_mu_bar_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_basic_trig_sch_flag_err", + htt_stats_buf->ax_basic_trig_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_ulmumimo_trig_sch_status", + htt_stats_buf->ax_ulmumimo_trig_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_ulmumimo_trig_sch_flag_err", + htt_stats_buf->ax_ulmumimo_trig_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n"); + + stats->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_be_sched_status_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats) +{ + const struct ath12k_htt_tx_selfgen_be_sched_status_stats_tlv *htt_stats_buf = + tag_buf; + u8 *buf = stats->buf; + u32 len = stats->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_SELFGEN_BE_SCHED_STATUS_STATS_TLV:\n"); + len += print_array_to_buf(buf, len, "be_su_ndpa_sch_status", + htt_stats_buf->be_su_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_su_ndp_sch_status", + htt_stats_buf->be_su_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_mimo_ndpa_sch_status", + htt_stats_buf->be_mu_mimo_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_mimo_ndp_sch_status", + htt_stats_buf->be_mu_mimo_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_brp_sch_status", + htt_stats_buf->be_mu_brp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_bar_sch_status", + htt_stats_buf->be_mu_bar_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_basic_trig_sch_status", + htt_stats_buf->be_basic_trig_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_su_ndp_sch_flag_err", + htt_stats_buf->be_su_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_mimo_ndp_sch_flag_err", + htt_stats_buf->be_mu_mimo_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_brp_sch_flag_err", + htt_stats_buf->be_mu_brp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_bar_sch_flag_err", + htt_stats_buf->be_mu_bar_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_basic_trig_sch_flag_err", + htt_stats_buf->be_basic_trig_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_basic_trig_sch_flag_err", + htt_stats_buf->be_basic_trig_sch_flag_err, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_ulmumimo_trig_sch_flag_err", + htt_stats_buf->be_ulmumimo_trig_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n"); + + stats->buf_len = len; +} + +static void +ath12k_htt_print_stats_string_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_string_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u8 i; + u16 index = 0; + u32 datum; + char data[ATH12K_HTT_MAX_STRING_LEN] = {0}; + + tag_len = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:\n"); + for (i = 0; i < tag_len; i++) { + datum = __le32_to_cpu(htt_stats_buf->data[i]); + index += scnprintf(&data[index], ATH12K_HTT_MAX_STRING_LEN - index, + "%.*s", 4, (char *)&datum); + if (index >= ATH12K_HTT_MAX_STRING_LEN) + break; + } + len += scnprintf(buf + len, buf_len - len, "data = %s\n\n", data); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sring_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sring_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + u32 avail_words; + u32 head_tail_ptr; + u32 sring_stat; + u32 tail_ptr; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__ring_id__arena__ep); + avail_words = __le32_to_cpu(htt_stats_buf->num_avail_words__num_valid_words); + head_tail_ptr = __le32_to_cpu(htt_stats_buf->head_ptr__tail_ptr); + sring_stat = __le32_to_cpu(htt_stats_buf->consumer_empty__producer_full); + tail_ptr = __le32_to_cpu(htt_stats_buf->prefetch_count__internal_tail_ptr); + + len += scnprintf(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "ring_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_RING_ID)); + len += scnprintf(buf + len, buf_len - len, "arena = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_ARENA)); + len += scnprintf(buf + len, buf_len - len, "ep = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_EP)); + len += scnprintf(buf + len, buf_len - len, "base_addr_lsb = 0x%x\n", + le32_to_cpu(htt_stats_buf->base_addr_lsb)); + len += scnprintf(buf + len, buf_len - len, "base_addr_msb = 0x%x\n", + le32_to_cpu(htt_stats_buf->base_addr_msb)); + len += scnprintf(buf + len, buf_len - len, "ring_size = %u\n", + le32_to_cpu(htt_stats_buf->ring_size)); + len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", + le32_to_cpu(htt_stats_buf->elem_size)); + len += scnprintf(buf + len, buf_len - len, "num_avail_words = %u\n", + u32_get_bits(avail_words, + ATH12K_HTT_SRING_STATS_NUM_AVAIL_WORDS)); + len += scnprintf(buf + len, buf_len - len, "num_valid_words = %u\n", + u32_get_bits(avail_words, + ATH12K_HTT_SRING_STATS_NUM_VALID_WORDS)); + len += scnprintf(buf + len, buf_len - len, "head_ptr = %u\n", + u32_get_bits(head_tail_ptr, ATH12K_HTT_SRING_STATS_HEAD_PTR)); + len += scnprintf(buf + len, buf_len - len, "tail_ptr = %u\n", + u32_get_bits(head_tail_ptr, ATH12K_HTT_SRING_STATS_TAIL_PTR)); + len += scnprintf(buf + len, buf_len - len, "consumer_empty = %u\n", + u32_get_bits(sring_stat, + ATH12K_HTT_SRING_STATS_CONSUMER_EMPTY)); + len += scnprintf(buf + len, buf_len - len, "producer_full = %u\n", + u32_get_bits(head_tail_ptr, + ATH12K_HTT_SRING_STATS_PRODUCER_FULL)); + len += scnprintf(buf + len, buf_len - len, "prefetch_count = %u\n", + u32_get_bits(tail_ptr, ATH12K_HTT_SRING_STATS_PREFETCH_COUNT)); + len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %u\n\n", + u32_get_bits(tail_ptr, + ATH12K_HTT_SRING_STATS_INTERNAL_TAIL_PTR)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sfm_cmn_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sfm_cmn_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "buf_total = %u\n", + le32_to_cpu(htt_stats_buf->buf_total)); + len += scnprintf(buf + len, buf_len - len, "mem_empty = %u\n", + le32_to_cpu(htt_stats_buf->mem_empty)); + len += scnprintf(buf + len, buf_len - len, "deallocate_bufs = %u\n", + le32_to_cpu(htt_stats_buf->deallocate_bufs)); + len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", + le32_to_cpu(htt_stats_buf->num_records)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sfm_client_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sfm_client_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "client_id = %u\n", + le32_to_cpu(htt_stats_buf->client_id)); + len += scnprintf(buf + len, buf_len - len, "buf_min = %u\n", + le32_to_cpu(htt_stats_buf->buf_min)); + len += scnprintf(buf + len, buf_len - len, "buf_max = %u\n", + le32_to_cpu(htt_stats_buf->buf_max)); + len += scnprintf(buf + len, buf_len - len, "buf_busy = %u\n", + le32_to_cpu(htt_stats_buf->buf_busy)); + len += scnprintf(buf + len, buf_len - len, "buf_alloc = %u\n", + le32_to_cpu(htt_stats_buf->buf_alloc)); + len += scnprintf(buf + len, buf_len - len, "buf_avail = %u\n", + le32_to_cpu(htt_stats_buf->buf_avail)); + len += scnprintf(buf + len, buf_len - len, "num_users = %u\n\n", + le32_to_cpu(htt_stats_buf->num_users)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sfm_client_user_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sfm_client_user_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV:\n"); + len += print_array_to_buf(buf, len, "dwords_used_by_user_n", + htt_stats_buf->dwords_used_by_user_n, + num_elems, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_mu_mimo_sch_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_mu_mimo_sch_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u8 i; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_MU_MIMO_SCH_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_posted = %u\n", + le32_to_cpu(htt_stats_buf->mu_mimo_sch_posted)); + len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_failed = %u\n", + le32_to_cpu(htt_stats_buf->mu_mimo_sch_failed)); + len += scnprintf(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n", + le32_to_cpu(htt_stats_buf->mu_mimo_ppdu_posted)); + len += scnprintf(buf + len, buf_len - len, + "\nac_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0, + le32_to_cpu(htt_stats_buf->ac_mu_mimo_per_grp_sz[0])); + for (i = 1; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_sch_posted_per_group_index %u ", i); + len += scnprintf(buf + len, buf_len - len, + "(TOTAL STREAMS = %u) = %u\n", i + 1, + le32_to_cpu(htt_stats_buf->ac_mu_mimo_per_grp_sz[i])); + } + + for (i = 0; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_sch_posted_per_group_index %u ", + i + ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS); + len += scnprintf(buf + len, buf_len - len, + "(TOTAL STREAMS = %u) = %u\n", + i + ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS + 1, + le32_to_cpu(htt_stats_buf->ac_mu_mimo_grp_sz_ext[i])); + } + + len += scnprintf(buf + len, buf_len - len, + "\nax_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0, + le32_to_cpu(htt_stats_buf->ax_mu_mimo_per_grp_sz[0])); + for (i = 1; i < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_sch_posted_per_group_index %u ", i); + len += scnprintf(buf + len, buf_len - len, + "(TOTAL STREAMS = %u) = %u\n", i + 1, + le32_to_cpu(htt_stats_buf->ax_mu_mimo_per_grp_sz[i])); + } + + len += scnprintf(buf + len, buf_len - len, + "\nbe_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0, + le32_to_cpu(htt_stats_buf->be_mu_mimo_per_grp_sz[0])); + for (i = 1; i < ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "be_mu_mimo_sch_posted_per_group_index %u ", i); + len += scnprintf(buf + len, buf_len - len, + "(TOTAL STREAMS = %u) = %u\n", i + 1, + le32_to_cpu(htt_stats_buf->be_mu_mimo_per_grp_sz[i])); + } + + len += scnprintf(buf + len, buf_len - len, "\n11ac MU_MIMO SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_sch_nusers_"); + len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ac_mu_mimo_sch_nusers[i])); + } + + len += scnprintf(buf + len, buf_len - len, "\n11ax MU_MIMO SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_sch_nusers_"); + len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_mu_mimo_sch_nusers[i])); + } + + len += scnprintf(buf + len, buf_len - len, "\n11be MU_MIMO SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_sch_nusers_"); + len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i, + le32_to_cpu(htt_stats_buf->be_mu_mimo_sch_nusers[i])); + } + + len += scnprintf(buf + len, buf_len - len, "\n11ax OFDMA SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_OFDMA_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ax_ofdma_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ofdma_sch_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_ofdma_basic_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_ofdma_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_ofdma_bsr_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_ofdma_bsr_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_ofdma_bar_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_ofdma_bar_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_ofdma_brp_sch_nusers_%u = %u\n\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_ofdma_brp_nusers[i])); + } + + len += scnprintf(buf + len, buf_len - len, "11ax UL MUMIMO SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ax_ul_mumimo_basic_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_mumimo_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_mumimo_brp_sch_nusers_%u = %u\n\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_mumimo_brp_nusers[i])); + } + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_mumimo_grp_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_mumimo_grp_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + int j; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_MUMIMO_GRP_STATS:\n"); + len += print_array_to_buf(buf, len, + "dl_mumimo_grp_tputs_observed (per bin = 300 mbps)", + htt_stats_buf->dl_mumimo_grp_tputs, + ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS, "\n"); + len += print_array_to_buf(buf, len, "dl_mumimo_grp eligible", + htt_stats_buf->dl_mumimo_grp_eligible, + ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n"); + len += print_array_to_buf(buf, len, "dl_mumimo_grp_ineligible", + htt_stats_buf->dl_mumimo_grp_ineligible, + ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n"); + len += scnprintf(buf + len, buf_len - len, "dl_mumimo_grp_invalid:\n"); + for (j = 0; j < ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ; j++) { + len += scnprintf(buf + len, buf_len - len, "grp_id = %u", j); + len += print_array_to_buf(buf, len, "", + htt_stats_buf->dl_mumimo_grp_invalid, + ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE, + "\n"); + } + + len += print_array_to_buf(buf, len, "ul_mumimo_grp_best_grp_size", + htt_stats_buf->ul_mumimo_grp_best_grp_size, + ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n"); + len += print_array_to_buf_index(buf, len, "ul_mumimo_grp_best_num_usrs = ", 1, + htt_stats_buf->ul_mumimo_grp_best_usrs, + ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS, "\n"); + len += print_array_to_buf(buf, len, + "ul_mumimo_grp_tputs_observed (per bin = 300 mbps)", + htt_stats_buf->ul_mumimo_grp_tputs, + ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_mpdu_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 user_index; + u32 tx_sched_mode; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + user_index = __le32_to_cpu(htt_stats_buf->user_index); + tx_sched_mode = __le32_to_cpu(htt_stats_buf->tx_sched_mode); + + if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC) { + if (!user_index) + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_MU_MIMO_AC_MPDU_STATS:\n"); + + if (user_index < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS) { + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdus_queued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_queued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdus_tried_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_tried_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdus_failed_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_failed_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdus_requeued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_requeued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_err_no_ba_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->err_no_ba_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdu_underrun_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdu_underrun_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_ampdu_underrun_usr_%u = %u\n\n", + user_index, + le32_to_cpu(htt_stats_buf->ampdu_underrun_usr)); + } + } + + if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX) { + if (!user_index) + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_MU_MIMO_AX_MPDU_STATS:\n"); + + if (user_index < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS) { + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdus_queued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_queued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdus_tried_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_tried_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdus_failed_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_failed_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdus_requeued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_requeued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_err_no_ba_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->err_no_ba_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdu_underrun_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdu_underrun_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_ampdu_underrun_usr_%u = %u\n\n", + user_index, + le32_to_cpu(htt_stats_buf->ampdu_underrun_usr)); + } + } + + if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX) { + if (!user_index) + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_AX_MU_OFDMA_MPDU_STATS:\n"); + + if (user_index < ATH12K_HTT_TX_NUM_OFDMA_USER_STATS) { + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdus_queued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_queued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdus_tried_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_tried_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdus_failed_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_failed_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdus_requeued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_requeued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_err_no_ba_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->err_no_ba_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdu_underrun_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdu_underrun_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_ampdu_underrun_usr_%u = %u\n\n", + user_index, + le32_to_cpu(htt_stats_buf->ampdu_underrun_usr)); + } + } + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_cca_stats_hist_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_cca_stats_hist_v1_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_CCA_STATS_HIST_TLV :\n"); + len += scnprintf(buf + len, buf_len - len, "chan_num = %u\n", + le32_to_cpu(htt_stats_buf->chan_num)); + len += scnprintf(buf + len, buf_len - len, "num_records = %u\n", + le32_to_cpu(htt_stats_buf->num_records)); + len += scnprintf(buf + len, buf_len - len, "valid_cca_counters_bitmap = 0x%x\n", + le32_to_cpu(htt_stats_buf->valid_cca_counters_bitmap)); + len += scnprintf(buf + len, buf_len - len, "collection_interval = %u\n\n", + le32_to_cpu(htt_stats_buf->collection_interval)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_stats_cca_counters_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_stats_cca_counters_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_PDEV_STATS_CCA_COUNTERS_TLV:(in usec)\n"); + len += scnprintf(buf + len, buf_len - len, "tx_frame_usec = %u\n", + le32_to_cpu(htt_stats_buf->tx_frame_usec)); + len += scnprintf(buf + len, buf_len - len, "rx_frame_usec = %u\n", + le32_to_cpu(htt_stats_buf->rx_frame_usec)); + len += scnprintf(buf + len, buf_len - len, "rx_clear_usec = %u\n", + le32_to_cpu(htt_stats_buf->rx_clear_usec)); + len += scnprintf(buf + len, buf_len - len, "my_rx_frame_usec = %u\n", + le32_to_cpu(htt_stats_buf->my_rx_frame_usec)); + len += scnprintf(buf + len, buf_len - len, "usec_cnt = %u\n", + le32_to_cpu(htt_stats_buf->usec_cnt)); + len += scnprintf(buf + len, buf_len - len, "med_rx_idle_usec = %u\n", + le32_to_cpu(htt_stats_buf->med_rx_idle_usec)); + len += scnprintf(buf + len, buf_len - len, "med_tx_idle_global_usec = %u\n", + le32_to_cpu(htt_stats_buf->med_tx_idle_global_usec)); + len += scnprintf(buf + len, buf_len - len, "cca_obss_usec = %u\n\n", + le32_to_cpu(htt_stats_buf->cca_obss_usec)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_obss_pd_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_obss_pd_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u8 i; + static const char *access_cat_names[ATH12K_HTT_NUM_AC_WMM] = {"best effort", + "background", + "video", "voice"}; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_OBSS_PD_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "num_spatial_reuse_tx = %u\n", + le32_to_cpu(htt_stats_buf->num_sr_tx_transmissions)); + len += scnprintf(buf + len, buf_len - len, + "num_spatial_reuse_opportunities = %u\n", + le32_to_cpu(htt_stats_buf->num_spatial_reuse_opportunities)); + len += scnprintf(buf + len, buf_len - len, "num_non_srg_opportunities = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_opportunities)); + len += scnprintf(buf + len, buf_len - len, "num_non_srg_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_ppdu_tried)); + len += scnprintf(buf + len, buf_len - len, "num_non_srg_ppdu_success = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_ppdu_success)); + len += scnprintf(buf + len, buf_len - len, "num_srg_opportunities = %u\n", + le32_to_cpu(htt_stats_buf->num_srg_opportunities)); + len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_srg_ppdu_tried)); + len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_success = %u\n", + le32_to_cpu(htt_stats_buf->num_srg_ppdu_success)); + len += scnprintf(buf + len, buf_len - len, "num_psr_opportunities = %u\n", + le32_to_cpu(htt_stats_buf->num_psr_opportunities)); + len += scnprintf(buf + len, buf_len - len, "num_psr_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_psr_ppdu_tried)); + len += scnprintf(buf + len, buf_len - len, "num_psr_ppdu_success = %u\n", + le32_to_cpu(htt_stats_buf->num_psr_ppdu_success)); + len += scnprintf(buf + len, buf_len - len, "min_duration_check_flush_cnt = %u\n", + le32_to_cpu(htt_stats_buf->num_obss_min_dur_check_flush_cnt)); + len += scnprintf(buf + len, buf_len - len, "sr_ppdu_abort_flush_cnt = %u\n\n", + le32_to_cpu(htt_stats_buf->num_sr_ppdu_abort_flush_cnt)); + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_OBSS_PD_PER_AC_STATS:\n"); + for (i = 0; i < ATH12K_HTT_NUM_AC_WMM; i++) { + len += scnprintf(buf + len, buf_len - len, "Access Category %u (%s)\n", + i, access_cat_names[i]); + len += scnprintf(buf + len, buf_len - len, + "num_non_srg_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_tried_per_ac[i])); + len += scnprintf(buf + len, buf_len - len, + "num_non_srg_ppdu_success = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_success_ac[i])); + len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_srg_tried_per_ac[i])); + len += scnprintf(buf + len, buf_len - len, + "num_srg_ppdu_success = %u\n\n", + le32_to_cpu(htt_stats_buf->num_srg_success_per_ac[i])); + } + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_dmac_reset_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_dmac_reset_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u64 time; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_DMAC_RESET_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "reset_count = %u\n", + le32_to_cpu(htt_stats_buf->reset_count)); + time = ath12k_le32hilo_to_u64(htt_stats_buf->reset_time_hi_ms, + htt_stats_buf->reset_time_lo_ms); + len += scnprintf(buf + len, buf_len - len, "reset_time_ms = %llu\n", time); + + time = ath12k_le32hilo_to_u64(htt_stats_buf->disengage_time_hi_ms, + htt_stats_buf->disengage_time_lo_ms); + len += scnprintf(buf + len, buf_len - len, "disengage_time_ms = %llu\n", time); + + time = ath12k_le32hilo_to_u64(htt_stats_buf->engage_time_hi_ms, + htt_stats_buf->engage_time_lo_ms); + len += scnprintf(buf + len, buf_len - len, "engage_time_ms = %llu\n", time); + + len += scnprintf(buf + len, buf_len - len, "disengage_count = %u\n", + le32_to_cpu(htt_stats_buf->disengage_count)); + len += scnprintf(buf + len, buf_len - len, "engage_count = %u\n", + le32_to_cpu(htt_stats_buf->engage_count)); + len += scnprintf(buf + len, buf_len - len, "drain_dest_ring_mask = 0x%x\n\n", + le32_to_cpu(htt_stats_buf->drain_dest_ring_mask)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_sched_algo_ofdma_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_sched_algo_ofdma_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_SCHED_ALGO_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += print_array_to_buf(buf, len, "rate_based_dlofdma_enabled_count", + htt_stats_buf->rate_based_dlofdma_enabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "rate_based_dlofdma_disabled_count", + htt_stats_buf->rate_based_dlofdma_disabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "rate_based_dlofdma_probing_count", + htt_stats_buf->rate_based_dlofdma_disabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "rate_based_dlofdma_monitoring_count", + htt_stats_buf->rate_based_dlofdma_monitor_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_enabled_count", + htt_stats_buf->chan_acc_lat_based_dlofdma_enabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_disabled_count", + htt_stats_buf->chan_acc_lat_based_dlofdma_disabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_monitoring_count", + htt_stats_buf->chan_acc_lat_based_dlofdma_monitor_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "downgrade_to_dl_su_ru_alloc_fail", + htt_stats_buf->downgrade_to_dl_su_ru_alloc_fail, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "candidate_list_single_user_disable_ofdma", + htt_stats_buf->candidate_list_single_user_disable_ofdma, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "dl_cand_list_dropped_high_ul_qos_weight", + htt_stats_buf->dl_cand_list_dropped_high_ul_qos_weight, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "ax_dlofdma_disabled_due_to_pipelining", + htt_stats_buf->ax_dlofdma_disabled_due_to_pipelining, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "dlofdma_disabled_su_only_eligible", + htt_stats_buf->dlofdma_disabled_su_only_eligible, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "dlofdma_disabled_consec_no_mpdus_tried", + htt_stats_buf->dlofdma_disabled_consec_no_mpdus_tried, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "dlofdma_disabled_consec_no_mpdus_success", + htt_stats_buf->dlofdma_disabled_consec_no_mpdus_success, + ATH12K_HTT_NUM_AC_WMM, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_rate_stats_be_ofdma_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_rate_stats_be_ofdma_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + u8 i; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_RATE_STATS_BE_OFDMA_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "be_ofdma_tx_ldpc = %u\n", + le32_to_cpu(htt_stats_buf->be_ofdma_tx_ldpc)); + len += print_array_to_buf(buf, len, "be_ofdma_tx_mcs", + htt_stats_buf->be_ofdma_tx_mcs, + ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS, "\n"); + len += print_array_to_buf(buf, len, "be_ofdma_eht_sig_mcs", + htt_stats_buf->be_ofdma_eht_sig_mcs, + ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS, "\n"); + len += scnprintf(buf + len, buf_len - len, "be_ofdma_tx_ru_size = "); + for (i = 0; i < ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS; i++) + len += scnprintf(buf + len, buf_len - len, " %s:%u ", + ath12k_htt_be_tx_rx_ru_size_to_str(i), + le32_to_cpu(htt_stats_buf->be_ofdma_tx_ru_size[i])); + len += scnprintf(buf + len, buf_len - len, "\n"); + len += print_array_to_buf_index(buf, len, "be_ofdma_tx_nss = ", 1, + htt_stats_buf->be_ofdma_tx_nss, + ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, + "\n"); + len += print_array_to_buf(buf, len, "be_ofdma_tx_bw", + htt_stats_buf->be_ofdma_tx_bw, + ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS, "\n"); + for (i = 0; i < ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS; i++) { + len += scnprintf(buf + len, buf_len - len, + "be_ofdma_tx_gi[%u]", i); + len += print_array_to_buf(buf, len, "", htt_stats_buf->gi[i], + ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS, "\n"); + } + len += scnprintf(buf + len, buf_len - len, "\n"); + + stats_req->buf_len = len; +} + static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *tag_buf, void *user_data) @@ -1552,6 +2801,83 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_TX_DE_COMPL_STATS_TAG: ath12k_htt_print_tx_de_compl_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_TX_SELFGEN_CMN_STATS_TAG: + ath12k_htt_print_tx_selfgen_cmn_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AC_STATS_TAG: + ath12k_htt_print_tx_selfgen_ac_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AX_STATS_TAG: + ath12k_htt_print_tx_selfgen_ax_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_BE_STATS_TAG: + ath12k_htt_print_tx_selfgen_be_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AC_ERR_STATS_TAG: + ath12k_htt_print_tx_selfgen_ac_err_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AX_ERR_STATS_TAG: + ath12k_htt_print_tx_selfgen_ax_err_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG: + ath12k_htt_print_tx_selfgen_be_err_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AC_SCHED_STATUS_STATS_TAG: + ath12k_htt_print_tx_selfgen_ac_sched_status_stats_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_TX_SELFGEN_AX_SCHED_STATUS_STATS_TAG: + ath12k_htt_print_tx_selfgen_ax_sched_status_stats_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG: + ath12k_htt_print_tx_selfgen_be_sched_status_stats_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_STRING_TAG: + ath12k_htt_print_stats_string_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SRING_STATS_TAG: + ath12k_htt_print_sring_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SFM_CMN_TAG: + ath12k_htt_print_sfm_cmn_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SFM_CLIENT_TAG: + ath12k_htt_print_sfm_client_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SFM_CLIENT_USER_TAG: + ath12k_htt_print_sfm_client_user_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG: + ath12k_htt_print_tx_pdev_mu_mimo_sch_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_MUMIMO_GRP_STATS_TAG: + ath12k_htt_print_tx_pdev_mumimo_grp_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_MPDU_STATS_TAG: + ath12k_htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_CCA_1SEC_HIST_TAG: + case HTT_STATS_PDEV_CCA_100MSEC_HIST_TAG: + case HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG: + ath12k_htt_print_pdev_cca_stats_hist_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_CCA_COUNTERS_TAG: + ath12k_htt_print_pdev_stats_cca_counters_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_OBSS_PD_TAG: + ath12k_htt_print_pdev_obss_pd_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_DMAC_RESET_STATS_TAG: + ath12k_htt_print_dmac_reset_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG: + ath12k_htt_print_pdev_sched_algo_ofdma_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG: + ath12k_htt_print_tx_pdev_rate_stats_be_ofdma_tlv(tag_buf, len, stats_req); + break; default: break; } @@ -1627,9 +2953,9 @@ static ssize_t ath12k_read_htt_stats_type(struct file *file, char buf[32]; size_t len; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); type = ar->debug.htt_stats.type; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); len = scnprintf(buf, sizeof(buf), "%u\n", type); @@ -1662,7 +2988,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file, type >= ATH12K_DBG_HTT_NUM_EXT_STATS) return -EINVAL; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); ar->debug.htt_stats.type = type; ar->debug.htt_stats.cfg_param[0] = cfg_param[0]; @@ -1670,7 +2996,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file, ar->debug.htt_stats.cfg_param[2] = cfg_param[2]; ar->debug.htt_stats.cfg_param[3] = cfg_param[3]; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return count; } @@ -1691,7 +3017,7 @@ static int ath12k_debugfs_htt_stats_req(struct ath12k *ar) int ret, pdev_id; struct htt_ext_stats_cfg_params cfg_params = { 0 }; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); init_completion(&stats_req->htt_stats_rcvd); @@ -1741,7 +3067,7 @@ static int ath12k_open_htt_stats(struct inode *inode, if (type == ATH12K_DBG_HTT_EXT_STATS_RESET) return -EPERM; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); if (ah->state != ATH12K_HW_STATE_ON) { ret = -ENETDOWN; @@ -1776,14 +3102,14 @@ static int ath12k_open_htt_stats(struct inode *inode, file->private_data = stats_req; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return 0; out: kfree(stats_req); ar->debug.htt_stats.stats_req = NULL; err_unlock: - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return ret; } @@ -1793,10 +3119,10 @@ static int ath12k_release_htt_stats(struct inode *inode, { struct ath12k *ar = inode->i_private; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); kfree(file->private_data); ar->debug.htt_stats.stats_req = NULL; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return 0; } @@ -1840,7 +3166,7 @@ static ssize_t ath12k_write_htt_stats_reset(struct file *file, type == ATH12K_DBG_HTT_EXT_STATS_RESET) return -E2BIG; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); cfg_params.cfg0 = HTT_STAT_DEFAULT_RESET_START_OFFSET; param_pos = (type >> 5) + 1; @@ -1866,12 +3192,12 @@ static ssize_t ath12k_write_htt_stats_reset(struct file *file, 0ULL); if (ret) { ath12k_warn(ar->ab, "failed to send htt stats request: %d\n", ret); - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return ret; } ar->debug.htt_stats.reset = type; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return count; } diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index d52b26b23e65..ac86cab234ec 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -123,12 +123,21 @@ struct ath12k_htt_extd_stats_msg { /* htt_dbg_ext_stats_type */ enum ath12k_dbg_htt_ext_stats_type { - ATH12K_DBG_HTT_EXT_STATS_RESET = 0, - ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1, - ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4, - ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5, - ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6, - ATH12K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8, + ATH12K_DBG_HTT_EXT_STATS_RESET = 0, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4, + ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6, + ATH12K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8, + ATH12K_DBG_HTT_EXT_STATS_TX_SELFGEN_INFO = 12, + ATH12K_DBG_HTT_EXT_STATS_SRNG_INFO = 15, + ATH12K_DBG_HTT_EXT_STATS_SFM_INFO = 16, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_MU = 17, + ATH12K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19, + ATH12K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23, + ATH12K_DBG_HTT_EXT_STATS_SOC_ERROR = 45, + ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49, + ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, @@ -139,6 +148,7 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1, HTT_STATS_TX_PDEV_SIFS_TAG = 2, HTT_STATS_TX_PDEV_FLUSH_TAG = 3, + HTT_STATS_STRING_TAG = 5, HTT_STATS_TX_TQM_GEN_MPDU_TAG = 11, HTT_STATS_TX_TQM_LIST_MPDU_TAG = 12, HTT_STATS_TX_TQM_LIST_MPDU_CNT_TAG = 13, @@ -151,22 +161,47 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_DE_ENQUEUE_PACKETS_TAG = 21, HTT_STATS_TX_DE_ENQUEUE_DISCARD_TAG = 22, HTT_STATS_TX_DE_CMN_TAG = 23, + HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG = 25, + HTT_STATS_SFM_CMN_TAG = 26, + HTT_STATS_SRING_STATS_TAG = 27, HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG = 36, HTT_STATS_TX_SCHED_CMN_TAG = 37, HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG = 39, + HTT_STATS_SFM_CLIENT_USER_TAG = 41, + HTT_STATS_SFM_CLIENT_TAG = 42, HTT_STATS_TX_TQM_ERROR_STATS_TAG = 43, HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG = 44, + HTT_STATS_TX_SELFGEN_AC_ERR_STATS_TAG = 46, + HTT_STATS_TX_SELFGEN_CMN_STATS_TAG = 47, + HTT_STATS_TX_SELFGEN_AC_STATS_TAG = 48, + HTT_STATS_TX_SELFGEN_AX_STATS_TAG = 49, + HTT_STATS_TX_SELFGEN_AX_ERR_STATS_TAG = 50, HTT_STATS_HW_INTR_MISC_TAG = 54, HTT_STATS_HW_PDEV_ERRS_TAG = 56, HTT_STATS_TX_DE_COMPL_STATS_TAG = 65, HTT_STATS_WHAL_TX_TAG = 66, HTT_STATS_TX_PDEV_SIFS_HIST_TAG = 67, + HTT_STATS_PDEV_CCA_1SEC_HIST_TAG = 70, + HTT_STATS_PDEV_CCA_100MSEC_HIST_TAG = 71, + HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG = 72, + HTT_STATS_PDEV_CCA_COUNTERS_TAG = 73, + HTT_STATS_TX_PDEV_MPDU_STATS_TAG = 74, HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG = 86, HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG = 87, + HTT_STATS_PDEV_OBSS_PD_TAG = 88, HTT_STATS_HW_WAR_TAG = 89, HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG = 100, HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102, + HTT_STATS_TX_SELFGEN_AC_SCHED_STATUS_STATS_TAG = 111, + HTT_STATS_TX_SELFGEN_AX_SCHED_STATUS_STATS_TAG = 112, HTT_STATS_MU_PPDU_DIST_TAG = 129, + HTT_STATS_TX_PDEV_MUMIMO_GRP_STATS_TAG = 130, + HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG = 135, + HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG = 137, + HTT_STATS_TX_SELFGEN_BE_STATS_TAG = 138, + HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG = 139, + HTT_STATS_DMAC_RESET_STATS_TAG = 155, + HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG = 165, HTT_STATS_MAX_TAG, }; @@ -690,4 +725,401 @@ struct ath12k_htt_tx_de_compl_stats_tlv { __le32 tqm_bypass_frame; } __packed; +enum ath12k_htt_tx_mumimo_grp_invalid_reason_code_stats { + ATH12K_HTT_TX_MUMIMO_GRP_VALID, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_NUM_MU_USERS_EXCEEDED_MU_MAX_USERS, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_SCHED_ALGO_NOT_MU_COMPATIBLE_GID, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_NON_PRIMARY_GRP, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_ZERO_CANDIDATES, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MORE_CANDIDATES, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_SIZE_EXCEED_NSS, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_INELIGIBLE, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_EFF_MU_TPUT_OMBPS, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MAX_REASON_CODE, +}; + +#define ATH12K_HTT_NUM_AC_WMM 0x4 +#define ATH12K_HTT_MAX_NUM_SBT_INTR 4 +#define ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS 4 +#define ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS 8 +#define ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS 8 +#define ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS 7 +#define ATH12K_HTT_TX_NUM_OFDMA_USER_STATS 74 +#define ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS 8 +#define ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ 8 +#define ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS 10 + +#define ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE \ + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MAX_REASON_CODE +#define ATH12K_HTT_TX_NUM_MUMIMO_GRP_INVALID_WORDS \ + (ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ * ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE) + +struct ath12k_htt_tx_selfgen_cmn_stats_tlv { + __le32 mac_id__word; + __le32 su_bar; + __le32 rts; + __le32 cts2self; + __le32 qos_null; + __le32 delayed_bar_1; + __le32 delayed_bar_2; + __le32 delayed_bar_3; + __le32 delayed_bar_4; + __le32 delayed_bar_5; + __le32 delayed_bar_6; + __le32 delayed_bar_7; +} __packed; + +struct ath12k_htt_tx_selfgen_ac_stats_tlv { + __le32 ac_su_ndpa; + __le32 ac_su_ndp; + __le32 ac_mu_mimo_ndpa; + __le32 ac_mu_mimo_ndp; + __le32 ac_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS - 1]; +} __packed; + +struct ath12k_htt_tx_selfgen_ax_stats_tlv { + __le32 ax_su_ndpa; + __le32 ax_su_ndp; + __le32 ax_mu_mimo_ndpa; + __le32 ax_mu_mimo_ndp; + __le32 ax_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1]; + __le32 ax_basic_trigger; + __le32 ax_bsr_trigger; + __le32 ax_mu_bar_trigger; + __le32 ax_mu_rts_trigger; + __le32 ax_ulmumimo_trigger; +} __packed; + +struct ath12k_htt_tx_selfgen_be_stats_tlv { + __le32 be_su_ndpa; + __le32 be_su_ndp; + __le32 be_mu_mimo_ndpa; + __le32 be_mu_mimo_ndp; + __le32 be_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1]; + __le32 be_basic_trigger; + __le32 be_bsr_trigger; + __le32 be_mu_bar_trigger; + __le32 be_mu_rts_trigger; + __le32 be_ulmumimo_trigger; + __le32 be_su_ndpa_queued; + __le32 be_su_ndp_queued; + __le32 be_mu_mimo_ndpa_queued; + __le32 be_mu_mimo_ndp_queued; + __le32 be_mu_mimo_brpoll_queued[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1]; + __le32 be_ul_mumimo_trigger[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; +} __packed; + +struct ath12k_htt_tx_selfgen_ac_err_stats_tlv { + __le32 ac_su_ndp_err; + __le32 ac_su_ndpa_err; + __le32 ac_mu_mimo_ndpa_err; + __le32 ac_mu_mimo_ndp_err; + __le32 ac_mu_mimo_brp1_err; + __le32 ac_mu_mimo_brp2_err; + __le32 ac_mu_mimo_brp3_err; +} __packed; + +struct ath12k_htt_tx_selfgen_ax_err_stats_tlv { + __le32 ax_su_ndp_err; + __le32 ax_su_ndpa_err; + __le32 ax_mu_mimo_ndpa_err; + __le32 ax_mu_mimo_ndp_err; + __le32 ax_mu_mimo_brp_err[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1]; + __le32 ax_basic_trigger_err; + __le32 ax_bsr_trigger_err; + __le32 ax_mu_bar_trigger_err; + __le32 ax_mu_rts_trigger_err; + __le32 ax_ulmumimo_trigger_err; +} __packed; + +struct ath12k_htt_tx_selfgen_be_err_stats_tlv { + __le32 be_su_ndp_err; + __le32 be_su_ndpa_err; + __le32 be_mu_mimo_ndpa_err; + __le32 be_mu_mimo_ndp_err; + __le32 be_mu_mimo_brp_err[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1]; + __le32 be_basic_trigger_err; + __le32 be_bsr_trigger_err; + __le32 be_mu_bar_trigger_err; + __le32 be_mu_rts_trigger_err; + __le32 be_ulmumimo_trigger_err; + __le32 be_mu_mimo_brp_err_num_cbf_rxd[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; + __le32 be_su_ndpa_flushed; + __le32 be_su_ndp_flushed; + __le32 be_mu_mimo_ndpa_flushed; + __le32 be_mu_mimo_ndp_flushed; + __le32 be_mu_mimo_brpoll_flushed[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1]; + __le32 be_ul_mumimo_trigger_err[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; +} __packed; + +enum ath12k_htt_tx_selfgen_sch_tsflag_error_stats { + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_FLUSH_RCVD_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_FILT_SCHED_CMD_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_MISMATCH_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_CBF_MIMO_CTRL_MISMATCH_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_CBF_BW_MISMATCH_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RETRY_COUNT_FAIL_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_TOO_LATE_RECEIVED_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_SIFS_STALL_NO_NEXT_CMD_ERR, + + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS +}; + +struct ath12k_htt_tx_selfgen_ac_sched_status_stats_tlv { + __le32 ac_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ac_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ac_mu_mimo_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_mu_mimo_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; +} __packed; + +struct ath12k_htt_tx_selfgen_ax_sched_status_stats_tlv { + __le32 ax_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_mu_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_mu_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_mu_bar_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_mu_bar_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_basic_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_basic_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_ulmumimo_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_ulmumimo_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; +} __packed; + +struct ath12k_htt_tx_selfgen_be_sched_status_stats_tlv { + __le32 be_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_mu_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_mu_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_mu_bar_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_mu_bar_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_basic_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_basic_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_ulmumimo_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_ulmumimo_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; +} __packed; + +struct ath12k_htt_stats_string_tlv { + DECLARE_FLEX_ARRAY(__le32, data); +} __packed; + +#define ATH12K_HTT_SRING_STATS_MAC_ID GENMASK(7, 0) +#define ATH12K_HTT_SRING_STATS_RING_ID GENMASK(15, 8) +#define ATH12K_HTT_SRING_STATS_ARENA GENMASK(23, 16) +#define ATH12K_HTT_SRING_STATS_EP BIT(24) +#define ATH12K_HTT_SRING_STATS_NUM_AVAIL_WORDS GENMASK(15, 0) +#define ATH12K_HTT_SRING_STATS_NUM_VALID_WORDS GENMASK(31, 16) +#define ATH12K_HTT_SRING_STATS_HEAD_PTR GENMASK(15, 0) +#define ATH12K_HTT_SRING_STATS_TAIL_PTR GENMASK(31, 16) +#define ATH12K_HTT_SRING_STATS_CONSUMER_EMPTY GENMASK(15, 0) +#define ATH12K_HTT_SRING_STATS_PRODUCER_FULL GENMASK(31, 16) +#define ATH12K_HTT_SRING_STATS_PREFETCH_COUNT GENMASK(15, 0) +#define ATH12K_HTT_SRING_STATS_INTERNAL_TAIL_PTR GENMASK(31, 16) + +struct ath12k_htt_sring_stats_tlv { + __le32 mac_id__ring_id__arena__ep; + __le32 base_addr_lsb; + __le32 base_addr_msb; + __le32 ring_size; + __le32 elem_size; + __le32 num_avail_words__num_valid_words; + __le32 head_ptr__tail_ptr; + __le32 consumer_empty__producer_full; + __le32 prefetch_count__internal_tail_ptr; +} __packed; + +struct ath12k_htt_sfm_cmn_tlv { + __le32 mac_id__word; + __le32 buf_total; + __le32 mem_empty; + __le32 deallocate_bufs; + __le32 num_records; +} __packed; + +struct ath12k_htt_sfm_client_tlv { + __le32 client_id; + __le32 buf_min; + __le32 buf_max; + __le32 buf_busy; + __le32 buf_alloc; + __le32 buf_avail; + __le32 num_users; +} __packed; + +struct ath12k_htt_sfm_client_user_tlv { + DECLARE_FLEX_ARRAY(__le32, dwords_used_by_user_n); +} __packed; + +struct ath12k_htt_tx_pdev_mu_mimo_sch_stats_tlv { + __le32 mu_mimo_sch_posted; + __le32 mu_mimo_sch_failed; + __le32 mu_mimo_ppdu_posted; + __le32 ac_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS]; + __le32 ax_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS]; + __le32 ax_ofdma_sch_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_ofdma_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_ofdma_bsr_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_ofdma_bar_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_ofdma_brp_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_mumimo_nusers[ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS]; + __le32 ax_ul_mumimo_brp_nusers[ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS]; + __le32 ac_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS]; + __le32 ax_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS]; + __le32 be_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; + __le32 be_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; + __le32 ac_mu_mimo_grp_sz_ext[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS]; +} __packed; + +struct ath12k_htt_tx_pdev_mumimo_grp_stats_tlv { + __le32 dl_mumimo_grp_best_grp_size[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ]; + __le32 dl_mumimo_grp_best_num_usrs[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS]; + __le32 dl_mumimo_grp_eligible[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ]; + __le32 dl_mumimo_grp_ineligible[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ]; + __le32 dl_mumimo_grp_invalid[ATH12K_HTT_TX_NUM_MUMIMO_GRP_INVALID_WORDS]; + __le32 dl_mumimo_grp_tputs[ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS]; + __le32 ul_mumimo_grp_best_grp_size[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ]; + __le32 ul_mumimo_grp_best_usrs[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS]; + __le32 ul_mumimo_grp_tputs[ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS]; +} __packed; + +enum ath12k_htt_stats_tx_sched_modes { + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC = 0, + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX, + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX, + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_BE, + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_BE +}; + +struct ath12k_htt_tx_pdev_mpdu_stats_tlv { + __le32 mpdus_queued_usr; + __le32 mpdus_tried_usr; + __le32 mpdus_failed_usr; + __le32 mpdus_requeued_usr; + __le32 err_no_ba_usr; + __le32 mpdu_underrun_usr; + __le32 ampdu_underrun_usr; + __le32 user_index; + __le32 tx_sched_mode; +} __packed; + +struct ath12k_htt_pdev_stats_cca_counters_tlv { + __le32 tx_frame_usec; + __le32 rx_frame_usec; + __le32 rx_clear_usec; + __le32 my_rx_frame_usec; + __le32 usec_cnt; + __le32 med_rx_idle_usec; + __le32 med_tx_idle_global_usec; + __le32 cca_obss_usec; +} __packed; + +struct ath12k_htt_pdev_cca_stats_hist_v1_tlv { + __le32 chan_num; + __le32 num_records; + __le32 valid_cca_counters_bitmap; + __le32 collection_interval; +} __packed; + +struct ath12k_htt_pdev_obss_pd_stats_tlv { + __le32 num_obss_tx_ppdu_success; + __le32 num_obss_tx_ppdu_failure; + __le32 num_sr_tx_transmissions; + __le32 num_spatial_reuse_opportunities; + __le32 num_non_srg_opportunities; + __le32 num_non_srg_ppdu_tried; + __le32 num_non_srg_ppdu_success; + __le32 num_srg_opportunities; + __le32 num_srg_ppdu_tried; + __le32 num_srg_ppdu_success; + __le32 num_psr_opportunities; + __le32 num_psr_ppdu_tried; + __le32 num_psr_ppdu_success; + __le32 num_non_srg_tried_per_ac[ATH12K_HTT_NUM_AC_WMM]; + __le32 num_non_srg_success_ac[ATH12K_HTT_NUM_AC_WMM]; + __le32 num_srg_tried_per_ac[ATH12K_HTT_NUM_AC_WMM]; + __le32 num_srg_success_per_ac[ATH12K_HTT_NUM_AC_WMM]; + __le32 num_obss_min_dur_check_flush_cnt; + __le32 num_sr_ppdu_abort_flush_cnt; +} __packed; + +struct ath12k_htt_dmac_reset_stats_tlv { + __le32 reset_count; + __le32 reset_time_lo_ms; + __le32 reset_time_hi_ms; + __le32 disengage_time_lo_ms; + __le32 disengage_time_hi_ms; + __le32 engage_time_lo_ms; + __le32 engage_time_hi_ms; + __le32 disengage_count; + __le32 engage_count; + __le32 drain_dest_ring_mask; +} __packed; + +struct ath12k_htt_pdev_sched_algo_ofdma_stats_tlv { + __le32 mac_id__word; + __le32 rate_based_dlofdma_enabled_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 rate_based_dlofdma_disabled_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 rate_based_dlofdma_probing_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 rate_based_dlofdma_monitor_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 chan_acc_lat_based_dlofdma_enabled_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 chan_acc_lat_based_dlofdma_disabled_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 chan_acc_lat_based_dlofdma_monitor_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 downgrade_to_dl_su_ru_alloc_fail[ATH12K_HTT_NUM_AC_WMM]; + __le32 candidate_list_single_user_disable_ofdma[ATH12K_HTT_NUM_AC_WMM]; + __le32 dl_cand_list_dropped_high_ul_qos_weight[ATH12K_HTT_NUM_AC_WMM]; + __le32 ax_dlofdma_disabled_due_to_pipelining[ATH12K_HTT_NUM_AC_WMM]; + __le32 dlofdma_disabled_su_only_eligible[ATH12K_HTT_NUM_AC_WMM]; + __le32 dlofdma_disabled_consec_no_mpdus_tried[ATH12K_HTT_NUM_AC_WMM]; + __le32 dlofdma_disabled_consec_no_mpdus_success[ATH12K_HTT_NUM_AC_WMM]; +} __packed; + +enum ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE { + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_26, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52_26, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106_26, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_242, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484_242, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484_242, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2_484, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3_484, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x4, + ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS, +}; + +#define ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS 8 +#define ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS 16 +#define ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS 5 +#define ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS 4 +#define ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS 4 + +struct ath12k_htt_tx_pdev_rate_stats_be_ofdma_tlv { + __le32 mac_id__word; + __le32 be_ofdma_tx_ldpc; + __le32 be_ofdma_tx_mcs[ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS]; + __le32 be_ofdma_tx_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; + __le32 be_ofdma_tx_bw[ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS]; + __le32 gi[ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS][ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS]; + __le32 be_ofdma_tx_ru_size[ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS]; + __le32 be_ofdma_eht_sig_mcs[ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS]; +} __packed; + #endif diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 61aa78d8bd8c..c99e9ceb1a6e 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -327,20 +327,22 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring, } static -u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif *arvif) +u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, + struct ath12k_link_vif *arvif) { u32 bank_config = 0; + struct ath12k_vif *ahvif = arvif->ahvif; /* Only valid for raw frames with HW crypto enabled. * With SW crypto, mac80211 sets key per packet */ - if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && + if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) bank_config |= - u32_encode_bits(ath12k_dp_tx_get_encrypt_type(arvif->key_cipher), + u32_encode_bits(ath12k_dp_tx_get_encrypt_type(ahvif->key_cipher), HAL_TX_BANK_CONFIG_ENCRYPT_TYPE); - bank_config |= u32_encode_bits(arvif->tx_encap_type, + bank_config |= u32_encode_bits(ahvif->tx_encap_type, HAL_TX_BANK_CONFIG_ENCAP_TYPE); bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_SRC_BUFFER_SWAP) | u32_encode_bits(0, HAL_TX_BANK_CONFIG_LINK_META_SWAP) | @@ -355,7 +357,7 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif HAL_TX_ADDRY_EN), HAL_TX_BANK_CONFIG_ADDRY_EN); - bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(arvif->vif) ? 3 : 0, + bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(ahvif->vif) ? 3 : 0, HAL_TX_BANK_CONFIG_MESH_EN) | u32_encode_bits(arvif->vdev_id_check_en, HAL_TX_BANK_CONFIG_VDEV_ID_CHECK_EN); @@ -365,7 +367,8 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif return bank_config; } -static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab, struct ath12k_vif *arvif, +static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab, + struct ath12k_link_vif *arvif, struct ath12k_dp *dp) { int bank_id = DP_INVALID_BANK_ID; @@ -1099,9 +1102,9 @@ int ath12k_dp_htt_connect(struct ath12k_dp *dp) return 0; } -static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif) +static void ath12k_dp_update_vdev_search(struct ath12k_link_vif *arvif) { - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_STA: /* TODO: Verify the search type and flags since ast hash * is not part of peer mapv3 @@ -1120,7 +1123,7 @@ static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif) } } -void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif) +void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif) { struct ath12k_base *ab = ar->ab; @@ -1162,7 +1165,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) spin_lock_bh(&dp->rx_desc_lock); for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - desc_info = dp->spt_info->rxbaddr[i]; + desc_info = dp->rxbaddr[i]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { if (!desc_info[j].in_use) { @@ -1181,11 +1184,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) } for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - if (!dp->spt_info->rxbaddr[i]) + if (!dp->rxbaddr[i]) continue; - kfree(dp->spt_info->rxbaddr[i]); - dp->spt_info->rxbaddr[i] = NULL; + kfree(dp->rxbaddr[i]); + dp->rxbaddr[i] = NULL; } spin_unlock_bh(&dp->rx_desc_lock); @@ -1202,10 +1205,16 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) if (!skb) continue; - skb_cb = ATH12K_SKB_CB(skb); - ar = skb_cb->ar; - if (atomic_dec_and_test(&ar->dp.num_tx_pending)) - wake_up(&ar->dp.tx_empty_waitq); + /* if we are unregistering, hw would've been destroyed and + * ar is no longer valid. + */ + if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags))) { + skb_cb = ATH12K_SKB_CB(skb); + ar = skb_cb->ar; + + if (atomic_dec_and_test(&ar->dp.num_tx_pending)) + wake_up(&ar->dp.tx_empty_waitq); + } dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr, skb->len, DMA_TO_DEVICE); @@ -1220,11 +1229,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) { tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; - if (!dp->spt_info->txbaddr[tx_spt_page]) + if (!dp->txbaddr[tx_spt_page]) continue; - kfree(dp->spt_info->txbaddr[tx_spt_page]); - dp->spt_info->txbaddr[tx_spt_page] = NULL; + kfree(dp->txbaddr[tx_spt_page]); + dp->txbaddr[tx_spt_page] = NULL; } spin_unlock_bh(&dp->tx_desc_lock[pool_id]); @@ -1241,6 +1250,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) } kfree(dp->spt_info); + dp->spt_info = NULL; } static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab) @@ -1276,8 +1286,10 @@ void ath12k_dp_free(struct ath12k_base *ab) ath12k_dp_rx_reo_cmd_list_cleanup(ab); - for (i = 0; i < ab->hw_params->max_tx_ring; i++) + for (i = 0; i < ab->hw_params->max_tx_ring; i++) { kfree(dp->tx_ring[i].tx_status); + dp->tx_ring[i].tx_status = NULL; + } ath12k_dp_rx_free(ab); /* Deinit any SOC level resource */ @@ -1415,7 +1427,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i; cookie_ppt_idx = dp->rx_ppt_base + ppt_idx; - dp->spt_info->rxbaddr[i] = &rx_descs[0]; + dp->rxbaddr[i] = &rx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(cookie_ppt_idx, j); @@ -1445,7 +1457,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page; - dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0]; + dp->txbaddr[tx_spt_page] = &tx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j); diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 2fb18b83b3ee..2e05fc19410e 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -16,6 +16,7 @@ struct ath12k_base; struct ath12k_peer; struct ath12k_dp; struct ath12k_vif; +struct ath12k_link_vif; struct hal_tcl_status_ring; struct ath12k_ext_irq_grp; @@ -300,8 +301,6 @@ struct ath12k_tx_desc_info { struct ath12k_spt_info { dma_addr_t paddr; u64 *vaddr; - struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES]; - struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES]; }; struct ath12k_reo_queue_ref { @@ -352,6 +351,8 @@ struct ath12k_dp { struct ath12k_spt_info *spt_info; u32 num_spt_pages; u32 rx_ppt_base; + struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES]; + struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES]; struct list_head rx_desc_free_list; /* protects the free desc list */ spinlock_t rx_desc_lock; @@ -1799,7 +1800,7 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, struct ath12k_ext_irq_grp *irq_grp, int budget); int ath12k_dp_htt_connect(struct ath12k_dp *dp); -void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif); +void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif); void ath12k_dp_free(struct ath12k_base *ab); int ath12k_dp_alloc(struct ath12k_base *ab); void ath12k_dp_cc_config(struct ath12k_base *ab); diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 5c6749bc4039..494984133a91 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -26,15 +26,12 @@ ath12k_dp_mon_rx_populate_byte_count(const struct hal_rx_ppdu_end_user_stats *st void *ppduinfo, struct hal_rx_user_status *rx_user_status) { - u32 mpdu_ok_byte_count = __le32_to_cpu(stats->mpdu_ok_cnt); - u32 mpdu_err_byte_count = __le32_to_cpu(stats->mpdu_err_cnt); - rx_user_status->mpdu_ok_byte_count = - u32_get_bits(mpdu_ok_byte_count, - HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_OK_BYTE_COUNT); + le32_get_bits(stats->info7, + HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT); rx_user_status->mpdu_err_byte_count = - u32_get_bits(mpdu_err_byte_count, - HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_ERR_BYTE_COUNT); + le32_get_bits(stats->info8, + HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT); } static void @@ -593,12 +590,20 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, struct hal_rx_ppdu_start *ppdu_start = (struct hal_rx_ppdu_start *)tlv_data; + u64 ppdu_ts = ath12k_le32hilo_to_u64(ppdu_start->ppdu_start_ts_63_32, + ppdu_start->ppdu_start_ts_31_0); + info[0] = __le32_to_cpu(ppdu_start->info0); - ppdu_info->ppdu_id = - u32_get_bits(info[0], HAL_RX_PPDU_START_INFO0_PPDU_ID); - ppdu_info->chan_num = __le32_to_cpu(ppdu_start->chan_num); - ppdu_info->ppdu_ts = __le32_to_cpu(ppdu_start->ppdu_start_ts); + ppdu_info->ppdu_id = u32_get_bits(info[0], + HAL_RX_PPDU_START_INFO0_PPDU_ID); + + info[1] = __le32_to_cpu(ppdu_start->info1); + ppdu_info->chan_num = u32_get_bits(info[1], + HAL_RX_PPDU_START_INFO1_CHAN_NUM); + ppdu_info->freq = u32_get_bits(info[1], + HAL_RX_PPDU_START_INFO1_CHAN_FREQ); + ppdu_info->ppdu_ts = ppdu_ts; if (ppdu_info->ppdu_id != ppdu_info->last_ppdu_id) { ppdu_info->last_ppdu_id = ppdu_info->ppdu_id; @@ -726,33 +731,20 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, case HAL_PHYRX_RSSI_LEGACY: { struct hal_rx_phyrx_rssi_legacy_info *rssi = (struct hal_rx_phyrx_rssi_legacy_info *)tlv_data; - u32 reception_type = 0; - u32 rssi_legacy_info = __le32_to_cpu(rssi->rsvd[0]); info[0] = __le32_to_cpu(rssi->info0); + info[1] = __le32_to_cpu(rssi->info1); /* TODO: Please note that the combined rssi will not be accurate * in MU case. Rssi in MU needs to be retrieved from * PHYRX_OTHER_RECEIVE_INFO TLV. */ ppdu_info->rssi_comb = - u32_get_bits(info[0], - HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB); - reception_type = - u32_get_bits(rssi_legacy_info, - HAL_RX_PHYRX_RSSI_LEGACY_INFO_RSVD1_RECEPTION); - - switch (reception_type) { - case HAL_RECEPTION_TYPE_ULOFMDA: - ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA; - break; - case HAL_RECEPTION_TYPE_ULMIMO: - ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO; - break; - default: - ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU; - break; - } + u32_get_bits(info[1], + HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB); + + ppdu_info->bw = u32_get_bits(info[0], + HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW); break; } case HAL_RXPCU_PPDU_END_INFO: { @@ -860,27 +852,29 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, return HAL_RX_MON_STATUS_PPDU_NOT_DONE; } -static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar, struct sk_buff *msdu) +static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar, + struct sk_buff *head_msdu, + struct sk_buff *tail_msdu) { u32 rx_pkt_offset, l2_hdr_offset; rx_pkt_offset = ar->ab->hal.hal_desc_sz; - l2_hdr_offset = ath12k_dp_rx_h_l3pad(ar->ab, - (struct hal_rx_desc *)msdu->data); - skb_pull(msdu, rx_pkt_offset + l2_hdr_offset); + l2_hdr_offset = + ath12k_dp_rx_h_l3pad(ar->ab, (struct hal_rx_desc *)tail_msdu->data); + skb_pull(head_msdu, rx_pkt_offset + l2_hdr_offset); } static struct sk_buff * -ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, - u32 mac_id, struct sk_buff *head_msdu, +ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, u32 mac_id, + struct sk_buff *head_msdu, struct sk_buff *tail_msdu, struct ieee80211_rx_status *rxs, bool *fcs_err) { struct ath12k_base *ab = ar->ab; - struct sk_buff *msdu, *mpdu_buf, *prev_buf; - struct hal_rx_desc *rx_desc; + struct sk_buff *msdu, *mpdu_buf, *prev_buf, *head_frag_list; + struct hal_rx_desc *rx_desc, *tail_rx_desc; u8 *hdr_desc, *dest, decap_format; struct ieee80211_hdr_3addr *wh; - u32 err_bitmap; + u32 err_bitmap, frag_list_sum_len = 0; mpdu_buf = NULL; @@ -888,24 +882,30 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, goto err_merge_fail; rx_desc = (struct hal_rx_desc *)head_msdu->data; - err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc); + tail_rx_desc = (struct hal_rx_desc *)tail_msdu->data; + err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, tail_rx_desc); if (err_bitmap & HAL_RX_MPDU_ERR_FCS) *fcs_err = true; - decap_format = ath12k_dp_rx_h_decap_type(ab, rx_desc); + decap_format = ath12k_dp_rx_h_decap_type(ab, tail_rx_desc); - ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs); + ath12k_dp_rx_h_ppdu(ar, tail_rx_desc, rxs); if (decap_format == DP_RX_DECAP_TYPE_RAW) { - ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu); + ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu, tail_msdu); prev_buf = head_msdu; msdu = head_msdu->next; + head_frag_list = NULL; while (msdu) { - ath12k_dp_mon_rx_msdus_set_payload(ar, msdu); + ath12k_dp_mon_rx_msdus_set_payload(ar, msdu, tail_msdu); + + if (!head_frag_list) + head_frag_list = msdu; + frag_list_sum_len += msdu->len; prev_buf = msdu; msdu = msdu->next; } @@ -913,6 +913,12 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, prev_buf->next = NULL; skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN); + if (head_frag_list) { + skb_shinfo(head_msdu)->frag_list = head_frag_list; + head_msdu->data_len = frag_list_sum_len; + head_msdu->len += head_msdu->data_len; + head_msdu->next = NULL; + } } else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) { u8 qos_pkt = 0; @@ -929,7 +935,7 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, msdu = head_msdu; while (msdu) { - ath12k_dp_mon_rx_msdus_set_payload(ar, msdu); + ath12k_dp_mon_rx_msdus_set_payload(ar, msdu, tail_msdu); if (qos_pkt) { dest = skb_push(msdu, sizeof(__le16)); if (!dest) @@ -1135,7 +1141,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct } static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id, - struct sk_buff *head_msdu, + struct sk_buff *head_msdu, struct sk_buff *tail_msdu, struct hal_rx_mon_ppdu_info *ppduinfo, struct napi_struct *napi) { @@ -1144,7 +1150,8 @@ static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id, struct ieee80211_rx_status *rxs = &dp->rx_status; bool fcs_err = false; - mon_skb = ath12k_dp_mon_rx_merg_msdus(ar, mac_id, head_msdu, + mon_skb = ath12k_dp_mon_rx_merg_msdus(ar, mac_id, + head_msdu, tail_msdu, rxs, &fcs_err); if (!mon_skb) goto mon_deliver_fail; @@ -1252,7 +1259,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar, if (head_msdu && tail_msdu) { ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu, - ppdu_info, napi); + tail_msdu, ppdu_info, napi); } kfree(mon_mpdu); @@ -1948,15 +1955,16 @@ ath12k_dp_mon_tx_process_ppdu_info(struct ath12k *ar, int mac_id, struct dp_mon_tx_ppdu_info *tx_ppdu_info) { struct dp_mon_mpdu *tmp, *mon_mpdu; - struct sk_buff *head_msdu; + struct sk_buff *head_msdu, *tail_msdu; list_for_each_entry_safe(mon_mpdu, tmp, &tx_ppdu_info->dp_tx_mon_mpdu_list, list) { list_del(&mon_mpdu->list); head_msdu = mon_mpdu->head; + tail_msdu = mon_mpdu->tail; if (head_msdu) - ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu, + ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu, tail_msdu, &tx_ppdu_info->rx_status, napi); kfree(mon_mpdu); @@ -2165,7 +2173,7 @@ ath12k_dp_mon_rx_update_peer_rate_table_stats(struct ath12k_rx_peer_stats *rx_st } static void ath12k_dp_mon_rx_update_peer_su_stats(struct ath12k *ar, - struct ath12k_sta *arsta, + struct ath12k_link_sta *arsta, struct hal_rx_mon_ppdu_info *ppdu_info) { struct ath12k_rx_peer_stats *rx_stats = arsta->rx_stats; @@ -2321,7 +2329,8 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar, struct hal_rx_mon_ppdu_info *ppdu_info, u32 uid) { - struct ath12k_sta *arsta = NULL; + struct ath12k_sta *ahsta; + struct ath12k_link_sta *arsta; struct ath12k_rx_peer_stats *rx_stats = NULL; struct hal_rx_user_status *user_stats = &ppdu_info->userstats[uid]; struct ath12k_peer *peer; @@ -2338,7 +2347,8 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar, return; } - arsta = ath12k_sta_to_arsta(peer->sta); + ahsta = ath12k_sta_to_ahsta(peer->sta); + arsta = &ahsta->deflink; rx_stats = arsta->rx_stats; if (!rx_stats) @@ -2445,7 +2455,8 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id, struct dp_srng *mon_dst_ring; struct hal_srng *srng; struct dp_rxdma_mon_ring *buf_ring; - struct ath12k_sta *arsta = NULL; + struct ath12k_sta *ahsta = NULL; + struct ath12k_link_sta *arsta; struct ath12k_peer *peer; u64 cookie; int num_buffs_reaped = 0, srng_id, buf_id; @@ -2514,7 +2525,8 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id, } if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_SU) { - arsta = ath12k_sta_to_arsta(peer->sta); + ahsta = ath12k_sta_to_ahsta(peer->sta); + arsta = &ahsta->deflink; ath12k_dp_mon_rx_update_peer_su_stats(ar, arsta, ppdu_info); } else if ((ppdu_info->fc_valid) && diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 91e3393f7b5f..9ae579e50557 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1041,13 +1041,14 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar, struct ieee80211_ampdu_params *params) { struct ath12k_base *ab = ar->ab; - struct ath12k_sta *arsta = ath12k_sta_to_arsta(params->sta); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta); + struct ath12k_link_sta *arsta = &ahsta->deflink; int vdev_id = arsta->arvif->vdev_id; int ret; ret = ath12k_dp_rx_peer_tid_setup(ar, params->sta->addr, vdev_id, params->tid, params->buf_size, - params->ssn, arsta->pn_type); + params->ssn, arsta->ahsta->pn_type); if (ret) ath12k_warn(ab, "failed to setup rx tid %d\n", ret); @@ -1059,7 +1060,8 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar, { struct ath12k_base *ab = ar->ab; struct ath12k_peer *peer; - struct ath12k_sta *arsta = ath12k_sta_to_arsta(params->sta); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta); + struct ath12k_link_sta *arsta = &ahsta->deflink; int vdev_id = arsta->arvif->vdev_id; bool active; int ret; @@ -1091,7 +1093,7 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar, return ret; } -int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif, +int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif, const u8 *peer_addr, enum set_key_cmd key_cmd, struct ieee80211_key_conf *key) @@ -1313,7 +1315,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, struct ath12k_base *ab = ar->ab; struct ath12k_peer *peer; struct ieee80211_sta *sta; - struct ath12k_sta *arsta; + struct ath12k_sta *ahsta; + struct ath12k_link_sta *arsta; struct htt_ppdu_stats_user_rate *user_rate; struct ath12k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats; struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user]; @@ -1394,7 +1397,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, } sta = peer->sta; - arsta = ath12k_sta_to_arsta(sta); + ahsta = ath12k_sta_to_ahsta(sta); + arsta = &ahsta->deflink; memset(&arsta->txrate, 0, sizeof(arsta->txrate)); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index eb1f92559179..bfd4f814553e 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -88,7 +88,7 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar, struct ieee80211_ampdu_params *params); int ath12k_dp_rx_ampdu_stop(struct ath12k *ar, struct ieee80211_ampdu_params *params); -int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif, +int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif, const u8 *peer_addr, enum set_key_cmd key_cmd, struct ieee80211_key_conf *key); diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 44406e0b4a34..a8d341a6df01 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -10,7 +10,7 @@ #include "hw.h" static enum hal_tcl_encap_type -ath12k_dp_tx_get_encap_type(struct ath12k_vif *arvif, struct sk_buff *skb) +ath12k_dp_tx_get_encap_type(struct ath12k_link_vif *arvif, struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath12k_base *ab = arvif->ar->ab; @@ -216,7 +216,7 @@ out: return ret; } -int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, +int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, struct sk_buff *skb) { struct ath12k_base *ab = ar->ab; @@ -230,6 +230,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, struct sk_buff *skb_ext_desc; struct hal_srng *tcl_ring; struct ieee80211_hdr *hdr = (void *)skb->data; + struct ath12k_vif *ahvif = arvif->ahvif; struct dp_tx_ring *tx_ring; u8 pool_id; u8 hal_ring_id; @@ -274,7 +275,7 @@ tcl_ring_sel: ti.bank_id = arvif->bank_id; ti.meta_data_flags = arvif->tcl_metadata; - if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && + if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) { if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) { ti.encrypt_type = @@ -376,7 +377,7 @@ map: ti.desc_id = tx_desc->desc_id; ti.data_len = skb->len; skb_cb->paddr = ti.paddr; - skb_cb->vif = arvif->vif; + skb_cb->vif = ahvif->vif; skb_cb->ar = ar; if (msdu_ext_desc) { diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.h b/drivers/net/wireless/ath/ath12k/dp_tx.h index 55ff8cc721e3..46dce23501f3 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.h +++ b/drivers/net/wireless/ath/ath12k/dp_tx.h @@ -16,7 +16,7 @@ struct ath12k_dp_htt_wbm_tx_status { }; int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab); -int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, +int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, struct sk_buff *skb); void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id); diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index ca04bfae8bdc..fd98fac16dd5 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -385,13 +385,13 @@ static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) { return le32_get_bits(desc->u.qcn9274.msdu_end.info12, - RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP); + RX_MSDU_END_INFO12_MIMO_SS_BITMAP); } static u8 ath12k_hw_qcn9274_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) { return le16_get_bits(desc->u.qcn9274.msdu_end.info5, - RX_MSDU_END_QCN9274_INFO5_TID); + RX_MSDU_END_INFO5_TID); } static u16 ath12k_hw_qcn9274_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) @@ -846,13 +846,13 @@ static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type(struct hal_rx_desc static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) { return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, - RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP); + RX_MSDU_END_INFO12_MIMO_SS_BITMAP); } static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) { return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, - RX_MSDU_END_QCN9274_INFO5_TID); + RX_MSDU_END_INFO5_TID); } static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) @@ -1198,7 +1198,7 @@ static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) { return le32_get_bits(desc->u.wcn7850.msdu_end.info12, - RX_MSDU_END_WCN7850_INFO12_MIMO_SS_BITMAP); + RX_MSDU_END_INFO12_MIMO_SS_BITMAP); } static u8 ath12k_hw_wcn7850_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) @@ -1216,7 +1216,7 @@ static void ath12k_hw_wcn7850_rx_desc_copy_end_tlv(struct hal_rx_desc *fdesc, struct hal_rx_desc *ldesc) { memcpy(&fdesc->u.wcn7850.msdu_end, &ldesc->u.wcn7850.msdu_end, - sizeof(struct rx_msdu_end_wcn7850)); + sizeof(struct rx_msdu_end_qcn9274)); } static u32 ath12k_hw_wcn7850_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc) diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h index 095216eabc01..2de7b0eba9f2 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HAL_RX_H @@ -156,6 +156,7 @@ struct hal_rx_mon_ppdu_info { u32 preamble_type; u32 mpdu_len; u16 chan_num; + u16 freq; u16 tcp_msdu_count; u16 tcp_ack_msdu_count; u16 udp_msdu_count; @@ -232,21 +233,25 @@ struct hal_rx_mon_ppdu_info { u8 medium_prot_type; }; -#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0) +#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0) +#define HAL_RX_PPDU_START_INFO1_CHAN_NUM GENMASK(15, 0) +#define HAL_RX_PPDU_START_INFO1_CHAN_FREQ GENMASK(31, 16) struct hal_rx_ppdu_start { __le32 info0; - __le32 chan_num; - __le32 ppdu_start_ts; + __le32 info1; + __le32 ppdu_start_ts_31_0; + __le32 ppdu_start_ts_63_32; + __le32 rsvd[2]; } __packed; -#define HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR GENMASK(25, 16) +#define HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR GENMASK(26, 16) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK GENMASK(8, 0) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID BIT(9) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_QOS_CTRL_VALID BIT(10) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_HT_CTRL_VALID BIT(11) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE GENMASK(23, 20) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK GENMASK(10, 0) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID BIT(11) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_QOS_CTRL_VALID BIT(12) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_HT_CTRL_VALID BIT(13) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE GENMASK(24, 21) #define HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX GENMASK(15, 0) #define HAL_RX_PPDU_END_USER_STATS_INFO2_FRAME_CTRL GENMASK(31, 16) @@ -262,8 +267,8 @@ struct hal_rx_ppdu_start { #define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP GENMASK(15, 0) #define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_EOSP_BITMAP GENMASK(31, 16) -#define HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_OK_BYTE_COUNT GENMASK(24, 0) -#define HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_ERR_BYTE_COUNT GENMASK(24, 0) +#define HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT GENMASK(24, 0) +#define HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT GENMASK(24, 0) struct hal_rx_ppdu_end_user_stats { __le32 rsvd0[2]; @@ -278,9 +283,9 @@ struct hal_rx_ppdu_end_user_stats { __le32 usr_resp_ref; __le32 info6; __le32 rsvd3[4]; - __le32 mpdu_ok_cnt; + __le32 info7; __le32 rsvd4; - __le32 mpdu_err_cnt; + __le32 info8; __le32 rsvd5[2]; __le32 usr_resp_ref_ext; __le32 rsvd6; @@ -436,23 +441,27 @@ enum hal_rx_ul_reception_type { HAL_RECEPTION_TYPE_FRAMELESS }; -#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB GENMASK(15, 8) -#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_RSVD1_RECEPTION GENMASK(3, 0) +#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RECEPTION GENMASK(3, 0) +#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW GENMASK(7, 5) +#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8) struct hal_rx_phyrx_rssi_legacy_info { - __le32 rsvd[35]; __le32 info0; + __le32 rsvd0[39]; + __le32 info1; + __le32 rsvd1; } __packed; -#define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16) -#define HAL_RX_MPDU_START_INFO1_PEERID GENMASK(31, 16) -#define HAL_RX_MPDU_START_INFO2_MPDU_LEN GENMASK(13, 0) +#define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16) +#define HAL_RX_MPDU_START_INFO1_PEERID GENMASK(31, 16) +#define HAL_RX_MPDU_START_INFO2_MPDU_LEN GENMASK(13, 0) struct hal_rx_mpdu_start { + __le32 rsvd0[9]; __le32 info0; __le32 info1; - __le32 rsvd1[11]; + __le32 rsvd1[2]; __le32 info2; - __le32 rsvd2[9]; + __le32 rsvd2[16]; } __packed; #define HAL_RX_PPDU_END_DURATION GENMASK(23, 0) diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h index 0e53ec269fa4..e8840fab6061 100644 --- a/drivers/net/wireless/ath/ath12k/hif.h +++ b/drivers/net/wireless/ath/ath12k/hif.h @@ -31,6 +31,7 @@ struct ath12k_hif_ops { void (*ce_irq_disable)(struct ath12k_base *ab); void (*get_ce_msi_idx)(struct ath12k_base *ab, u32 ce_id, u32 *msi_idx); int (*panic_handler)(struct ath12k_base *ab); + void (*coredump_download)(struct ath12k_base *ab); }; static inline int ath12k_hif_map_service_to_pipe(struct ath12k_base *ab, u16 service_id, @@ -156,4 +157,9 @@ static inline int ath12k_hif_panic_handler(struct ath12k_base *ab) return ab->hif.ops->panic_handler(ab); } +static inline void ath12k_hif_coredump_download(struct ath12k_base *ab) +{ + if (ab->hif.ops->coredump_download) + ab->hif.ops->coredump_download(ab); +} #endif /* ATH12K_HIF_H */ diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index ec1bda95e555..b7b583fadb5a 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -913,7 +913,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_cfg = 0, .rfkill_on_level = 0, - .rddm_size = 0, + .rddm_size = 0x600000, .def_num_link = 0, .max_mlo_peer = 256, @@ -1069,7 +1069,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_cfg = 0, .rfkill_on_level = 0, - .rddm_size = 0, + .rddm_size = 0x600000, .def_num_link = 0, .max_mlo_peer = 256, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 137394c36460..d493ec812055 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -250,10 +250,10 @@ static const u32 ath12k_smps_map[] = { }; static int ath12k_start_vdev_delay(struct ath12k *ar, - struct ath12k_vif *arvif); + struct ath12k_link_vif *arvif); static void ath12k_mac_stop(struct ath12k *ar); -static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif); -static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif); +static int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif); +static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ath12k_link_vif *arvif); static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode) { @@ -476,18 +476,25 @@ static u8 ath12k_parse_mpdudensity(u8 mpdudensity) } } -static int ath12k_mac_vif_chan(struct ieee80211_vif *vif, - struct cfg80211_chan_def *def) +static int ath12k_mac_vif_link_chan(struct ieee80211_vif *vif, u8 link_id, + struct cfg80211_chan_def *def) { + struct ieee80211_bss_conf *link_conf; struct ieee80211_chanctx_conf *conf; rcu_read_lock(); - conf = rcu_dereference(vif->bss_conf.chanctx_conf); + link_conf = rcu_dereference(vif->link_conf[link_id]); + + if (!link_conf) { + rcu_read_unlock(); + return -ENOLINK; + } + + conf = rcu_dereference(link_conf->chanctx_conf); if (!conf) { rcu_read_unlock(); return -ENOENT; } - *def = conf->def; rcu_read_unlock(); @@ -539,18 +546,33 @@ static void ath12k_get_arvif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct ath12k_vif_iter *arvif_iter = data; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + unsigned long links_map = ahvif->links_map; + struct ath12k_link_vif *arvif; + u8 link_id; + + for_each_set_bit(link_id, &links_map, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = rcu_dereference(ahvif->link[link_id]); + + if (WARN_ON(!arvif)) + continue; - if (arvif->vdev_id == arvif_iter->vdev_id && - arvif->ar == arvif_iter->ar) - arvif_iter->arvif = arvif; + if (arvif->vdev_id == arvif_iter->vdev_id && + arvif->ar == arvif_iter->ar) { + arvif_iter->arvif = arvif; + break; + } + } } -struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) +struct ath12k_link_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) { struct ath12k_vif_iter arvif_iter = {}; u32 flags; + /* To use the arvif returned, caller must have held rcu read lock. + */ + WARN_ON(!rcu_read_lock_any_held()); arvif_iter.vdev_id = vdev_id; arvif_iter.ar = ar; @@ -567,12 +589,12 @@ struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) return arvif_iter.arvif; } -struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, - u32 vdev_id) +struct ath12k_link_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, + u32 vdev_id) { int i; struct ath12k_pdev *pdev; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; for (i = 0; i < ab->num_radios; i++) { pdev = rcu_dereference(ab->pdevs_active[i]); @@ -658,7 +680,8 @@ static struct ath12k *ath12k_get_ar_by_ctx(struct ieee80211_hw *hw, static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; struct ath12k_hw *ah = ath12k_hw_to_ah(hw); /* If there is one pdev within ah, then we return @@ -673,11 +696,12 @@ static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, return NULL; } -static struct ath12k_vif *ath12k_mac_get_vif_up(struct ath12k *ar) +static struct ath12k_link_vif *ath12k_mac_get_vif_up(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - lockdep_assert_held(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) { if (arvif->is_up) return arvif; @@ -705,17 +729,17 @@ static bool ath12k_mac_band_match(enum nl80211_band band1, enum WMI_HOST_WLAN_BA return false; } -static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_vif *arvif) +static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif *vif = arvif->ahvif->vif; struct cfg80211_chan_def def; enum nl80211_band band; u8 pdev_id = ab->fw_pdev[0].pdev_id; int i; - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return pdev_id; band = def.chan->band; @@ -730,7 +754,7 @@ static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_vif *arvif) u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; struct ath12k_base *ab = ar->ab; if (!ab->hw_params->single_pdev_only) @@ -770,11 +794,11 @@ static void ath12k_pdev_caps_update(struct ath12k *ar) static int ath12k_mac_txpower_recalc(struct ath12k *ar) { struct ath12k_pdev *pdev = ar->pdev; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret, txpower = -1; u32 param; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { if (arvif->txpower <= 0) @@ -824,13 +848,13 @@ fail: return ret; } -static int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif) +static int ath12k_recalc_rtscts_prot(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; u32 vdev_param, rts_cts; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); vdev_param = WMI_VDEV_PARAM_ENABLE_RTSCTS; @@ -863,7 +887,7 @@ static int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif) return ret; } -static int ath12k_mac_set_kickout(struct ath12k_vif *arvif) +static int ath12k_mac_set_kickout(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; u32 param; @@ -913,11 +937,14 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar) struct ath12k_peer *peer, *tmp; struct ath12k_base *ab = ar->ab; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); spin_lock_bh(&ab->base_lock); list_for_each_entry_safe(peer, tmp, &ab->peers, list) { - ath12k_dp_rx_peer_tid_cleanup(ar, peer); + /* Skip Rx TID cleanup for self peer */ + if (peer->sta) + ath12k_dp_rx_peer_tid_cleanup(ar, peer); + list_del(&peer->list); kfree(peer); } @@ -929,7 +956,7 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar) static int ath12k_mac_vdev_setup_sync(struct ath12k *ar) { - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) return -ESHUTDOWN; @@ -971,7 +998,7 @@ static int ath12k_mac_monitor_vdev_start(struct ath12k *ar, int vdev_id, struct ath12k_wmi_vdev_up_params params = {}; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); channel = chandef->chan; arg.vdev_id = vdev_id; @@ -1034,7 +1061,7 @@ static int ath12k_mac_monitor_vdev_stop(struct ath12k *ar) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->vdev_setup_done); @@ -1064,9 +1091,8 @@ static int ath12k_mac_monitor_vdev_create(struct ath12k *ar) struct ath12k_wmi_vdev_create_arg arg = {}; int bit, ret; u8 tmp_addr[6]; - u16 nss; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (ar->monitor_vdev_created) return 0; @@ -1104,19 +1130,6 @@ static int ath12k_mac_monitor_vdev_create(struct ath12k *ar) return ret; } - nss = hweight32(ar->cfg_tx_chainmask) ? : 1; - ret = ath12k_wmi_vdev_set_param_cmd(ar, ar->monitor_vdev_id, - WMI_VDEV_PARAM_NSS, nss); - if (ret) { - ath12k_warn(ar->ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n", - ar->monitor_vdev_id, ar->cfg_tx_chainmask, nss, ret); - return ret; - } - - ret = ath12k_mac_txpower_recalc(ar); - if (ret) - return ret; - ar->allocated_vdev_map |= 1LL << ar->monitor_vdev_id; ar->ab->free_vdev_map &= ~(1LL << ar->monitor_vdev_id); ar->num_created_vdevs++; @@ -1132,7 +1145,7 @@ static int ath12k_mac_monitor_vdev_delete(struct ath12k *ar) int ret; unsigned long time_left; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!ar->monitor_vdev_created) return 0; @@ -1178,7 +1191,7 @@ static int ath12k_mac_monitor_start(struct ath12k *ar) struct cfg80211_chan_def *chandef = NULL; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (ar->monitor_started) return 0; @@ -1208,7 +1221,7 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!ar->monitor_started) return 0; @@ -1226,12 +1239,13 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) return ret; } -static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) +static int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif) { + struct ath12k_vif *ahvif = arvif->ahvif; struct ath12k *ar = arvif->ar; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->vdev_setup_done); @@ -1253,7 +1267,7 @@ static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) ar->num_started_vdevs--; ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", - arvif->vif->addr, arvif->vdev_id); + ahvif->vif->addr, arvif->vdev_id); if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); @@ -1272,36 +1286,33 @@ static int ath12k_mac_config(struct ath12k *ar, u32 changed) struct ieee80211_conf *conf = &hw->conf; int ret = 0; - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { ar->monitor_conf_enabled = conf->flags & IEEE80211_CONF_MONITOR; if (ar->monitor_conf_enabled) { if (ar->monitor_vdev_created) - goto exit; + return ret; ret = ath12k_mac_monitor_vdev_create(ar); if (ret) - goto exit; + return ret; ret = ath12k_mac_monitor_start(ar); if (ret) goto err_mon_del; } else { if (!ar->monitor_vdev_created) - goto exit; + return ret; ret = ath12k_mac_monitor_stop(ar); if (ret) - goto exit; + return ret; ath12k_mac_monitor_vdev_delete(ar); } } -exit: - mutex_unlock(&ar->conf_mutex); return ret; err_mon_del: ath12k_mac_monitor_vdev_delete(ar); - mutex_unlock(&ar->conf_mutex); return ret; } @@ -1311,6 +1322,8 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) struct ath12k *ar; int ret; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_ah_to_ar(ah, 0); ret = ath12k_mac_config(ar, changed); @@ -1321,7 +1334,7 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) return ret; } -static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_vif *arvif, +static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_link_vif *arvif, struct sk_buff *bcn) { struct ath12k *ar = arvif->ar; @@ -1378,7 +1391,7 @@ static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, return 0; } -static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *bcn, +static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_buff *bcn, u8 bssid_index, bool *nontx_profile_found) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data; @@ -1470,19 +1483,22 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *b } } -static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif) +static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_link_vif *arvif) { - struct ieee80211_bss_conf *bss_conf = &arvif->vif->bss_conf; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_bss_conf *bss_conf = &ahvif->vif->bss_conf; struct ath12k_wmi_bcn_tmpl_ema_arg ema_args; struct ieee80211_ema_beacons *beacons; - struct ath12k_vif *tx_arvif; + struct ath12k_link_vif *tx_arvif; bool nontx_profile_found = false; + struct ath12k_vif *tx_ahvif; int ret = 0; u8 i; - tx_arvif = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif); + tx_ahvif = ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif); + tx_arvif = &tx_ahvif->deflink; beacons = ieee80211_beacon_get_template_ema_list(ath12k_ar_to_hw(tx_arvif->ar), - tx_arvif->vif, 0); + tx_ahvif->vif, 0); if (!beacons || !beacons->cnt) { ath12k_warn(arvif->ar->ab, "failed to get ema beacon templates from mac80211\n"); @@ -1520,22 +1536,25 @@ static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif) return ret; } -static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) +static int ath12k_mac_setup_bcn_tmpl(struct ath12k_link_vif *arvif) { - struct ath12k_vif *tx_arvif = arvif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); + struct ath12k_link_vif *tx_arvif = arvif; struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; + struct ath12k_vif *tx_ahvif = ahvif; bool nontx_profile_found = false; struct sk_buff *bcn; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + if (ahvif->vdev_type != WMI_VDEV_TYPE_AP) return 0; if (vif->mbssid_tx_vif) { - tx_arvif = ath12k_vif_to_arvif(vif->mbssid_tx_vif); + tx_ahvif = ath12k_vif_to_ahvif(vif->mbssid_tx_vif); + tx_arvif = &tx_ahvif->deflink; if (tx_arvif != arvif && arvif->is_up) return 0; @@ -1543,7 +1562,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) return ath12k_mac_setup_bcn_tmpl_ema(arvif); } - bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_arvif->vif, + bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_ahvif->vif, &offs, 0); if (!bcn) { ath12k_warn(ab, "failed to get beacon template from mac80211\n"); @@ -1554,14 +1573,14 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) ath12k_mac_set_arvif_ies(arvif, bcn, 0, NULL); } else { ath12k_mac_set_arvif_ies(arvif, bcn, - arvif->vif->bss_conf.bssid_index, + ahvif->vif->bss_conf.bssid_index, &nontx_profile_found); if (!nontx_profile_found) ath12k_warn(ab, "nontransmitted profile not found in beacon template\n"); } - if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) { + if (ahvif->vif->type == NL80211_IFTYPE_AP && ahvif->vif->p2p) { ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn); if (ret) { ath12k_warn(ab, "failed to setup P2P GO bcn ie: %d\n", @@ -1595,14 +1614,15 @@ free_bcn_skb: return ret; } -static void ath12k_control_beaconing(struct ath12k_vif *arvif, +static void ath12k_control_beaconing(struct ath12k_link_vif *arvif, struct ieee80211_bss_conf *info) { struct ath12k_wmi_vdev_up_params params = {}; + struct ath12k_vif *ahvif = arvif->ahvif; struct ath12k *ar = arvif->ar; int ret; - lockdep_assert_held(&arvif->ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(arvif->ar)->wiphy); if (!info->enable_beacon) { ret = ath12k_wmi_vdev_down(ar, arvif->vdev_id); @@ -1622,15 +1642,19 @@ static void ath12k_control_beaconing(struct ath12k_vif *arvif, return; } - arvif->aid = 0; + ahvif->aid = 0; ether_addr_copy(arvif->bssid, info->bssid); params.vdev_id = arvif->vdev_id; - params.aid = arvif->aid; + params.aid = ahvif->aid; params.bssid = arvif->bssid; - if (arvif->vif->mbssid_tx_vif) { - params.tx_bssid = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif)->bssid; + if (ahvif->vif->mbssid_tx_vif) { + struct ath12k_vif *tx_ahvif = + ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif); + struct ath12k_link_vif *tx_arvif = &tx_ahvif->deflink; + + params.tx_bssid = tx_arvif->bssid; params.nontx_profile_idx = info->bssid_index; params.nontx_profile_cnt = 1 << info->bssid_indicator; } @@ -1651,7 +1675,8 @@ static void ath12k_mac_handle_beacon_iter(void *data, u8 *mac, { struct sk_buff *skb = data; struct ieee80211_mgmt *mgmt = (void *)skb->data; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; if (vif->type != NL80211_IFTYPE_STATION) return; @@ -1674,7 +1699,8 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { u32 *vdev_id = data; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; struct ath12k *ar = arvif->ar; struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); @@ -1705,9 +1731,9 @@ void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id) static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work) { - struct ath12k_vif *arvif = container_of(work, struct ath12k_vif, - connection_loss_work.work); - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_link_vif *arvif = container_of(work, struct ath12k_link_vif, + connection_loss_work.work); + struct ieee80211_vif *vif = arvif->ahvif->vif; if (!arvif->is_up) return; @@ -1716,15 +1742,16 @@ static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work) } static void ath12k_peer_assoc_h_basic(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); u32 aid; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); if (vif->type == NL80211_IFTYPE_STATION) aid = vif->cfg.aid; @@ -1742,21 +1769,22 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar, } static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ieee80211_bss_conf *info = &vif->bss_conf; struct cfg80211_chan_def def; struct cfg80211_bss *bss; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); const u8 *rsnie = NULL; const u8 *wpaie = NULL; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; bss = cfg80211_get_bss(hw->wiphy, def.chan, info->bssid, NULL, 0, @@ -1804,11 +1832,12 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, } static void ath12k_peer_assoc_h_rates(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates; struct cfg80211_chan_def def; const struct ieee80211_supported_band *sband; @@ -1819,9 +1848,9 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar, u8 rate; int i; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; band = def.chan->band; @@ -1867,12 +1896,13 @@ ath12k_peer_assoc_h_vht_masked(const u16 *vht_mcs_mask) } static void ath12k_peer_assoc_h_ht(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_chan_def def; enum nl80211_band band; const u8 *ht_mcs_mask; @@ -1880,9 +1910,9 @@ static void ath12k_peer_assoc_h_ht(struct ath12k *ar, u8 max_nss; u32 stbc; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; if (!ht_cap->ht_supported) @@ -2028,12 +2058,13 @@ ath12k_peer_assoc_h_vht_limit(u16 tx_mcs_set, } static void ath12k_peer_assoc_h_vht(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_chan_def def; enum nl80211_band band; const u16 *vht_mcs_mask; @@ -2042,7 +2073,9 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, u8 max_nss, vht_mcs; int i; - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; if (!vht_cap->vht_supported) @@ -2123,10 +2156,12 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, } static void ath12k_peer_assoc_h_he(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; int i; u8 ampdu_factor, max_nss; @@ -2278,16 +2313,18 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, } static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; struct cfg80211_chan_def def; enum nl80211_band band; u8 ampdu_factor, mpdu_density; - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; band = def.chan->band; @@ -2347,9 +2384,10 @@ static int ath12k_get_smps_from_capa(const struct ieee80211_sta_ht_cap *ht_cap, return 0; } -static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, +static void ath12k_peer_assoc_h_smps(struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_he_6ghz_capa *he_6ghz_capa = &sta->deflink.he_6ghz_capa; const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; int smps; @@ -2376,13 +2414,13 @@ static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, } static void ath12k_peer_assoc_h_qos(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_AP: if (sta->wme) { /* TODO: Check WME vs QoS */ @@ -2412,15 +2450,16 @@ static void ath12k_peer_assoc_h_qos(struct ath12k *ar, } static int ath12k_peer_assoc_qos_ap(struct ath12k *ar, - struct ath12k_vif *arvif, - struct ieee80211_sta *sta) + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k_wmi_ap_ps_arg arg; u32 max_sp; u32 uapsd; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); arg.vdev_id = arvif->vdev_id; @@ -2574,18 +2613,22 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_eht(struct ath12k *ar, } static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_chan_def def; enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; enum wmi_phy_mode phymode = MODE_UNKNOWN; - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; band = def.chan->band; @@ -2719,17 +2762,19 @@ static void ath12k_mac_set_eht_ppe_threshold(const u8 *ppe_thres, } static void ath12k_peer_assoc_h_eht(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap; const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; const struct ieee80211_eht_mcs_nss_supp_20mhz_only *bw_20; const struct ieee80211_eht_mcs_nss_supp_bw *bw; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); u32 *rx_mcs, *tx_mcs; + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + if (!sta->deflink.he_cap.has_he || !eht_cap->has_eht) return; @@ -2802,34 +2847,34 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar, } static void ath12k_peer_assoc_prepare(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg, bool reassoc) { - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); memset(arg, 0, sizeof(*arg)); reinit_completion(&ar->peer_assoc_done); arg->peer_new_assoc = !reassoc; - ath12k_peer_assoc_h_basic(ar, vif, sta, arg); - ath12k_peer_assoc_h_crypto(ar, vif, sta, arg); - ath12k_peer_assoc_h_rates(ar, vif, sta, arg); - ath12k_peer_assoc_h_ht(ar, vif, sta, arg); - ath12k_peer_assoc_h_vht(ar, vif, sta, arg); - ath12k_peer_assoc_h_he(ar, vif, sta, arg); - ath12k_peer_assoc_h_he_6ghz(ar, vif, sta, arg); - ath12k_peer_assoc_h_eht(ar, vif, sta, arg); - ath12k_peer_assoc_h_qos(ar, vif, sta, arg); - ath12k_peer_assoc_h_phymode(ar, vif, sta, arg); - ath12k_peer_assoc_h_smps(sta, arg); + ath12k_peer_assoc_h_basic(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_crypto(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_rates(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_ht(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_vht(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_he(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_he_6ghz(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_eht(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_qos(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_phymode(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_smps(arsta, arg); /* TODO: amsdu_disable req? */ } -static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, +static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_link_vif *arvif, const u8 *addr, const struct ieee80211_sta_ht_cap *ht_cap, const struct ieee80211_he_6ghz_capa *he_6ghz_capa) @@ -2849,21 +2894,24 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, } static void ath12k_bss_assoc(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_wmi_peer_assoc_arg peer_arg; + struct ath12k_link_sta *arsta; struct ieee80211_sta *ap_sta; + struct ath12k_sta *ahsta; struct ath12k_peer *peer; bool is_auth = false; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n", - arvif->vdev_id, arvif->bssid, arvif->aid); + arvif->vdev_id, arvif->bssid, ahvif->aid); rcu_read_lock(); @@ -2875,7 +2923,15 @@ static void ath12k_bss_assoc(struct ath12k *ar, return; } - ath12k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false); + ahsta = ath12k_sta_to_ahsta(ap_sta); + arsta = &ahsta->deflink; + + if (WARN_ON(!arsta)) { + rcu_read_unlock(); + return; + } + + ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, false); rcu_read_unlock(); @@ -2903,11 +2959,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, WARN_ON(arvif->is_up); - arvif->aid = vif->cfg.aid; + ahvif->aid = vif->cfg.aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); params.vdev_id = arvif->vdev_id; - params.aid = arvif->aid; + params.aid = ahvif->aid; params.bssid = arvif->bssid; ret = ath12k_wmi_vdev_up(ar, ¶ms); if (ret) { @@ -2949,11 +3005,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, } static void ath12k_bss_disassoc(struct ath12k *ar, - struct ath12k_vif *arvif) + struct ath12k_link_vif *arvif) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n", arvif->vdev_id, arvif->bssid); @@ -2996,10 +3052,10 @@ static u32 ath12k_mac_get_rate_hw_value(int bitrate) } static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, - struct ieee80211_vif *vif, + struct ath12k_link_vif *arvif, struct cfg80211_chan_def *def) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); const struct ieee80211_supported_band *sband; u8 basic_rate_idx; @@ -3008,7 +3064,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, u16 bitrate; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); sband = hw->wiphy->bands[def->chan->band]; basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; @@ -3033,9 +3089,19 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, ath12k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret); } -static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, +static int +ath12k_mac_op_change_vif_links(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 old_links, u16 new_links, + struct ieee80211_bss_conf *ol[IEEE80211_MLD_MAX_NUM_LINKS]) +{ + return 0; +} + +static int ath12k_mac_fils_discovery(struct ath12k_link_vif *arvif, struct ieee80211_bss_conf *info) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ath12k *ar = arvif->ar; struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct sk_buff *tmpl; @@ -3046,7 +3112,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, if (info->fils_discovery.max_interval) { interval = info->fils_discovery.max_interval; - tmpl = ieee80211_get_fils_discovery_tmpl(hw, arvif->vif); + tmpl = ieee80211_get_fils_discovery_tmpl(hw, vif); if (tmpl) ret = ath12k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id, tmpl); @@ -3054,8 +3120,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, unsol_bcast_probe_resp_enabled = 1; interval = info->unsol_bcast_probe_resp_interval; - tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, - arvif->vif); + tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif); if (tmpl) ret = ath12k_wmi_probe_resp_tmpl(ar, arvif->vdev_id, tmpl); @@ -3080,10 +3145,44 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, return ret; } -static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) +static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 changed) +{ + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + unsigned long links = ahvif->links_map; + struct ath12k_link_vif *arvif; + struct ath12k *ar; + u8 link_id; + + lockdep_assert_wiphy(hw->wiphy); + + if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { + ahvif->u.ap.ssid_len = vif->cfg.ssid_len; + if (vif->cfg.ssid_len) + memcpy(ahvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); + } + + if (changed & BSS_CHANGED_ASSOC) { + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || !arvif->ar) + continue; + + ar = arvif->ar; + + if (vif->cfg.assoc) + ath12k_bss_assoc(ar, arvif, &vif->bss_conf); + else + ath12k_bss_disassoc(ar, arvif); + } + } +} + +static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; - struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif *vif = arvif->ahvif->vif; struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf; enum wmi_sta_powersave_param param; enum wmi_sta_ps_mode psmode; @@ -3091,12 +3190,12 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) int timeout; bool enable_ps; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (vif->type != NL80211_IFTYPE_STATION) return; - enable_ps = arvif->ps; + enable_ps = arvif->ahvif->ps; if (enable_ps) { psmode = WMI_STA_PS_MODE_ENABLED; param = WMI_STA_PS_PARAM_INACTIVITY_TIME; @@ -3128,11 +3227,12 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) } static void ath12k_mac_bss_info_changed(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct ieee80211_bss_conf *info, u64 changed) { - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ieee80211_vif_cfg *vif_cfg = &vif->cfg; struct cfg80211_chan_def def; u32 param_id, param_value; @@ -3146,7 +3246,7 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, u8 rateidx; u32 rate; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (changed & BSS_CHANGED_BEACON_INT) { arvif->beacon_interval = info->beacon_int; @@ -3202,10 +3302,10 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { - arvif->u.ap.ssid_len = vif->cfg.ssid_len; + ahvif->u.ap.ssid_len = vif->cfg.ssid_len; if (vif->cfg.ssid_len) - memcpy(arvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); - arvif->u.ap.hidden_ssid = info->hidden_ssid; + memcpy(ahvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); + ahvif->u.ap.hidden_ssid = info->hidden_ssid; } if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) @@ -3316,7 +3416,7 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, } if (changed & BSS_CHANGED_MCAST_RATE && - !ath12k_mac_vif_chan(arvif->vif, &def)) { + !ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)) { band = def.chan->band; mcast_rate = vif->bss_conf.mcast_rate[band]; @@ -3360,8 +3460,8 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, } if (changed & BSS_CHANGED_BASIC_RATES && - !ath12k_mac_vif_chan(arvif->vif, &def)) - ath12k_recalculate_mgmt_rate(ar, vif, &def); + !ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)) + ath12k_recalculate_mgmt_rate(ar, arvif, &def); if (changed & BSS_CHANGED_TWT) { if (info->twt_requester || info->twt_responder) @@ -3406,53 +3506,177 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, if (changed & BSS_CHANGED_PS && ar->ab->hw_params->supports_sta_ps) { - arvif->ps = vif_cfg->ps; + ahvif->ps = vif_cfg->ps; ath12k_mac_vif_setup_ps(arvif); } } -static struct ath12k_vif_cache *ath12k_arvif_get_cache(struct ath12k_vif *arvif) +static struct ath12k_vif_cache *ath12k_ahvif_get_link_cache(struct ath12k_vif *ahvif, + u8 link_id) +{ + if (!ahvif->cache[link_id]) { + ahvif->cache[link_id] = kzalloc(sizeof(*ahvif->cache[0]), GFP_KERNEL); + if (ahvif->cache[link_id]) + INIT_LIST_HEAD(&ahvif->cache[link_id]->key_conf.list); + } + + return ahvif->cache[link_id]; +} + +static void ath12k_ahvif_put_link_key_cache(struct ath12k_vif_cache *cache) { - if (!arvif->cache) - arvif->cache = kzalloc(sizeof(*arvif->cache), GFP_KERNEL); + struct ath12k_key_conf *key_conf, *tmp; - return arvif->cache; + if (!cache || list_empty(&cache->key_conf.list)) + return; + list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) { + list_del(&key_conf->list); + kfree(key_conf); + } } -static void ath12k_arvif_put_cache(struct ath12k_vif *arvif) +static void ath12k_ahvif_put_link_cache(struct ath12k_vif *ahvif, u8 link_id) { - kfree(arvif->cache); - arvif->cache = NULL; + ath12k_ahvif_put_link_key_cache(ahvif->cache[link_id]); + kfree(ahvif->cache[link_id]); + ahvif->cache[link_id] = NULL; } -static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u64 changed) +static void ath12k_mac_op_link_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u64 changed) { struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_vif_cache *cache; + struct ath12k_link_vif *arvif; + u8 link_id = info->link_id; - ar = ath12k_get_ar_by_vif(hw, vif); + lockdep_assert_wiphy(hw->wiphy); + + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); /* if the vdev is not created on a certain radio, * cache the info to be updated later on vdev creation */ - if (!ar) { - cache = ath12k_arvif_get_cache(arvif); + if (!arvif || !arvif->is_created) { + cache = ath12k_ahvif_get_link_cache(ahvif, link_id); if (!cache) return; - arvif->cache->bss_conf_changed |= changed; + + cache->bss_conf_changed |= changed; + return; } - mutex_lock(&ar->conf_mutex); + ar = arvif->ar; ath12k_mac_bss_info_changed(ar, arvif, info, changed); +} + +static struct ath12k_link_vif *ath12k_mac_assign_link_vif(struct ath12k_hw *ah, + struct ieee80211_vif *vif, + u8 link_id) +{ + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + int i; + + lockdep_assert_wiphy(ah->hw->wiphy); + + arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]); + if (arvif) + return arvif; + + if (!vif->valid_links) { + /* Use deflink for Non-ML VIFs and mark the link id as 0 + */ + link_id = 0; + arvif = &ahvif->deflink; + } else { + /* If this is the first link arvif being created for an ML VIF + * use the preallocated deflink memory + */ + if (!ahvif->links_map) { + arvif = &ahvif->deflink; + } else { + arvif = (struct ath12k_link_vif *) + kzalloc(sizeof(struct ath12k_link_vif), GFP_KERNEL); + if (!arvif) + return NULL; + } + } + + arvif->ahvif = ahvif; + arvif->link_id = link_id; + ahvif->links_map |= BIT(link_id); + + INIT_LIST_HEAD(&arvif->list); + INIT_DELAYED_WORK(&arvif->connection_loss_work, + ath12k_mac_vif_sta_connection_loss_work); + + for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { + arvif->bitrate_mask.control[i].legacy = 0xffffffff; + memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].ht_mcs)); + memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].vht_mcs)); + } + + /* Allocate Default Queue now and reassign during actual vdev create */ + vif->cab_queue = ATH12K_HW_DEFAULT_QUEUE; + for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++) + vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE; - mutex_unlock(&ar->conf_mutex); + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; + + rcu_assign_pointer(ahvif->link[arvif->link_id], arvif); + ahvif->links_map |= BIT(link_id); + synchronize_rcu(); + return arvif; +} + +static void ath12k_mac_unassign_link_vif(struct ath12k_link_vif *arvif) +{ + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k_hw *ah = ahvif->ah; + + lockdep_assert_wiphy(ah->hw->wiphy); + + rcu_assign_pointer(ahvif->link[arvif->link_id], NULL); + synchronize_rcu(); + ahvif->links_map &= ~BIT(arvif->link_id); + + if (arvif != &ahvif->deflink) + kfree(arvif); + else + memset(arvif, 0, sizeof(*arvif)); +} + +static void ath12k_mac_remove_link_interface(struct ieee80211_hw *hw, + struct ath12k_link_vif *arvif) +{ + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k_hw *ah = hw->priv; + struct ath12k *ar = arvif->ar; + int ret; + + lockdep_assert_wiphy(ah->hw->wiphy); + + cancel_delayed_work_sync(&arvif->connection_loss_work); + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac remove link interface (vdev %d link id %d)", + arvif->vdev_id, arvif->link_id); + + if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) { + ret = ath12k_peer_delete(ar, arvif->vdev_id, arvif->bssid); + if (ret) + ath12k_warn(ar->ab, "failed to submit AP self-peer removal on vdev %d link id %d: %d", + arvif->vdev_id, arvif->link_id, ret); + } + ath12k_mac_vdev_delete(ar, arvif); } static struct ath12k* @@ -3541,7 +3765,7 @@ static int ath12k_scan_stop(struct ath12k *ar) }; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); /* TODO: Fill other STOP Params */ arg.pdev_id = ar->pdev->pdev_id; @@ -3581,7 +3805,7 @@ static void ath12k_scan_abort(struct ath12k *ar) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); spin_lock_bh(&ar->data_lock); @@ -3616,9 +3840,9 @@ static void ath12k_scan_timeout_work(struct work_struct *work) struct ath12k *ar = container_of(work, struct ath12k, scan.timeout.work); - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); ath12k_scan_abort(ar); - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); } static int ath12k_start_scan(struct ath12k *ar, @@ -3626,7 +3850,7 @@ static int ath12k_start_scan(struct ath12k *ar, { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ret = ath12k_wmi_send_scan_start_cmd(ar, arg); if (ret) @@ -3655,24 +3879,50 @@ static int ath12k_start_scan(struct ath12k *ar, return 0; } +static u8 +ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar) +{ + struct ath12k_link_vif *arvif; + struct ath12k_hw *ah = ahvif->ah; + unsigned long links = ahvif->links_map; + u8 link_id; + + lockdep_assert_wiphy(ah->hw->wiphy); + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]); + + if (!arvif || !arvif->is_created) + continue; + + if (ar == arvif->ar) + return link_id; + } + + /* input ar is not assigned to any of the links, use link id + * 0 for scan vdev creation. + */ + return 0; +} + static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar, *prev_ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar; + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; struct cfg80211_scan_request *req = &hw_req->req; struct ath12k_wmi_scan_req_arg *arg = NULL; + u8 link_id; int ret; int i; bool create = true; - if (ah->num_radio == 1) { - WARN_ON(!arvif->is_created); - ar = ath12k_ah_to_ar(ah, 0); - goto scan; - } + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; /* Since the targeted scan device could depend on the frequency * requested in the hw_req, select the corresponding radio @@ -3681,6 +3931,13 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, if (!ar) return -EINVAL; + /* check if any of the links of ML VIF is already started on + * radio(ar) correpsondig to given scan frequency and use it, + * if not use deflink(link 0) for scan purpose. + */ + link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar); + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + /* If the vif is already assigned to a specific vdev of an ar, * check whether its already started, vdev which is started * are not allowed to switch to a new radio. @@ -3698,31 +3955,24 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, return -EINVAL; if (ar != arvif->ar) { - /* backup the previously used ar ptr, since the vdev delete - * would assign the arvif->ar to NULL after the call - */ - prev_ar = arvif->ar; - mutex_lock(&prev_ar->conf_mutex); - ret = ath12k_mac_vdev_delete(prev_ar, vif); - mutex_unlock(&prev_ar->conf_mutex); - if (ret) - ath12k_warn(prev_ar->ab, - "unable to delete scan vdev %d\n", ret); + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } else { create = false; } } if (create) { - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_vdev_create(ar, vif); - mutex_unlock(&ar->conf_mutex); + /* Previous arvif would've been cleared in radio switch block + * above, assign arvif again for create. + */ + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + + ret = ath12k_mac_vdev_create(ar, arvif); if (ret) { ath12k_warn(ar->ab, "unable to create scan vdev %d\n", ret); return -EINVAL; } } -scan: - mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); switch (ar->scan.state) { @@ -3805,30 +4055,31 @@ exit: kfree(arg); } - mutex_unlock(&ar->conf_mutex); - return ret; } static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; struct ath12k *ar; + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + if (!arvif->is_created) return; ar = arvif->ar; - mutex_lock(&ar->conf_mutex); ath12k_scan_abort(ar); - mutex_unlock(&ar->conf_mutex); cancel_delayed_work_sync(&ar->scan.timeout); } -static int ath12k_install_key(struct ath12k_vif *arvif, +static int ath12k_install_key(struct ath12k_link_vif *arvif, struct ieee80211_key_conf *key, enum set_key_cmd cmd, const u8 *macaddr, u32 flags) @@ -3843,8 +4094,10 @@ static int ath12k_install_key(struct ath12k_vif *arvif, .key_flags = flags, .macaddr = macaddr, }; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); - lockdep_assert_held(&arvif->ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->install_key_done); @@ -3895,13 +4148,13 @@ install: if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ)) return -ETIMEDOUT; - if (ether_addr_equal(macaddr, arvif->vif->addr)) - arvif->key_cipher = key->cipher; + if (ether_addr_equal(macaddr, vif->addr)) + ahvif->key_cipher = key->cipher; return ar->install_key_status ? -EINVAL : 0; } -static int ath12k_clear_peer_keys(struct ath12k_vif *arvif, +static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif, const u8 *addr) { struct ath12k *ar = arvif->ar; @@ -3912,7 +4165,7 @@ static int ath12k_clear_peer_keys(struct ath12k_vif *arvif, int i; u32 flags = 0; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); spin_lock_bh(&ab->base_lock); peer = ath12k_peer_find(ab, arvif->vdev_id, addr); @@ -3944,25 +4197,31 @@ static int ath12k_clear_peer_keys(struct ath12k_vif *arvif, } static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ieee80211_key_conf *key) { + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); + struct ieee80211_sta *sta = NULL; struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_peer *peer; - struct ath12k_sta *arsta; + struct ath12k_sta *ahsta; const u8 *peer_addr; - int ret = 0; + int ret; u32 flags = 0; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + if (arsta) + sta = ath12k_ahsta_to_sta(arsta->ahsta); if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) return 1; if (sta) peer_addr = sta->addr; - else if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + else if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) peer_addr = vif->bss_conf.bssid; else peer_addr = vif->addr; @@ -3970,7 +4229,7 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, key->hw_key_idx = key->keyidx; /* the peer should not disappear in mid-way (unless FW goes awry) since - * we already hold conf_mutex. we just make sure its there now. + * we already hold wiphy lock. we just make sure its there now. */ spin_lock_bh(&ab->base_lock); peer = ath12k_peer_find(ab, arvif->vdev_id, peer_addr); @@ -3980,14 +4239,13 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, if (cmd == SET_KEY) { ath12k_warn(ab, "cannot install key for non-existent peer %pM\n", peer_addr); - ret = -EOPNOTSUPP; - goto exit; - } else { - /* if the peer doesn't exist there is no key to disable - * anymore - */ - goto exit; + return -EOPNOTSUPP; } + + /* if the peer doesn't exist there is no key to disable + * anymore + */ + return 0; } if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) @@ -3998,13 +4256,13 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, ret = ath12k_install_key(arvif, key, cmd, peer_addr, flags); if (ret) { ath12k_warn(ab, "ath12k_install_key failed (%d)\n", ret); - goto exit; + return ret; } ret = ath12k_dp_rx_peer_pn_replay_config(arvif, peer_addr, cmd, key); if (ret) { ath12k_warn(ab, "failed to offload PN replay detection %d\n", ret); - goto exit; + return ret; } spin_lock_bh(&ab->base_lock); @@ -4029,7 +4287,7 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, ath12k_warn(ab, "peer %pM disappeared!\n", peer_addr); if (sta) { - arsta = ath12k_sta_to_arsta(sta); + ahsta = ath12k_sta_to_ahsta(sta); switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: @@ -4038,61 +4296,138 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: if (cmd == SET_KEY) - arsta->pn_type = HAL_PN_TYPE_WPA; + ahsta->pn_type = HAL_PN_TYPE_WPA; else - arsta->pn_type = HAL_PN_TYPE_NONE; + ahsta->pn_type = HAL_PN_TYPE_NONE; break; default: - arsta->pn_type = HAL_PN_TYPE_NONE; + ahsta->pn_type = HAL_PN_TYPE_NONE; break; } } spin_unlock_bh(&ab->base_lock); -exit: - return ret; + return 0; +} + +static int ath12k_mac_update_key_cache(struct ath12k_vif_cache *cache, + enum set_key_cmd cmd, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct ath12k_key_conf *key_conf = NULL, *tmp; + + if (cmd == SET_KEY) { + key_conf = kzalloc(sizeof(*key_conf), GFP_KERNEL); + + if (!key_conf) + return -ENOMEM; + + key_conf->cmd = cmd; + key_conf->sta = sta; + key_conf->key = key; + list_add_tail(&key_conf->list, + &cache->key_conf.list); + } + if (list_empty(&cache->key_conf.list)) + return 0; + list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) { + if (key_conf->key == key) { + /* DEL key for an old SET key which driver hasn't flushed yet. + */ + list_del(&key_conf->list); + kfree(key_conf); + break; + } + } + return 0; } static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + struct ath12k_link_sta *arsta = NULL; struct ath12k_vif_cache *cache; - struct ath12k *ar; + struct ath12k_sta *ahsta; + unsigned long links; + u8 link_id; int ret; + lockdep_assert_wiphy(hw->wiphy); + /* BIP needs to be done in software */ if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || - key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) + key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) { return 1; + } if (key->keyidx > WMI_MAX_KEY_INDEX) return -ENOSPC; - ar = ath12k_get_ar_by_vif(hw, vif); - if (!ar) { - /* ar is expected to be valid when sta ptr is available */ - if (sta) { - WARN_ON_ONCE(1); - return -EINVAL; + if (sta) { + ahsta = ath12k_sta_to_ahsta(sta); + /* For an ML STA Pairwise key is same for all associated link Stations, + * hence do set key for all link STAs which are active. + */ + if (sta->mlo) { + links = ahsta->links_map; + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(hw->wiphy, + ahvif->link[link_id]); + arsta = wiphy_dereference(hw->wiphy, + ahsta->link[link_id]); + + if (WARN_ON(!arvif || !arsta)) + /* arvif and arsta are expected to be valid when + * STA is present. + */ + continue; + + ret = ath12k_mac_set_key(arvif->ar, cmd, arvif, + arsta, key); + if (ret) + break; + } + } else { + arsta = &ahsta->deflink; + arvif = arsta->arvif; + if (WARN_ON(!arvif)) { + ret = -EINVAL; + goto out; + } + + ret = ath12k_mac_set_key(arvif->ar, cmd, arvif, arsta, key); + } + } else { + if (key->link_id >= 0 && key->link_id < IEEE80211_MLD_MAX_NUM_LINKS) { + link_id = key->link_id; + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + } else { + link_id = 0; + arvif = &ahvif->deflink; } - cache = ath12k_arvif_get_cache(arvif); - if (!cache) - return -ENOSPC; - cache->key_conf.cmd = cmd; - cache->key_conf.key = key; - cache->key_conf.changed = true; - return 0; + if (!arvif || !arvif->is_created) { + cache = ath12k_ahvif_get_link_cache(ahvif, link_id); + if (!cache) + return -ENOSPC; + + ret = ath12k_mac_update_key_cache(cache, cmd, sta, key); + + return ret; + } + + ret = ath12k_mac_set_key(arvif->ar, cmd, arvif, NULL, key); } - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_set_key(ar, cmd, vif, sta, key); - mutex_unlock(&ar->conf_mutex); +out: + return ret; } @@ -4111,17 +4446,18 @@ ath12k_mac_bitrate_mask_num_vht_rates(struct ath12k *ar, } static int -ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_vif *arvif, - struct ieee80211_sta *sta, +ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, const struct cfg80211_bitrate_mask *mask, enum nl80211_band band) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k *ar = arvif->ar; u8 vht_rate, nss; u32 rate_code; int ret, i; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); nss = 0; @@ -4157,11 +4493,12 @@ ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_vif *arvif, } static int ath12k_station_assoc(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, bool reassoc) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k_wmi_peer_assoc_arg peer_arg; int ret; struct cfg80211_chan_def def; @@ -4169,15 +4506,15 @@ static int ath12k_station_assoc(struct ath12k *ar, struct cfg80211_bitrate_mask *mask; u8 num_vht_rates; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return -EPERM; band = def.chan->band; mask = &arvif->bitrate_mask; - ath12k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc); + ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, reassoc); if (peer_arg.peer_nss < 1) { ath12k_warn(ar->ab, @@ -4205,7 +4542,7 @@ static int ath12k_station_assoc(struct ath12k *ar, * Note that all other rates and NSS will be disabled for this peer. */ if (sta->deflink.vht_cap.vht_supported && num_vht_rates == 1) { - ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, + ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, band); if (ret) return ret; @@ -4234,7 +4571,7 @@ static int ath12k_station_assoc(struct ath12k *ar, } if (sta->wme && sta->uapsd_queues) { - ret = ath12k_peer_assoc_qos_ap(ar, arvif, sta); + ret = ath12k_peer_assoc_qos_ap(ar, arvif, arsta); if (ret) { ath12k_warn(ar->ab, "failed to set qos params for STA %pM for vdev %i: %d\n", sta->addr, arvif->vdev_id, ret); @@ -4246,13 +4583,13 @@ static int ath12k_station_assoc(struct ath12k *ar, } static int ath12k_station_disassoc(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!sta->wme) { arvif->num_legacy_stations--; @@ -4270,11 +4607,10 @@ static int ath12k_station_disassoc(struct ath12k *ar, return 0; } -static void ath12k_sta_rc_update_wk(struct work_struct *wk) +static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) { struct ath12k *ar; - struct ath12k_vif *arvif; - struct ath12k_sta *arsta; + struct ath12k_link_vif *arvif; struct ieee80211_sta *sta; struct cfg80211_chan_def def; enum nl80211_band band; @@ -4285,13 +4621,18 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) const struct cfg80211_bitrate_mask *mask; struct ath12k_wmi_peer_assoc_arg peer_arg; enum wmi_phy_mode peer_phymode; + struct ath12k_link_sta *arsta; + struct ieee80211_vif *vif; - arsta = container_of(wk, struct ath12k_sta, update_wk); - sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); + lockdep_assert_wiphy(wiphy); + + arsta = container_of(wk, struct ath12k_link_sta, update_wk); + sta = ath12k_ahsta_to_sta(arsta->ahsta); arvif = arsta->arvif; + vif = ath12k_ahvif_to_vif(arvif->ahvif); ar = arvif->ar; - if (WARN_ON(ath12k_mac_vif_chan(arvif->vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; band = def.chan->band; @@ -4310,14 +4651,12 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) spin_unlock_bh(&ar->data_lock); - mutex_lock(&ar->conf_mutex); - nss = max_t(u32, 1, nss); nss = min(nss, max(ath12k_mac_max_ht_nss(ht_mcs_mask), ath12k_mac_max_vht_nss(vht_mcs_mask))); if (changed & IEEE80211_RC_BW_CHANGED) { - ath12k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg); + ath12k_peer_assoc_h_phymode(ar, arvif, arsta, &peer_arg); peer_phymode = peer_arg.peer_phymode; if (bw > bw_prev) { @@ -4334,7 +4673,7 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) if (err) { ath12k_warn(ar->ab, "failed to update STA %pM to peer phymode %d: %d\n", sta->addr, peer_phymode, err); - goto err_rc_bw_changed; + return; } err = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, WMI_PEER_CHWIDTH, @@ -4355,7 +4694,7 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) if (err) { ath12k_warn(ar->ab, "failed to update STA %pM peer to bandwidth %d: %d\n", sta->addr, bw, err); - goto err_rc_bw_changed; + return; } err = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, WMI_PEER_PHYMODE, @@ -4405,14 +4744,14 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) * across HT/VHT and for multiple VHT MCS support. */ if (sta->deflink.vht_cap.vht_supported && num_vht_rates == 1) { - ath12k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, + ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, band); } else { /* If the peer is non-VHT or no fixed VHT rate * is provided in the new bitrate mask we set the * other rates using peer_assoc command. */ - ath12k_peer_assoc_prepare(ar, arvif->vif, sta, + ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, true); err = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg); @@ -4425,18 +4764,17 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) sta->addr, arvif->vdev_id); } } -err_rc_bw_changed: - mutex_unlock(&ar->conf_mutex); } -static int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif, - struct ieee80211_sta *sta) +static int ath12k_mac_inc_num_stations(struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k *ar = arvif->ar; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) + if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) return 0; if (ar->num_stations >= ar->max_num_stations) @@ -4447,38 +4785,38 @@ static int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif, return 0; } -static void ath12k_mac_dec_num_stations(struct ath12k_vif *arvif, - struct ieee80211_sta *sta) +static void ath12k_mac_dec_num_stations(struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k *ar = arvif->ar; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) + if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) return; ar->num_stations--; } static int ath12k_mac_station_add(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k_wmi_peer_create_arg peer_param; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - ret = ath12k_mac_inc_num_stations(arvif, sta); + ret = ath12k_mac_inc_num_stations(arvif, arsta); if (ret) { ath12k_warn(ab, "refusing to associate station: too many connected already (%d)\n", ar->max_num_stations); goto exit; } - arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); if (!arsta->rx_stats) { ret = -ENOMEM; @@ -4519,7 +4857,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, if (ab->hw_params->vdev_start_delay && !arvif->is_started && - arvif->vdev_type != WMI_VDEV_TYPE_AP) { + arvif->ahvif->vdev_type != WMI_VDEV_TYPE_AP) { ret = ath12k_start_vdev_delay(ar, arvif); if (ret) { ath12k_warn(ab, "failed to delay vdev start: %d\n", ret); @@ -4532,7 +4870,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, free_peer: ath12k_peer_delete(ar, arvif->vdev_id, sta->addr); dec_num_station: - ath12k_mac_dec_num_stations(arvif, sta); + ath12k_mac_dec_num_stations(arvif, arsta); exit: return ret; } @@ -4574,16 +4912,18 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); + struct ath12k_link_vif *arvif; + struct ath12k_link_sta *arsta; struct ath12k_peer *peer; int ret = 0; - /* cancel must be done outside the mutex to avoid deadlock */ - if ((old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST)) - cancel_work_sync(&arsta->update_wk); + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + arsta = &ahsta->deflink; ar = ath12k_get_ar_by_vif(hw, vif); if (!ar) { @@ -4591,21 +4931,28 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, return -EINVAL; } - mutex_lock(&ar->conf_mutex); - if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) { memset(arsta, 0, sizeof(*arsta)); + rcu_assign_pointer(ahsta->link[0], arsta); + /* TODO use appropriate link id once MLO support is added */ + arsta->link_id = ATH12K_DEFAULT_LINK_ID; + ahsta->links_map = BIT(arsta->link_id); + arsta->ahsta = ahsta; arsta->arvif = arvif; - INIT_WORK(&arsta->update_wk, ath12k_sta_rc_update_wk); + wiphy_work_init(&arsta->update_wk, ath12k_sta_rc_update_wk); + + synchronize_rcu(); - ret = ath12k_mac_station_add(ar, vif, sta); + ret = ath12k_mac_station_add(ar, arvif, arsta); if (ret) ath12k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n", sta->addr, arvif->vdev_id); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { - if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { + wiphy_work_cancel(hw->wiphy, &arsta->update_wk); + + if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) { ath12k_bss_disassoc(ar, arvif); ret = ath12k_mac_vdev_stop(arvif); if (ret) @@ -4622,7 +4969,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n", sta->addr, arvif->vdev_id); - ath12k_mac_dec_num_stations(arvif, sta); + ath12k_mac_dec_num_stations(arvif, arsta); spin_lock_bh(&ar->ab->base_lock); peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); if (peer && peer->sta == sta) { @@ -4637,12 +4984,20 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, kfree(arsta->rx_stats); arsta->rx_stats = NULL; + + if (arsta->link_id < IEEE80211_MLD_MAX_NUM_LINKS) { + rcu_assign_pointer(ahsta->link[arsta->link_id], NULL); + synchronize_rcu(); + ahsta->links_map &= ~(BIT(arsta->link_id)); + arsta->link_id = ATH12K_INVALID_LINK_ID; + arsta->ahsta = NULL; + } } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT || vif->type == NL80211_IFTYPE_ADHOC)) { - ret = ath12k_station_assoc(ar, vif, sta, false); + ret = ath12k_station_assoc(ar, arvif, arsta, false); if (ret) ath12k_warn(ar->ab, "Failed to associate station: %pM\n", sta->addr); @@ -4686,14 +5041,12 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT || vif->type == NL80211_IFTYPE_ADHOC)) { - ret = ath12k_station_disassoc(ar, vif, sta); + ret = ath12k_station_disassoc(ar, arvif, arsta); if (ret) ath12k_warn(ar->ab, "Failed to disassociate station: %pM\n", sta->addr); } - mutex_unlock(&ar->conf_mutex); - return ret; } @@ -4703,25 +5056,32 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; int ret; s16 txpwr; + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) { txpwr = 0; } else { txpwr = sta->deflink.txpwr.power; - if (!txpwr) - return -EINVAL; + if (!txpwr) { + ret = -EINVAL; + goto out; + } } - if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) - return -EINVAL; + if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) { + ret = -EINVAL; + goto out; + } ar = ath12k_ah_to_ar(ah, 0); - mutex_lock(&ar->conf_mutex); - ret = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, WMI_PEER_USE_FIXED_PWR, txpwr); if (ret) { @@ -4731,20 +5091,26 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, } out: - mutex_unlock(&ar->conf_mutex); return ret; } static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct ath12k *ar; - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_sta *arsta; + struct ath12k_link_vif *arvif; struct ath12k_peer *peer; u32 bw, smps; + /* TODO: use proper link id once link sta specific rc update support is + * available in mac80211. + */ + u8 link_id = ATH12K_DEFAULT_LINK_ID; ar = ath12k_get_ar_by_vif(hw, vif); if (!ar) { @@ -4752,11 +5118,27 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, return; } + rcu_read_lock(); + arvif = rcu_dereference(ahvif->link[link_id]); + if (!arvif) { + ath12k_warn(ar->ab, "mac sta rc update failed to fetch link vif on link id %u for peer %pM\n", + link_id, sta->addr); + rcu_read_unlock(); + return; + } + arsta = rcu_dereference(ahsta->link[link_id]); + if (!arsta) { + rcu_read_unlock(); + ath12k_warn(ar->ab, "mac sta rc update failed to fetch link sta on link id %u for peer %pM\n", + link_id, sta->addr); + return; + } spin_lock_bh(&ar->ab->base_lock); peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); if (!peer) { spin_unlock_bh(&ar->ab->base_lock); + rcu_read_unlock(); ath12k_warn(ar->ab, "mac sta rc update failed to find peer %pM on vdev %i\n", sta->addr, arvif->vdev_id); return; @@ -4808,17 +5190,20 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); - ieee80211_queue_work(hw, &arsta->update_wk); + wiphy_work_queue(hw->wiphy, &arsta->update_wk); + + rcu_read_unlock(); } -static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif, +static int ath12k_conf_tx_uapsd(struct ath12k_link_vif *arvif, u16 ac, bool enable) { struct ath12k *ar = arvif->ar; + struct ath12k_vif *ahvif = arvif->ahvif; u32 value; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA) return 0; switch (ac) { @@ -4841,19 +5226,19 @@ static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif, } if (enable) - arvif->u.sta.uapsd |= value; + ahvif->u.sta.uapsd |= value; else - arvif->u.sta.uapsd &= ~value; + ahvif->u.sta.uapsd &= ~value; ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, WMI_STA_PS_PARAM_UAPSD, - arvif->u.sta.uapsd); + ahvif->u.sta.uapsd); if (ret) { ath12k_warn(ar->ab, "could not set uapsd params %d\n", ret); goto exit; } - if (arvif->u.sta.uapsd) + if (ahvif->u.sta.uapsd) value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; else value = WMI_STA_PS_RX_WAKE_POLICY_WAKE; @@ -4868,8 +5253,7 @@ exit: return ret; } -static int ath12k_mac_conf_tx(struct ath12k_vif *arvif, - unsigned int link_id, u16 ac, +static int ath12k_mac_conf_tx(struct ath12k_link_vif *arvif, u16 ac, const struct ieee80211_tx_queue_params *params) { struct wmi_wmm_params_arg *p = NULL; @@ -4877,7 +5261,7 @@ static int ath12k_mac_conf_tx(struct ath12k_vif *arvif, struct ath12k_base *ab = ar->ab; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); switch (ac) { case IEEE80211_AC_VO: @@ -4926,26 +5310,30 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { - struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_vif_cache *cache = arvif->cache; + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + struct ath12k_vif_cache *cache; int ret; - ar = ath12k_get_ar_by_vif(hw, vif); - if (!ar) { - /* cache the info and apply after vdev is created */ - cache = ath12k_arvif_get_cache(arvif); + lockdep_assert_wiphy(hw->wiphy); + + if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) + return -EINVAL; + + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || !arvif->is_created) { + cache = ath12k_ahvif_get_link_cache(ahvif, link_id); if (!cache) return -ENOSPC; + cache->tx_conf.changed = true; cache->tx_conf.ac = ac; cache->tx_conf.tx_queue_params = *params; + return 0; } - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_conf_tx(arvif, link_id, ac, params); - mutex_unlock(&ar->conf_mutex); + ret = ath12k_mac_conf_tx(arvif, ac, params); return ret; } @@ -5016,10 +5404,11 @@ ath12k_create_ht_cap(struct ath12k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask return ht_cap; } -static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif) +static int ath12k_mac_set_txbf_conf(struct ath12k_link_vif *arvif) { u32 value = 0; struct ath12k *ar = arvif->ar; + struct ath12k_vif *ahvif = arvif->ahvif; int nsts; int sound_dim; u32 vht_cap = ar->pdev->cap.vht_cap; @@ -5047,7 +5436,7 @@ static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif) value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) && - arvif->vdev_type == WMI_VDEV_TYPE_AP) + ahvif->vdev_type == WMI_VDEV_TYPE_AP) value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER; } @@ -5055,7 +5444,7 @@ static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif) value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && - arvif->vdev_type == WMI_VDEV_TYPE_STA) + ahvif->vdev_type == WMI_VDEV_TYPE_STA) value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE; } @@ -5612,7 +6001,7 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) struct ath12k_hw *ah = ath12k_ar_to_ah(ar); int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (ath12k_check_chain_mask(ar, tx_ant, true)) return -EINVAL; @@ -5716,7 +6105,7 @@ static int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx) return 0; } -static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_vif *arvif, +static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arvif, struct sk_buff *skb) { struct ath12k_base *ab = ar->ab; @@ -5784,7 +6173,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) { struct ath12k *ar = container_of(work, struct ath12k, wmi_mgmt_tx_work); struct ath12k_skb_cb *skb_cb; - struct ath12k_vif *arvif; + struct ath12k_vif *ahvif; + struct ath12k_link_vif *arvif; struct sk_buff *skb; int ret; @@ -5796,8 +6186,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) continue; } - arvif = ath12k_vif_to_arvif(skb_cb->vif); - + ahvif = ath12k_vif_to_ahvif(skb_cb->vif); + arvif = &ahvif->deflink; if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) { ret = ath12k_mac_mgmt_tx_wmi(ar, arvif, skb); if (ret) { @@ -5852,18 +6242,18 @@ static void ath12k_mac_add_p2p_noa_ie(struct ath12k *ar, struct sk_buff *skb, bool is_prb_rsp) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); if (likely(!is_prb_rsp)) return; spin_lock_bh(&ar->data_lock); - if (arvif->u.ap.noa_data && - !pskb_expand_head(skb, 0, arvif->u.ap.noa_len, + if (ahvif->u.ap.noa_data && + !pskb_expand_head(skb, 0, ahvif->u.ap.noa_len, GFP_ATOMIC)) - skb_put_data(skb, arvif->u.ap.noa_data, - arvif->u.ap.noa_len); + skb_put_data(skb, ahvif->u.ap.noa_data, + ahvif->u.ap.noa_len); spin_unlock_bh(&ar->data_lock); } @@ -5875,7 +6265,8 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; struct ath12k *ar = arvif->ar; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_key_conf *key = info->control.hw_key; @@ -5939,8 +6330,7 @@ static int ath12k_mac_start(struct ath12k *ar) int ret; lockdep_assert_held(&ah->hw_mutex); - - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1, pdev->pdev_id); @@ -6025,14 +6415,11 @@ static int ath12k_mac_start(struct ath12k *ar) } } - mutex_unlock(&ar->conf_mutex); - rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], &ab->pdevs[ar->pdev_idx]); return 0; err: - mutex_unlock(&ar->conf_mutex); return ret; } @@ -6052,6 +6439,8 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) struct ath12k *ar; int ret, i; + lockdep_assert_wiphy(hw->wiphy); + ath12k_drain_tx(ah); guard(mutex)(&ah->hw_mutex); @@ -6158,15 +6547,14 @@ static void ath12k_mac_stop(struct ath12k *ar) int ret; lockdep_assert_held(&ah->hw_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - mutex_lock(&ar->conf_mutex); ret = ath12k_mac_config_mon_status_default(ar, false); if (ret && (ret != -EOPNOTSUPP)) ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n", ret); clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); - mutex_unlock(&ar->conf_mutex); cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); @@ -6192,6 +6580,8 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend) struct ath12k *ar; int i; + lockdep_assert_wiphy(hw->wiphy); + ath12k_drain_tx(ah); mutex_lock(&ah->hw_mutex); @@ -6205,7 +6595,7 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend) } static u8 -ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) +ath12k_mac_get_vdev_stats_id(struct ath12k_link_vif *arvif) { struct ath12k_base *ab = arvif->ar->ab; u8 vdev_stats_id = 0; @@ -6227,19 +6617,22 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) return vdev_stats_id; } -static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif, +static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_link_vif *arvif, u32 *flags, u32 *tx_vdev_id) { - struct ieee80211_vif *tx_vif = arvif->vif->mbssid_tx_vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *tx_vif = ahvif->vif->mbssid_tx_vif; struct ath12k *ar = arvif->ar; - struct ath12k_vif *tx_arvif; + struct ath12k_link_vif *tx_arvif; + struct ath12k_vif *tx_ahvif; if (!tx_vif) return 0; - tx_arvif = ath12k_vif_to_arvif(tx_vif); + tx_ahvif = ath12k_vif_to_ahvif(tx_vif); + tx_arvif = &tx_ahvif->deflink; - if (arvif->vif->bss_conf.nontransmitted) { + if (ahvif->vif->bss_conf.nontransmitted) { if (ar->ah->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy) return -EINVAL; @@ -6251,22 +6644,23 @@ static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif, return -EINVAL; } - if (arvif->vif->bss_conf.ema_ap) + if (ahvif->vif->bss_conf.ema_ap) *flags |= WMI_VDEV_MBSSID_FLAGS_EMA_MODE; return 0; } -static int ath12k_mac_setup_vdev_create_arg(struct ath12k_vif *arvif, +static int ath12k_mac_setup_vdev_create_arg(struct ath12k_link_vif *arvif, struct ath12k_wmi_vdev_create_arg *arg) { struct ath12k *ar = arvif->ar; struct ath12k_pdev *pdev = ar->pdev; + struct ath12k_vif *ahvif = arvif->ahvif; int ret; arg->if_id = arvif->vdev_id; - arg->type = arvif->vdev_type; - arg->subtype = arvif->vdev_subtype; + arg->type = ahvif->vdev_type; + arg->subtype = ahvif->vdev_subtype; arg->pdev_id = pdev->pdev_id; arg->mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP; @@ -6333,14 +6727,15 @@ ath12k_mac_prepare_he_mode(struct ath12k_pdev *pdev, u32 viftype) } static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, - struct ath12k_vif *arvif) + struct ath12k_link_vif *arvif) { u32 param_id, param_value; struct ath12k_base *ab = ar->ab; + struct ath12k_vif *ahvif = arvif->ahvif; int ret; param_id = WMI_VDEV_PARAM_SET_HEMU_MODE; - param_value = ath12k_mac_prepare_he_mode(ar->pdev, arvif->vif->type); + param_value = ath12k_mac_prepare_he_mode(ar->pdev, ahvif->vif->type); ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param_id, param_value); if (ret) { @@ -6363,9 +6758,10 @@ static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, return ret; } -static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) +static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif) { - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; u32 param_id, param_value; @@ -6378,14 +6774,14 @@ static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) IEEE80211_OFFLOAD_DECAP_ENABLED); if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) - arvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET; + ahvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET; else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) - arvif->tx_encap_type = ATH12K_HW_TXRX_RAW; + ahvif->tx_encap_type = ATH12K_HW_TXRX_RAW; else - arvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI; + ahvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, arvif->tx_encap_type); + param_id, ahvif->tx_encap_type); if (ret) { ath12k_warn(ab, "failed to set vdev %d tx encap mode: %d\n", arvif->vdev_id, ret); @@ -6412,57 +6808,86 @@ static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + unsigned long links; + int link_id; - ath12k_mac_update_vif_offload(arvif); + lockdep_assert_wiphy(hw->wiphy); + + if (vif->valid_links) { + links = vif->valid_links; + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!(arvif && arvif->ar)) + continue; + + ath12k_mac_update_vif_offload(arvif); + } + + return; + } + + ath12k_mac_update_vif_offload(&ahvif->deflink); } -static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) +int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) { struct ath12k_hw *ah = ar->ah; struct ath12k_base *ab = ar->ab; struct ieee80211_hw *hw = ah->hw; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k_wmi_vdev_create_arg vdev_arg = {0}; struct ath12k_wmi_peer_create_arg peer_param; + struct ieee80211_bss_conf *link_conf; u32 param_id, param_value; u16 nss; int i; int ret, vdev_id; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); + + link_conf = wiphy_dereference(hw->wiphy, vif->link_conf[arvif->link_id]); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in vdev create for vif %pM link %u\n", + vif->addr, arvif->link_id); + return -ENOLINK; + } + + memcpy(arvif->bssid, link_conf->addr, ETH_ALEN); arvif->ar = ar; vdev_id = __ffs64(ab->free_vdev_map); arvif->vdev_id = vdev_id; - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; switch (vif->type) { case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: - arvif->vdev_type = WMI_VDEV_TYPE_STA; + ahvif->vdev_type = WMI_VDEV_TYPE_STA; if (vif->p2p) - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; break; case NL80211_IFTYPE_MESH_POINT: - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; fallthrough; case NL80211_IFTYPE_AP: - arvif->vdev_type = WMI_VDEV_TYPE_AP; + ahvif->vdev_type = WMI_VDEV_TYPE_AP; if (vif->p2p) - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; break; case NL80211_IFTYPE_MONITOR: - arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; + ahvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ar->monitor_vdev_id = vdev_id; break; case NL80211_IFTYPE_P2P_DEVICE: - arvif->vdev_type = WMI_VDEV_TYPE_STA; - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + ahvif->vdev_type = WMI_VDEV_TYPE_STA; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; break; default: WARN_ON(1); @@ -6470,7 +6895,7 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) } ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev create id %d type %d subtype %d map %llx\n", - arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, + arvif->vdev_id, ahvif->vdev_type, ahvif->vdev_subtype, ab->free_vdev_map); vif->cab_queue = arvif->vdev_id % (ATH12K_HW_MAX_QUEUES - 1); @@ -6484,11 +6909,11 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) goto err; } - ret = ath12k_wmi_vdev_create(ar, vif->addr, &vdev_arg); + ret = ath12k_wmi_vdev_create(ar, arvif->bssid, &vdev_arg); if (ret) { ath12k_warn(ab, "failed to create WMI vdev %d: %d\n", arvif->vdev_id, ret); - goto err; + return ret; } ar->num_created_vdevs++; @@ -6513,10 +6938,10 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) goto err_vdev_del; } - switch (arvif->vdev_type) { + switch (ahvif->vdev_type) { case WMI_VDEV_TYPE_AP: peer_param.vdev_id = arvif->vdev_id; - peer_param.peer_addr = vif->addr; + peer_param.peer_addr = arvif->bssid; peer_param.peer_type = WMI_PEER_TYPE_DEFAULT; ret = ath12k_peer_create(ar, arvif, NULL, &peer_param); if (ret) { @@ -6589,29 +7014,28 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) } ath12k_dp_vdev_tx_attach(ar, arvif); - if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled) ath12k_mac_monitor_vdev_create(ar); - arvif->ar = ar; return ret; err_peer_del: - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) { reinit_completion(&ar->peer_delete_done); - ret = ath12k_wmi_send_peer_delete_cmd(ar, vif->addr, + ret = ath12k_wmi_send_peer_delete_cmd(ar, arvif->bssid, arvif->vdev_id); if (ret) { ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", - arvif->vdev_id, vif->addr); + arvif->vdev_id, arvif->bssid); goto err; } ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id, - vif->addr); + arvif->bssid); if (ret) - goto err; + /* KVALO: why not goto err? */ + return ret; ar->num_peers--; } @@ -6633,21 +7057,56 @@ err: return ret; } -static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ieee80211_vif *vif) +static void ath12k_mac_vif_flush_key_cache(struct ath12k_link_vif *arvif) +{ + struct ath12k_key_conf *key_conf, *tmp; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k_hw *ah = ahvif->ah; + struct ath12k_sta *ahsta; + struct ath12k_link_sta *arsta; + struct ath12k_vif_cache *cache = ahvif->cache[arvif->link_id]; + int ret; + + lockdep_assert_wiphy(ah->hw->wiphy); + + list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) { + arsta = NULL; + if (key_conf->sta) { + ahsta = ath12k_sta_to_ahsta(key_conf->sta); + arsta = wiphy_dereference(ah->hw->wiphy, + ahsta->link[arvif->link_id]); + if (!arsta) + goto free_cache; + } + + ret = ath12k_mac_set_key(arvif->ar, key_conf->cmd, + arvif, arsta, + key_conf->key); + if (ret) + ath12k_warn(arvif->ar->ab, "unable to apply set key param to vdev %d ret %d\n", + arvif->vdev_id, ret); +free_cache: + list_del(&key_conf->list); + kfree(key_conf); + } +} + +static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ath12k_link_vif *arvif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_vif_cache *cache = arvif->cache; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); + struct ath12k_vif_cache *cache = ahvif->cache[arvif->link_id]; struct ath12k_base *ab = ar->ab; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!cache) return; if (cache->tx_conf.changed) { - ret = ath12k_mac_conf_tx(arvif, 0, cache->tx_conf.ac, + ret = ath12k_mac_conf_tx(arvif, cache->tx_conf.ac, &cache->tx_conf.tx_queue_params); if (ret) ath12k_warn(ab, @@ -6660,26 +7119,25 @@ static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ieee80211_vif cache->bss_conf_changed); } - if (cache->key_conf.changed) { - ret = ath12k_mac_set_key(ar, cache->key_conf.cmd, vif, NULL, - cache->key_conf.key); - if (ret) - ath12k_warn(ab, "unable to apply set key param to vdev %d ret %d\n", - arvif->vdev_id, ret); - } - ath12k_arvif_put_cache(arvif); + if (!list_empty(&cache->key_conf.list)) + ath12k_mac_vif_flush_key_cache(arvif); + + ath12k_ahvif_put_link_cache(ahvif, arvif->link_id); } static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, + struct ath12k_link_vif *arvif, struct ieee80211_chanctx_conf *ctx) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ath12k_hw *ah = hw->priv; - struct ath12k *ar, *prev_ar; + struct ath12k *ar; struct ath12k_base *ab; + u8 link_id = arvif->link_id; int ret; + lockdep_assert_wiphy(hw->wiphy); + if (ah->num_radio == 1) ar = ah->radio; else if (ctx) @@ -6708,27 +7166,20 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, if (WARN_ON(arvif->is_started)) return NULL; - /* backup the previously used ar ptr since arvif->ar would - * be set to NULL after vdev delete is done - */ - prev_ar = arvif->ar; - mutex_lock(&prev_ar->conf_mutex); - ret = ath12k_mac_vdev_delete(prev_ar, vif); - - if (ret) - ath12k_warn(prev_ar->ab, "unable to delete vdev %d\n", - ret); - mutex_unlock(&prev_ar->conf_mutex); + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } } ab = ar->ab; - mutex_lock(&ar->conf_mutex); - if (arvif->is_created) goto flush; + /* Assign arvif again here since previous radio switch block + * would've unassigned and cleared it. + */ + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); if (vif->type == NL80211_IFTYPE_AP && ar->num_peers > (ar->max_num_peers - 1)) { ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n"); @@ -6741,7 +7192,7 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, goto unlock; } - ret = ath12k_mac_vdev_create(ar, vif); + ret = ath12k_mac_vdev_create(ar, arvif); if (ret) { ath12k_warn(ab, "failed to create vdev %pM ret %d", vif->addr, ret); goto unlock; @@ -6752,21 +7203,27 @@ flush: * add_interface(), Apply any parameters for the vdev which were received * after add_interface, corresponding to this vif. */ - ath12k_mac_vif_cache_flush(ar, vif); + ath12k_mac_vif_cache_flush(ar, arvif); unlock: - mutex_unlock(&ar->conf_mutex); return arvif->ar; } static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; int i; - memset(arvif, 0, sizeof(*arvif)); + lockdep_assert_wiphy(hw->wiphy); - arvif->vif = vif; + memset(ahvif, 0, sizeof(*ahvif)); + + ahvif->ah = ah; + ahvif->vif = vif; + arvif = &ahvif->deflink; + arvif->ahvif = ahvif; INIT_LIST_HEAD(&arvif->list); INIT_DELAYED_WORK(&arvif->connection_loss_work, @@ -6786,13 +7243,14 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE; vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; - - /* For single radio wiphy(i.e ah->num_radio is 1), create the vdev - * during add_interface itself, for multi radio wiphy, defer the vdev - * creation until channel_assign to determine the radio on which the - * vdev needs to be created + /* For non-ml vifs, vif->addr is the actual vdev address but for + * ML vif link(link BSSID) address is the vdev address and it can be a + * different one from vif->addr (i.e ML address). + * Defer vdev creation until assign_chanctx or hw_scan is initiated as driver + * will not know if this interface is an ML vif at this point. */ - ath12k_mac_assign_vif_to_vdev(hw, vif, NULL); + ath12k_mac_assign_vif_to_vdev(hw, arvif, NULL); + return 0; } @@ -6821,14 +7279,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif } } -static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif) +static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ath12k_link_vif *arvif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k_base *ab = ar->ab; unsigned long time_left; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + reinit_completion(&ar->vdev_delete_done); ret = ath12k_wmi_vdev_delete(ar, arvif->vdev_id); @@ -6849,7 +7309,7 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif) ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); ar->num_created_vdevs--; - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ar->monitor_vdev_id = -1; ar->monitor_vdev_created = false; } else if (ar->monitor_vdev_created && !ar->monitor_started) { @@ -6865,7 +7325,7 @@ err_vdev_del: spin_unlock_bh(&ar->data_lock); ath12k_peer_cleanup(ar, arvif->vdev_id); - ath12k_arvif_put_cache(arvif); + ath12k_ahvif_put_link_cache(ahvif, arvif->link_id); idr_for_each(&ar->txmgmt_idr, ath12k_mac_vif_txmgmt_idr_remove, vif); @@ -6886,39 +7346,24 @@ err_vdev_del: static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_base *ab; - struct ath12k *ar; - int ret; + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + u8 link_id; - if (!arvif->is_created) { + lockdep_assert_wiphy(hw->wiphy); + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { /* if we cached some config but never received assign chanctx, * free the allocated cache. */ - ath12k_arvif_put_cache(arvif); - return; - } - - ar = arvif->ar; - ab = ar->ab; - - cancel_delayed_work_sync(&arvif->connection_loss_work); - - mutex_lock(&ar->conf_mutex); - - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n", - arvif->vdev_id); + ath12k_ahvif_put_link_cache(ahvif, link_id); + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || !arvif->is_created) + continue; - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { - ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr); - if (ret) - ath12k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n", - arvif->vdev_id, ret); + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } - - ath12k_mac_vdev_delete(ar, vif); - - mutex_unlock(&ar->conf_mutex); } /* FIXME: Has to be verified. */ @@ -6937,7 +7382,7 @@ static void ath12k_mac_configure_filter(struct ath12k *ar, bool reset_flag; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ar->filter_flags = total_flags; @@ -6962,14 +7407,12 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - ar = ath12k_ah_to_ar(ah, 0); + lockdep_assert_wiphy(hw->wiphy); - mutex_lock(&ar->conf_mutex); + ar = ath12k_ah_to_ar(ah, 0); *total_flags &= SUPPORTED_FILTERS; ath12k_mac_configure_filter(ar, *total_flags); - - mutex_unlock(&ar->conf_mutex); } static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) @@ -6979,11 +7422,11 @@ static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 * struct ath12k *ar; int i; + lockdep_assert_wiphy(hw->wiphy); + for_each_ar(ah, ar, i) { - mutex_lock(&ar->conf_mutex); antennas_rx = max_t(u32, antennas_rx, ar->cfg_rx_chainmask); antennas_tx = max_t(u32, antennas_tx, ar->cfg_tx_chainmask); - mutex_unlock(&ar->conf_mutex); } *tx_ant = antennas_tx; @@ -6999,10 +7442,10 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx int ret = 0; int i; + lockdep_assert_wiphy(hw->wiphy); + for_each_ar(ah, ar, i) { - mutex_lock(&ar->conf_mutex); ret = __ath12k_set_antenna(ar, tx_ant, rx_ant); - mutex_unlock(&ar->conf_mutex); if (ret) break; } @@ -7010,13 +7453,13 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx return ret; } -static int ath12k_mac_ampdu_action(struct ath12k_vif *arvif, +static int ath12k_mac_ampdu_action(struct ath12k_link_vif *arvif, struct ieee80211_ampdu_params *params) { struct ath12k *ar = arvif->ar; int ret = -EINVAL; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); switch (params->action) { case IEEE80211_AMPDU_RX_START: @@ -7046,19 +7489,20 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; int ret = -EINVAL; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_vif(hw, vif); if (!ar) return -EINVAL; ar = ath12k_ah_to_ar(ah, 0); + arvif = &ahvif->deflink; - mutex_lock(&ar->conf_mutex); ret = ath12k_mac_ampdu_action(arvif, params); - mutex_unlock(&ar->conf_mutex); - if (ret) ath12k_warn(ar->ab, "pdev idx %d unable to perform ampdu action %d ret %d\n", ar->pdev_idx, params->action, ret); @@ -7072,6 +7516,8 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ath12k *ar; struct ath12k_base *ab; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_ctx(hw, ctx); if (!ar) return -EINVAL; @@ -7082,8 +7528,6 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, "mac chanctx add freq %u width %d ptr %p\n", ctx->def.chan->center_freq, ctx->def.width, ctx); - mutex_lock(&ar->conf_mutex); - spin_lock_bh(&ar->data_lock); /* TODO: In case of multiple channel context, populate rx_channel from * Rx PPDU desc information. @@ -7091,8 +7535,6 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, ar->rx_channel = ctx->def.chan; spin_unlock_bh(&ar->data_lock); - mutex_unlock(&ar->conf_mutex); - return 0; } @@ -7102,6 +7544,8 @@ static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw, struct ath12k *ar; struct ath12k_base *ab; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_ctx(hw, ctx); if (!ar) return; @@ -7112,16 +7556,12 @@ static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw, "mac chanctx remove freq %u width %d ptr %p\n", ctx->def.chan->center_freq, ctx->def.width, ctx); - mutex_lock(&ar->conf_mutex); - spin_lock_bh(&ar->data_lock); /* TODO: In case of there is one more channel context left, populate * rx_channel with the channel of that remaining channel context. */ ar->rx_channel = NULL; spin_unlock_bh(&ar->data_lock); - - mutex_unlock(&ar->conf_mutex); } static enum wmi_phy_mode @@ -7188,7 +7628,7 @@ ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar, } static int -ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, +ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, struct ieee80211_chanctx_conf *ctx, bool restart) { @@ -7196,10 +7636,11 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, struct ath12k_base *ab = ar->ab; struct wmi_vdev_start_req_arg arg = {}; const struct cfg80211_chan_def *chandef = &ctx->def; - int he_support = arvif->vif->bss_conf.he_support; + struct ath12k_vif *ahvif = arvif->ahvif; + int he_support = ahvif->vif->bss_conf.he_support; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->vdev_setup_done); @@ -7215,7 +7656,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, arg.mode = ath12k_mac_check_down_grade_phy_mode(ar, arg.mode, chandef->chan->band, - arvif->vif->type); + ahvif->vif->type); arg.min_power = 0; arg.max_power = chandef->chan->max_power * 2; arg.max_reg_power = chandef->chan->max_reg_power * 2; @@ -7235,10 +7676,10 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, return ret; } - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { - arg.ssid = arvif->u.ap.ssid; - arg.ssid_len = arvif->u.ap.ssid_len; - arg.hidden_ssid = arvif->u.ap.hidden_ssid; + if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) { + arg.ssid = ahvif->u.ap.ssid; + arg.ssid_len = ahvif->u.ap.ssid_len; + arg.hidden_ssid = ahvif->u.ap.hidden_ssid; /* For now allow DFS for AP mode */ arg.chan_radar = !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); @@ -7285,7 +7726,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, ar->num_started_vdevs++; ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM started, vdev_id %d\n", - arvif->vif->addr, arvif->vdev_id); + ahvif->vif->addr, arvif->vdev_id); /* Enable CAC Flag in the driver by checking the channel DFS cac time, * i.e dfs_cac_ms value which will be valid only for radar channels @@ -7294,7 +7735,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, * during CAC. */ /* TODO: Set the flag for other interface types as required */ - if (arvif->vdev_type == WMI_VDEV_TYPE_AP && + if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP && chandef->chan->dfs_cac_ms && chandef->chan->dfs_state == NL80211_DFS_USABLE) { set_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); @@ -7311,13 +7752,13 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, return 0; } -static int ath12k_mac_vdev_start(struct ath12k_vif *arvif, +static int ath12k_mac_vdev_start(struct ath12k_link_vif *arvif, struct ieee80211_chanctx_conf *ctx) { return ath12k_mac_vdev_start_restart(arvif, ctx, false); } -static int ath12k_mac_vdev_restart(struct ath12k_vif *arvif, +static int ath12k_mac_vdev_restart(struct ath12k_link_vif *arvif, struct ieee80211_chanctx_conf *ctx) { return ath12k_mac_vdev_start_restart(arvif, ctx, true); @@ -7335,8 +7776,13 @@ static void ath12k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_mac_change_chanctx_arg *arg = data; + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(ahvif->ah->hw->wiphy); + + arvif = &ahvif->deflink; if (arvif->ar != arg->ar) return; @@ -7351,9 +7797,14 @@ static void ath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_mac_change_chanctx_arg *arg = data; struct ieee80211_chanctx_conf *ctx; + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(ahvif->ah->hw->wiphy); + + arvif = &ahvif->deflink; if (arvif->ar != arg->ar) return; @@ -7397,13 +7848,13 @@ static u32 ath12k_mac_nlwidth_to_wmiwidth(enum nl80211_chan_width width) } static int ath12k_mac_update_peer_puncturing_width(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct cfg80211_chan_def def) { u32 param_id, param_value; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA) return 0; param_id = WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP; @@ -7429,17 +7880,19 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, { struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_base *ab = ar->ab; + struct ath12k_link_vif *arvif; struct ieee80211_vif *vif; - struct ath12k_vif *arvif; + struct ath12k_vif *ahvif; int ret; int i; bool monitor_vif = false; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); for (i = 0; i < n_vifs; i++) { vif = vifs[i].vif; - arvif = ath12k_vif_to_arvif(vif); + ahvif = ath12k_vif_to_ahvif(vif); + arvif = &ahvif->deflink; if (vif->type == NL80211_IFTYPE_MONITOR) monitor_vif = true; @@ -7489,10 +7942,14 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, memset(¶ms, 0, sizeof(params)); params.vdev_id = arvif->vdev_id; - params.aid = arvif->aid; + params.aid = ahvif->aid; params.bssid = arvif->bssid; if (vif->mbssid_tx_vif) { - params.tx_bssid = ath12k_vif_to_arvif(vif->mbssid_tx_vif)->bssid; + struct ath12k_vif *ahvif = + ath12k_vif_to_ahvif(vif->mbssid_tx_vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; + + params.tx_bssid = arvif->bssid; params.nontx_profile_idx = vif->bss_conf.bssid_index; params.nontx_profile_cnt = 1 << vif->bss_conf.bssid_indicator; } @@ -7528,7 +7985,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar, struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx, .ar = ar }; struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_NORMAL, @@ -7558,14 +8015,14 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, struct ath12k *ar; struct ath12k_base *ab; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_ctx(hw, ctx); if (!ar) return; ab = ar->ab; - mutex_lock(&ar->conf_mutex); - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx change freq %u width %d ptr %p changed %x\n", ctx->def.chan->center_freq, ctx->def.width, ctx, changed); @@ -7574,7 +8031,7 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, * switch_vif_chanctx(). */ if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) - goto unlock; + return; if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH || changed & IEEE80211_CHANCTX_CHANGE_RADAR || @@ -7582,16 +8039,14 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, ath12k_mac_update_active_vif_chan(ar, ctx); /* TODO: Recalc radar detection */ - -unlock: - mutex_unlock(&ar->conf_mutex); } static int ath12k_start_vdev_delay(struct ath12k *ar, - struct ath12k_vif *arvif) + struct ath12k_link_vif *arvif) { struct ath12k_base *ab = ar->ab; - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); int ret; if (WARN_ON(arvif->is_started)) @@ -7605,7 +8060,7 @@ static int ath12k_start_vdev_delay(struct ath12k *ar, return ret; } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath12k_monitor_vdev_up(ar, arvif->vdev_id); if (ret) { ath12k_warn(ab, "failed put monitor up: %d\n", ret); @@ -7625,24 +8080,37 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + u8 link_id = link_conf->link_id; + struct ath12k_link_vif *arvif; int ret; + lockdep_assert_wiphy(hw->wiphy); + /* For multi radio wiphy, the vdev was not created during add_interface * create now since we have a channel ctx now to assign to a specific ar/fw */ - ar = ath12k_mac_assign_vif_to_vdev(hw, vif, ctx); - if (!ar) { + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + if (!arvif) { WARN_ON(1); + return -ENOMEM; + } + + if (!arvif->is_started) { + ar = ath12k_mac_assign_vif_to_vdev(hw, arvif, ctx); + if (!ar) + return -EINVAL; + } else { + ath12k_warn(arvif->ar->ab, "failed to assign chanctx for vif %pM link id %u link vif is already started", + vif->addr, link_id); return -EINVAL; } ab = ar->ab; - mutex_lock(&ar->conf_mutex); - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx assign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); @@ -7651,8 +8119,8 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, /* for some targets bss peer must be created before vdev_start */ if (ab->hw_params->vdev_start_delay && - arvif->vdev_type != WMI_VDEV_TYPE_AP && - arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && + ahvif->vdev_type != WMI_VDEV_TYPE_AP && + ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR && !ath12k_peer_exist_by_vdev_id(ab, arvif->vdev_id)) { memcpy(&arvif->chanctx, ctx, sizeof(*ctx)); ret = 0; @@ -7664,10 +8132,11 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath12k_mac_monitor_start(ar); if (ret) goto out; + arvif->is_started = true; goto out; } @@ -7680,7 +8149,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created) + if (ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created) ath12k_mac_monitor_start(ar); arvif->is_started = true; @@ -7688,8 +8157,6 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, /* TODO: Setup ps and cts/rts protection */ out: - mutex_unlock(&ar->conf_mutex); - return ret; } @@ -7701,9 +8168,15 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, { struct ath12k *ar; struct ath12k_base *ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + u8 link_id = link_conf->link_id; int ret; + lockdep_assert_wiphy(hw->wiphy); + + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + /* The vif is expected to be attached to an ar's VDEV. * We leave the vif/vdev in this function as is * and not delete the vdev symmetric to assign_vif_chanctx() @@ -7711,32 +8184,28 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, * remove_interface() or when there is a change in channel * that moves the vif to a new ar */ - if (!arvif->is_created) + if (!arvif || !arvif->is_created) return; ar = arvif->ar; ab = ar->ab; - mutex_lock(&ar->conf_mutex); - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx unassign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); WARN_ON(!arvif->is_started); - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath12k_mac_monitor_stop(ar); - if (ret) { - mutex_unlock(&ar->conf_mutex); + if (ret) return; - } arvif->is_started = false; } - if (arvif->vdev_type != WMI_VDEV_TYPE_STA && - arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA && + ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { ath12k_bss_disassoc(ar, arvif); ret = ath12k_mac_vdev_stop(arvif); if (ret) @@ -7745,11 +8214,12 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, } arvif->is_started = false; - if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && + if (ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->num_started_vdevs == 1 && ar->monitor_vdev_created) ath12k_mac_monitor_stop(ar); - mutex_unlock(&ar->conf_mutex); + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } static int @@ -7760,35 +8230,32 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, { struct ath12k *ar; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx); if (!ar) return -EINVAL; - mutex_lock(&ar->conf_mutex); - /* Switching channels across radio is not allowed */ - if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) { - mutex_unlock(&ar->conf_mutex); + if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) return -EINVAL; - } ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac chanctx switch n_vifs %d mode %d\n", n_vifs, mode); ath12k_mac_update_vif_chan(ar, vifs, n_vifs); - mutex_unlock(&ar->conf_mutex); - return 0; } static int ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret = 0; - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + list_for_each_entry(arvif, &ar->arvifs, list) { ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "setting mac vdev %d param %d value %d\n", param, arvif->vdev_id, value); @@ -7801,7 +8268,7 @@ ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value) break; } } - mutex_unlock(&ar->conf_mutex); + return ret; } @@ -7814,6 +8281,8 @@ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) struct ath12k *ar; int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret = 0, i; + lockdep_assert_wiphy(hw->wiphy); + /* Currently we set the rts threshold value to all the vifs across * all radios of the single wiphy. * TODO Once support for vif specific RTS threshold in mac80211 is @@ -7843,6 +8312,9 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) * supported. This effectively prevents mac80211 from doing frame * fragmentation in software. */ + + lockdep_assert_wiphy(hw->wiphy); + return -EOPNOTSUPP; } @@ -7887,6 +8359,8 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v struct ath12k *ar; int i; + lockdep_assert_wiphy(hw->wiphy); + if (drop) return; @@ -8020,14 +8494,14 @@ ath12k_mac_get_single_legacy_rate(struct ath12k *ar, return 0; } -static int ath12k_mac_set_fixed_rate_params(struct ath12k_vif *arvif, +static int ath12k_mac_set_fixed_rate_params(struct ath12k_link_vif *arvif, u32 rate, u8 nss, u8 sgi, u8 ldpc) { struct ath12k *ar = arvif->ar; u32 vdev_param; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n", arvif->vdev_id, rate, nss, sgi); @@ -8099,8 +8573,9 @@ ath12k_mac_vht_mcs_range_present(struct ath12k *ar, static void ath12k_mac_set_bitrate_mask_iter(void *data, struct ieee80211_sta *sta) { - struct ath12k_vif *arvif = data; - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); + struct ath12k_link_vif *arvif = data; + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + struct ath12k_link_sta *arsta = &ahsta->deflink; struct ath12k *ar = arvif->ar; if (arsta->arvif != arvif) @@ -8110,14 +8585,15 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data, arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED; spin_unlock_bh(&ar->data_lock); - ieee80211_queue_work(ath12k_ar_to_hw(ar), &arsta->update_wk); + wiphy_work_queue(ath12k_ar_to_hw(ar)->wiphy, &arsta->update_wk); } static void ath12k_mac_disable_peer_fixed_rate(void *data, struct ieee80211_sta *sta) { - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); - struct ath12k_vif *arvif = data; + struct ath12k_link_vif *arvif = data; + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + struct ath12k_link_sta *arsta = &ahsta->deflink; struct ath12k *ar = arvif->ar; int ret; @@ -8139,9 +8615,10 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct cfg80211_bitrate_mask *mask) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; struct cfg80211_chan_def def; - struct ath12k *ar = arvif->ar; + struct ath12k *ar; enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; @@ -8153,8 +8630,15 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, int ret; int num_rates; - if (ath12k_mac_vif_chan(vif, &def)) - return -EPERM; + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + + ar = arvif->ar; + if (ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)) { + ret = -EPERM; + goto out; + } band = def.chan->band; ht_mcs_mask = mask->control[band].ht_mcs; @@ -8183,9 +8667,9 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto out; } - ieee80211_iterate_stations_atomic(hw, - ath12k_mac_disable_peer_fixed_rate, - arvif); + ieee80211_iterate_stations_mtx(hw, + ath12k_mac_disable_peer_fixed_rate, + arvif); } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask, &single_nss)) { rate = WMI_FIXED_RATE_NONE; @@ -8226,34 +8710,25 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, */ ath12k_warn(ar->ab, "Setting more than one MCS Value in bitrate mask not supported\n"); - ret = -EINVAL; - goto out; + return -EINVAL; } - ieee80211_iterate_stations_atomic(hw, - ath12k_mac_disable_peer_fixed_rate, - arvif); - - mutex_lock(&ar->conf_mutex); + ieee80211_iterate_stations_mtx(hw, + ath12k_mac_disable_peer_fixed_rate, + arvif); arvif->bitrate_mask = *mask; - ieee80211_iterate_stations_atomic(hw, - ath12k_mac_set_bitrate_mask_iter, - arvif); - - mutex_unlock(&ar->conf_mutex); + ieee80211_iterate_stations_mtx(hw, + ath12k_mac_set_bitrate_mask_iter, + arvif); } - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); if (ret) { ath12k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n", arvif->vdev_id, ret); } - mutex_unlock(&ar->conf_mutex); - out: return ret; } @@ -8265,9 +8740,12 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; - struct ath12k_vif *arvif; + struct ath12k_vif *ahvif; + struct ath12k_link_vif *arvif; int recovery_count, i; + lockdep_assert_wiphy(hw->wiphy); + if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; @@ -8280,8 +8758,6 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ieee80211_wake_queues(hw); for_each_ar(ah, ar, i) { - mutex_lock(&ar->conf_mutex); - ab = ar->ab; ath12k_warn(ar->ab, "pdev %d successfully recovered\n", @@ -8306,11 +8782,12 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, } list_for_each_entry(arvif, &ar->arvifs, list) { + ahvif = arvif->ahvif; ath12k_dbg(ab, ATH12K_DBG_BOOT, "reconfig cipher %d up %d vdev type %d\n", - arvif->key_cipher, + ahvif->key_cipher, arvif->is_up, - arvif->vdev_type); + ahvif->vdev_type); /* After trigger disconnect, then upper layer will * trigger connect again, then the PN number of @@ -8318,16 +8795,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, * side, hence PN number mismatch will not happen. */ if (arvif->is_up && - arvif->vdev_type == WMI_VDEV_TYPE_STA && - arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { - ieee80211_hw_restart_disconnect(arvif->vif); + ahvif->vdev_type == WMI_VDEV_TYPE_STA && + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { + ieee80211_hw_restart_disconnect(ahvif->vif); ath12k_dbg(ab, ATH12K_DBG_BOOT, "restart disconnect\n"); } } - - mutex_unlock(&ar->conf_mutex); } } @@ -8338,7 +8813,7 @@ ath12k_mac_update_bss_chan_survey(struct ath12k *ar, int ret; enum wmi_bss_chan_info_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!test_bit(WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64, ar->ab->wmi_ab.svc_map) || ar->rx_channel != channel) @@ -8370,6 +8845,8 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, struct ieee80211_supported_band *sband; struct survey_info *ar_survey; + lockdep_assert_wiphy(hw->wiphy); + if (idx >= ATH12K_NUM_CHANS) return -ENOENT; @@ -8403,8 +8880,6 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, ar_survey = &ar->survey[idx]; - mutex_lock(&ar->conf_mutex); - ath12k_mac_update_bss_chan_survey(ar, &sband->channels[idx]); spin_lock_bh(&ar->data_lock); @@ -8416,7 +8891,6 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, if (ar->rx_channel == survey->channel) survey->filled |= SURVEY_INFO_IN_USE; - mutex_unlock(&ar->conf_mutex); return 0; } @@ -8425,7 +8899,12 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct station_info *sinfo) { - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + struct ath12k_link_sta *arsta; + + lockdep_assert_wiphy(hw->wiphy); + + arsta = &ahsta->deflink; sinfo->rx_duration = arsta->rx_duration; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); @@ -8462,7 +8941,7 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, ar = ath12k_ah_to_ar(ah, 0); - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); spin_lock_bh(&ar->data_lock); ar->scan.roc_notify = false; @@ -8470,8 +8949,6 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, ath12k_scan_abort(ar); - mutex_unlock(&ar->conf_mutex); - cancel_delayed_work_sync(&ar->scan.timeout); return 0; @@ -8483,24 +8960,31 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, int duration, enum ieee80211_roc_type type) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k_wmi_scan_req_arg arg; - struct ath12k *ar, *prev_ar; + struct ath12k_link_vif *arvif; + struct ath12k *ar; u32 scan_time_msec; bool create = true; + u8 link_id; int ret; - if (ah->num_radio == 1) { - WARN_ON(!arvif->is_created); - ar = ath12k_ah_to_ar(ah, 0); - goto scan; - } + lockdep_assert_wiphy(hw->wiphy); ar = ath12k_mac_select_scan_device(hw, vif, chan->center_freq); - if (!ar) - return -EINVAL; + if (!ar) { + ret = -EINVAL; + goto exit; + } + /* check if any of the links of ML VIF is already started on + * radio(ar) correpsondig to given scan frequency and use it, + * if not use deflink(link 0) for scan purpose. + */ + + link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar); + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); /* If the vif is already assigned to a specific vdev of an ar, * check whether its already started, vdev which is started * are not allowed to switch to a new radio. @@ -8511,44 +8995,35 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, * always on the same band for the vif */ if (arvif->is_created) { - if (WARN_ON(!arvif->ar)) - return -EINVAL; + if (WARN_ON(!arvif->ar)) { + ret = -EINVAL; + goto exit; + } - if (ar != arvif->ar && arvif->is_started) - return -EBUSY; + if (ar != arvif->ar && arvif->is_started) { + ret = -EBUSY; + goto exit; + } if (ar != arvif->ar) { - /* backup the previously used ar ptr, since the vdev delete - * would assign the arvif->ar to NULL after the call - */ - prev_ar = arvif->ar; - mutex_lock(&prev_ar->conf_mutex); - ret = ath12k_mac_vdev_delete(prev_ar, vif); - mutex_unlock(&prev_ar->conf_mutex); - if (ret) { - ath12k_warn(prev_ar->ab, - "unable to delete scan vdev for roc: %d\n", - ret); - return ret; - } + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } else { create = false; } } if (create) { - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_vdev_create(ar, vif); - mutex_unlock(&ar->conf_mutex); + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + + ret = ath12k_mac_vdev_create(ar, arvif); if (ret) { ath12k_warn(ar->ab, "unable to create scan vdev for roc: %d\n", ret); - return -EINVAL; + goto exit; } } -scan: - mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); switch (ar->scan.state) { @@ -8623,9 +9098,8 @@ scan: free_chan_list: kfree(arg.chan_list); -exit: - mutex_unlock(&ar->conf_mutex); +exit: return ret; } @@ -8633,16 +9107,20 @@ static void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *data) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_rekey_data *rekey_data = &arvif->rekey_data; + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_rekey_data *rekey_data; struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar = ath12k_ah_to_ar(ah, 0); + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + rekey_data = &arvif->rekey_data; ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set rekey data vdev %d\n", arvif->vdev_id); - mutex_lock(&ar->conf_mutex); - memcpy(rekey_data->kck, data->kck, NL80211_KCK_LEN); memcpy(rekey_data->kek, data->kek, NL80211_KEK_LEN); @@ -8659,8 +9137,6 @@ static void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw, rekey_data->kck, NL80211_KEK_LEN); ath12k_dbg_dump(ar->ab, ATH12K_DBG_MAC, "replay ctr", NULL, &rekey_data->replay_ctr, sizeof(rekey_data->replay_ctr)); - - mutex_unlock(&ar->conf_mutex); } static const struct ieee80211_ops ath12k_ops = { @@ -8673,7 +9149,9 @@ static const struct ieee80211_ops ath12k_ops = { .remove_interface = ath12k_mac_op_remove_interface, .update_vif_offload = ath12k_mac_op_update_vif_offload, .config = ath12k_mac_op_config, - .bss_info_changed = ath12k_mac_op_bss_info_changed, + .link_info_changed = ath12k_mac_op_link_info_changed, + .vif_cfg_changed = ath12k_mac_op_vif_cfg_changed, + .change_vif_links = ath12k_mac_op_change_vif_links, .configure_filter = ath12k_mac_op_configure_filter, .hw_scan = ath12k_mac_op_hw_scan, .cancel_hw_scan = ath12k_mac_op_cancel_hw_scan, @@ -8681,7 +9159,7 @@ static const struct ieee80211_ops ath12k_ops = { .set_rekey_data = ath12k_mac_op_set_rekey_data, .sta_state = ath12k_mac_op_sta_state, .sta_set_txpwr = ath12k_mac_op_sta_set_txpwr, - .sta_rc_update = ath12k_mac_op_sta_rc_update, + .link_sta_rc_update = ath12k_mac_op_sta_rc_update, .conf_tx = ath12k_mac_op_conf_tx, .set_antenna = ath12k_mac_op_set_antenna, .get_antenna = ath12k_mac_op_get_antenna, @@ -9320,7 +9798,7 @@ static void ath12k_mac_setup(struct ath12k *ar) spin_lock_init(&ar->data_lock); INIT_LIST_HEAD(&ar->arvifs); INIT_LIST_HEAD(&ar->ppdu_stats_info); - mutex_init(&ar->conf_mutex); + init_completion(&ar->vdev_setup_done); init_completion(&ar->vdev_delete_done); init_completion(&ar->peer_assoc_done); @@ -9501,7 +9979,7 @@ err: return ret; } -int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, +int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval) { @@ -9509,9 +9987,9 @@ int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, struct ath12k *ar = arvif->ar; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA) return 0; if (!test_bit(WMI_TLV_SERVICE_STA_KEEP_ALIVE, ar->ab->wmi_ab.svc_map)) diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 5efbb6822628..d382337ba649 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -41,6 +41,9 @@ struct ath12k_generic_iter { #define ATH12K_TX_POWER_MAX_VAL 70 #define ATH12K_TX_POWER_MIN_VAL 0 +#define ATH12K_DEFAULT_LINK_ID 0 +#define ATH12K_INVALID_LINK_ID 255 + enum ath12k_supported_bw { ATH12K_BW_20 = 0, ATH12K_BW_40 = 1, @@ -65,9 +68,9 @@ u8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, void __ath12k_mac_scan_finish(struct ath12k *ar); void ath12k_mac_scan_finish(struct ath12k *ar); -struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id); -struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, - u32 vdev_id); +struct ath12k_link_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id); +struct ath12k_link_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, + u32 vdev_id); struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id); struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id); @@ -82,7 +85,7 @@ int ath12k_mac_rfkill_config(struct ath12k *ar); int ath12k_mac_wait_tx_complete(struct ath12k *ar); void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb); void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id); -int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, +int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval); u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar); diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index df96b0f91f54..2f6d14382ed7 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -649,3 +649,8 @@ void ath12k_mhi_resume(struct ath12k_pci *ab_pci) { ath12k_mhi_set_state(ab_pci, ATH12K_MHI_RESUME); } + +void ath12k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic) +{ + mhi_download_rddm_image(mhi_ctrl, in_panic); +} diff --git a/drivers/net/wireless/ath/ath12k/mhi.h b/drivers/net/wireless/ath/ath12k/mhi.h index 9362ad1958c3..7358b8477536 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.h +++ b/drivers/net/wireless/ath/ath12k/mhi.h @@ -43,5 +43,5 @@ void ath12k_mhi_clear_vector(struct ath12k_base *ab); void ath12k_mhi_suspend(struct ath12k_pci *ar_pci); void ath12k_mhi_resume(struct ath12k_pci *ar_pci); - +void ath12k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic); #endif diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c index 3a851ee15b2f..84cccf7d91e7 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.c +++ b/drivers/net/wireless/ath/ath12k/p2p.c @@ -69,20 +69,20 @@ static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info return len; } -static void ath12k_p2p_noa_ie_assign(struct ath12k_vif *arvif, void *ie, +static void ath12k_p2p_noa_ie_assign(struct ath12k_link_vif *arvif, void *ie, size_t len) { struct ath12k *ar = arvif->ar; lockdep_assert_held(&ar->data_lock); - kfree(arvif->u.ap.noa_data); + kfree(arvif->ahvif->u.ap.noa_data); - arvif->u.ap.noa_data = ie; - arvif->u.ap.noa_len = len; + arvif->ahvif->u.ap.noa_data = ie; + arvif->ahvif->u.ap.noa_len = len; } -static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif, +static void __ath12k_p2p_noa_update(struct ath12k_link_vif *arvif, const struct ath12k_wmi_p2p_noa_info *noa) { struct ath12k *ar = arvif->ar; @@ -105,7 +105,7 @@ static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif, ath12k_p2p_noa_ie_assign(arvif, ie, len); } -void ath12k_p2p_noa_update(struct ath12k_vif *arvif, +void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif, const struct ath12k_wmi_p2p_noa_info *noa) { struct ath12k *ar = arvif->ar; @@ -118,9 +118,12 @@ void ath12k_p2p_noa_update(struct ath12k_vif *arvif, static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_p2p_noa_arg *arg = data; + struct ath12k_link_vif *arvif; + WARN_ON(!rcu_read_lock_any_held()); + arvif = &ahvif->deflink; if (arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id) return; diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h index b2eec51a9900..03ee877e6d6b 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.h +++ b/drivers/net/wireless/ath/ath12k/p2p.h @@ -16,7 +16,7 @@ struct ath12k_p2p_noa_arg { const struct ath12k_wmi_p2p_noa_info *noa; }; -void ath12k_p2p_noa_update(struct ath12k_vif *arvif, +void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif, const struct ath12k_wmi_p2p_noa_info *noa); void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, const struct ath12k_wmi_p2p_noa_info *noa); diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index bd269aa1740b..cf907550e6a4 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -7,6 +7,8 @@ #include <linux/module.h> #include <linux/msi.h> #include <linux/pci.h> +#include <linux/time.h> +#include <linux/vmalloc.h> #include "pci.h" #include "core.h" @@ -425,9 +427,9 @@ static void ath12k_pci_sync_ce_irqs(struct ath12k_base *ab) } } -static void ath12k_pci_ce_tasklet(struct tasklet_struct *t) +static void ath12k_pci_ce_workqueue(struct work_struct *work) { - struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); + struct ath12k_ce_pipe *ce_pipe = from_work(ce_pipe, work, intr_wq); int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); @@ -449,7 +451,7 @@ static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg) disable_irq_nosync(ab->irq_num[irq_idx]); - tasklet_schedule(&ce_pipe->intr_tq); + queue_work(system_bh_wq, &ce_pipe->intr_wq); return IRQ_HANDLED; } @@ -675,7 +677,7 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab) irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i; - tasklet_setup(&ce_pipe->intr_tq, ath12k_pci_ce_tasklet); + INIT_WORK(&ce_pipe->intr_wq, ath12k_pci_ce_workqueue); ret = request_irq(irq, ath12k_pci_ce_interrupt_handler, ab_pci->irq_flags, irq_name[irq_idx], @@ -962,7 +964,7 @@ static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci) PCI_EXP_LNKCTL_ASPMC); } -static void ath12k_pci_kill_tasklets(struct ath12k_base *ab) +static void ath12k_pci_cancel_workqueue(struct ath12k_base *ab) { int i; @@ -972,7 +974,7 @@ static void ath12k_pci_kill_tasklets(struct ath12k_base *ab) if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; - tasklet_kill(&ce_pipe->intr_tq); + cancel_work_sync(&ce_pipe->intr_wq); } } @@ -980,7 +982,7 @@ static void ath12k_pci_ce_irq_disable_sync(struct ath12k_base *ab) { ath12k_pci_ce_irqs_disable(ab); ath12k_pci_sync_ce_irqs(ab); - ath12k_pci_kill_tasklets(ab); + ath12k_pci_cancel_workqueue(ab); } int ath12k_pci_map_service_to_pipe(struct ath12k_base *ab, u16 service_id, @@ -1259,6 +1261,186 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value) ab_pci->pci_ops->release(ab); } +#ifdef CONFIG_ATH12K_COREDUMP +static int ath12k_pci_coredump_calculate_size(struct ath12k_base *ab, u32 *dump_seg_sz) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl; + struct image_info *rddm_img, *fw_img; + struct ath12k_tlv_dump_data *dump_tlv; + enum ath12k_fw_crash_dump_type mem_type; + u32 len = 0, rddm_tlv_sz = 0, paging_tlv_sz = 0; + struct ath12k_dump_file_data *file_data; + int i; + + rddm_img = mhi_ctrl->rddm_image; + if (!rddm_img) { + ath12k_err(ab, "No RDDM dump found\n"); + return 0; + } + + fw_img = mhi_ctrl->fbc_image; + + for (i = 0; i < fw_img->entries ; i++) { + if (!fw_img->mhi_buf[i].buf) + continue; + + paging_tlv_sz += fw_img->mhi_buf[i].len; + } + dump_seg_sz[FW_CRASH_DUMP_PAGING_DATA] = paging_tlv_sz; + + for (i = 0; i < rddm_img->entries; i++) { + if (!rddm_img->mhi_buf[i].buf) + continue; + + rddm_tlv_sz += rddm_img->mhi_buf[i].len; + } + dump_seg_sz[FW_CRASH_DUMP_RDDM_DATA] = rddm_tlv_sz; + + for (i = 0; i < ab->qmi.mem_seg_count; i++) { + mem_type = ath12k_coredump_get_dump_type(ab->qmi.target_mem[i].type); + + if (mem_type == FW_CRASH_DUMP_NONE) + continue; + + if (mem_type == FW_CRASH_DUMP_TYPE_MAX) { + ath12k_dbg(ab, ATH12K_DBG_PCI, + "target mem region type %d not supported", + ab->qmi.target_mem[i].type); + continue; + } + + if (!ab->qmi.target_mem[i].paddr) + continue; + + dump_seg_sz[mem_type] += ab->qmi.target_mem[i].size; + } + + for (i = 0; i < FW_CRASH_DUMP_TYPE_MAX; i++) { + if (!dump_seg_sz[i]) + continue; + + len += sizeof(*dump_tlv) + dump_seg_sz[i]; + } + + if (len) + len += sizeof(*file_data); + + return len; +} + +static void ath12k_pci_coredump_download(struct ath12k_base *ab) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl; + struct image_info *rddm_img, *fw_img; + struct timespec64 timestamp; + int i, len, mem_idx; + enum ath12k_fw_crash_dump_type mem_type; + struct ath12k_dump_file_data *file_data; + struct ath12k_tlv_dump_data *dump_tlv; + size_t hdr_len = sizeof(*file_data); + void *buf; + u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = { 0 }; + + ath12k_mhi_coredump(mhi_ctrl, false); + + len = ath12k_pci_coredump_calculate_size(ab, dump_seg_sz); + if (!len) { + ath12k_warn(ab, "No crash dump data found for devcoredump"); + return; + } + + rddm_img = mhi_ctrl->rddm_image; + fw_img = mhi_ctrl->fbc_image; + + /* dev_coredumpv() requires vmalloc data */ + buf = vzalloc(len); + if (!buf) + return; + + ab->dump_data = buf; + ab->ath12k_coredump_len = len; + file_data = ab->dump_data; + strscpy(file_data->df_magic, "ATH12K-FW-DUMP", sizeof(file_data->df_magic)); + file_data->len = cpu_to_le32(len); + file_data->version = cpu_to_le32(ATH12K_FW_CRASH_DUMP_V2); + file_data->chip_id = cpu_to_le32(ab_pci->dev_id); + file_data->qrtr_id = cpu_to_le32(ab_pci->ab->qmi.service_ins_id); + file_data->bus_id = cpu_to_le32(pci_domain_nr(ab_pci->pdev->bus)); + guid_gen(&file_data->guid); + ktime_get_real_ts64(×tamp); + file_data->tv_sec = cpu_to_le64(timestamp.tv_sec); + file_data->tv_nsec = cpu_to_le64(timestamp.tv_nsec); + buf += hdr_len; + dump_tlv = buf; + dump_tlv->type = cpu_to_le32(FW_CRASH_DUMP_PAGING_DATA); + dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[FW_CRASH_DUMP_PAGING_DATA]); + buf += COREDUMP_TLV_HDR_SIZE; + + /* append all segments together as they are all part of a single contiguous + * block of memory + */ + for (i = 0; i < fw_img->entries ; i++) { + if (!fw_img->mhi_buf[i].buf) + continue; + + memcpy_fromio(buf, (void const __iomem *)fw_img->mhi_buf[i].buf, + fw_img->mhi_buf[i].len); + buf += fw_img->mhi_buf[i].len; + } + + dump_tlv = buf; + dump_tlv->type = cpu_to_le32(FW_CRASH_DUMP_RDDM_DATA); + dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[FW_CRASH_DUMP_RDDM_DATA]); + buf += COREDUMP_TLV_HDR_SIZE; + + /* append all segments together as they are all part of a single contiguous + * block of memory + */ + for (i = 0; i < rddm_img->entries; i++) { + if (!rddm_img->mhi_buf[i].buf) + continue; + + memcpy_fromio(buf, (void const __iomem *)rddm_img->mhi_buf[i].buf, + rddm_img->mhi_buf[i].len); + buf += rddm_img->mhi_buf[i].len; + } + + mem_idx = FW_CRASH_DUMP_REMOTE_MEM_DATA; + for (; mem_idx < FW_CRASH_DUMP_TYPE_MAX; mem_idx++) { + if (!dump_seg_sz[mem_idx] || mem_idx == FW_CRASH_DUMP_NONE) + continue; + + dump_tlv = buf; + dump_tlv->type = cpu_to_le32(mem_idx); + dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[mem_idx]); + buf += COREDUMP_TLV_HDR_SIZE; + + for (i = 0; i < ab->qmi.mem_seg_count; i++) { + mem_type = ath12k_coredump_get_dump_type + (ab->qmi.target_mem[i].type); + + if (mem_type != mem_idx) + continue; + + if (!ab->qmi.target_mem[i].paddr) { + ath12k_dbg(ab, ATH12K_DBG_PCI, + "Skipping mem region type %d", + ab->qmi.target_mem[i].type); + continue; + } + + memcpy_fromio(buf, ab->qmi.target_mem[i].v.ioaddr, + ab->qmi.target_mem[i].size); + buf += ab->qmi.target_mem[i].size; + } + } + + queue_work(ab->workqueue, &ab->dump_work); +} +#endif + int ath12k_pci_power_up(struct ath12k_base *ab) { struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); @@ -1329,6 +1511,9 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = { .ce_irq_disable = ath12k_pci_hif_ce_irq_disable, .get_ce_msi_idx = ath12k_pci_get_ce_msi_idx, .panic_handler = ath12k_pci_panic_handler, +#ifdef CONFIG_ATH12K_COREDUMP + .coredump_download = ath12k_pci_coredump_download, +#endif }; static @@ -1538,6 +1723,7 @@ static void ath12k_pci_remove(struct pci_dev *pdev) set_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags); cancel_work_sync(&ab->reset_work); + cancel_work_sync(&ab->dump_work); ath12k_core_deinit(ab); qmi_fail: diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c index 19c0626fbff1..7a62665b8af9 100644 --- a/drivers/net/wireless/ath/ath12k/peer.c +++ b/drivers/net/wireless/ath/ath12k/peer.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -186,7 +186,7 @@ void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id) struct ath12k_peer *peer, *tmp; struct ath12k_base *ab = ar->ab; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); spin_lock_bh(&ab->base_lock); list_for_each_entry_safe(peer, tmp, &ab->peers, list) { @@ -235,7 +235,7 @@ int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->peer_delete_done); @@ -261,14 +261,15 @@ static int ath12k_wait_for_peer_created(struct ath12k *ar, int vdev_id, const u8 return ath12k_wait_for_peer_common(ar->ab, vdev_id, addr, true); } -int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif, +int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ieee80211_sta *sta, struct ath12k_wmi_peer_create_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ath12k_peer *peer; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (ar->num_peers > (ar->max_num_peers - 1)) { ath12k_warn(ar->ab, @@ -326,7 +327,7 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif, peer->pdev_idx = ar->pdev_idx; peer->sta = sta; - if (arvif->vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION) { arvif->ast_hash = peer->ast_hash; arvif->ast_idx = peer->hw_peer_id; } diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h index 7b3500b5c8c2..b955f0cdf598 100644 --- a/drivers/net/wireless/ath/ath12k/peer.h +++ b/drivers/net/wireless/ath/ath12k/peer.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_PEER_H @@ -59,7 +59,7 @@ struct ath12k_peer *ath12k_peer_find_by_addr(struct ath12k_base *ab, struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab, int peer_id); void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id); int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr); -int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif, +int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ieee80211_sta *sta, struct ath12k_wmi_peer_create_arg *arg); int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id, diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index a0db6702a189..10366bbe9999 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.h @@ -684,18 +684,17 @@ enum rx_msdu_start_reception_type { #define RX_MSDU_END_INFO5_SA_IDX_TIMEOUT BIT(0) #define RX_MSDU_END_INFO5_DA_IDX_TIMEOUT BIT(1) +#define RX_MSDU_END_INFO5_TO_DS BIT(2) +#define RX_MSDU_END_INFO5_TID GENMASK(6, 3) #define RX_MSDU_END_INFO5_SA_IS_VALID BIT(7) #define RX_MSDU_END_INFO5_DA_IS_VALID BIT(8) #define RX_MSDU_END_INFO5_DA_IS_MCBC BIT(9) #define RX_MSDU_END_INFO5_L3_HDR_PADDING GENMASK(11, 10) #define RX_MSDU_END_INFO5_FIRST_MSDU BIT(12) #define RX_MSDU_END_INFO5_LAST_MSDU BIT(13) +#define RX_MSDU_END_INFO5_FROM_DS BIT(14) #define RX_MSDU_END_INFO5_IP_CHKSUM_FAIL_COPY BIT(15) -#define RX_MSDU_END_QCN9274_INFO5_TO_DS BIT(2) -#define RX_MSDU_END_QCN9274_INFO5_TID GENMASK(6, 3) -#define RX_MSDU_END_QCN9274_INFO5_FROM_DS BIT(14) - #define RX_MSDU_END_INFO6_MSDU_DROP BIT(0) #define RX_MSDU_END_INFO6_REO_DEST_IND GENMASK(5, 1) #define RX_MSDU_END_INFO6_FLOW_IDX GENMASK(25, 6) @@ -709,14 +708,14 @@ enum rx_msdu_start_reception_type { #define RX_MSDU_END_INFO7_FLOW_AGGR_CONTN BIT(8) #define RX_MSDU_END_INFO7_FISA_TIMEOUT BIT(9) -#define RX_MSDU_END_QCN9274_INFO7_TCPUDP_CSUM_FAIL_CPY BIT(10) -#define RX_MSDU_END_QCN9274_INFO7_MSDU_LIMIT_ERROR BIT(11) -#define RX_MSDU_END_QCN9274_INFO7_FLOW_IDX_TIMEOUT BIT(12) -#define RX_MSDU_END_QCN9274_INFO7_FLOW_IDX_INVALID BIT(13) -#define RX_MSDU_END_QCN9274_INFO7_CCE_MATCH BIT(14) -#define RX_MSDU_END_QCN9274_INFO7_AMSDU_PARSER_ERR BIT(15) +#define RX_MSDU_END_INFO7_TCPUDP_CSUM_FAIL_CPY BIT(10) +#define RX_MSDU_END_INFO7_MSDU_LIMIT_ERROR BIT(11) +#define RX_MSDU_END_INFO7_FLOW_IDX_TIMEOUT BIT(12) +#define RX_MSDU_END_INFO7_FLOW_IDX_INVALID BIT(13) +#define RX_MSDU_END_INFO7_CCE_MATCH BIT(14) +#define RX_MSDU_END_INFO7_AMSDU_PARSER_ERR BIT(15) -#define RX_MSDU_END_QCN9274_INFO8_KEY_ID GENMASK(7, 0) +#define RX_MSDU_END_INFO8_KEY_ID GENMASK(7, 0) #define RX_MSDU_END_INFO9_SERVICE_CODE GENMASK(14, 6) #define RX_MSDU_END_INFO9_PRIORITY_VALID BIT(15) @@ -758,8 +757,8 @@ enum rx_msdu_start_reception_type { #define RX_MSDU_END_INFO12_RECV_BW GENMASK(20, 18) #define RX_MSDU_END_INFO12_RECEPTION_TYPE GENMASK(23, 21) -#define RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP GENMASK(30, 24) -#define RX_MSDU_END_QCN9274_INFO12_MIMO_DONE_COPY BIT(31) +#define RX_MSDU_END_INFO12_MIMO_SS_BITMAP GENMASK(30, 24) +#define RX_MSDU_END_INFO12_MIMO_DONE_COPY BIT(31) #define RX_MSDU_END_INFO13_FIRST_MPDU BIT(0) #define RX_MSDU_END_INFO13_MCAST_BCAST BIT(2) @@ -791,7 +790,7 @@ enum rx_msdu_start_reception_type { #define RX_MSDU_END_INFO13_UNDECRYPT_FRAME_ERR BIT(30) #define RX_MSDU_END_INFO13_FCS_ERR BIT(31) -#define RX_MSDU_END_QCN9274_INFO13_WIFI_PARSER_ERR BIT(15) +#define RX_MSDU_END_INFO13_WIFI_PARSER_ERR BIT(15) #define RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE GENMASK(12, 10) #define RX_MSDU_END_INFO14_RX_BITMAP_NOT_UPDED BIT(13) @@ -889,65 +888,6 @@ struct rx_msdu_end_qcn9274_compact { __le32 info14; } __packed; -/* These macro definitions are only used for WCN7850 */ -#define RX_MSDU_END_WCN7850_INFO2_KEY_ID BIT(7, 0) - -#define RX_MSDU_END_WCN7850_INFO5_MSDU_LIMIT_ERR BIT(2) -#define RX_MSDU_END_WCN7850_INFO5_IDX_TIMEOUT BIT(3) -#define RX_MSDU_END_WCN7850_INFO5_IDX_INVALID BIT(4) -#define RX_MSDU_END_WCN7850_INFO5_WIFI_PARSE_ERR BIT(5) -#define RX_MSDU_END_WCN7850_INFO5_AMSDU_PARSER_ERR BIT(6) -#define RX_MSDU_END_WCN7850_INFO5_TCPUDP_CSUM_FAIL_CPY BIT(14) - -#define RX_MSDU_END_WCN7850_INFO12_MIMO_SS_BITMAP GENMASK(31, 24) - -#define RX_MSDU_END_WCN7850_INFO13_FRAGMENT_FLAG BIT(13) -#define RX_MSDU_END_WCN7850_INFO13_CCE_MATCH BIT(15) - -struct rx_msdu_end_wcn7850 { - __le16 info0; - __le16 phy_ppdu_id; - __le16 ip_hdr_cksum; - __le16 info1; - __le16 info2; - __le16 cumulative_l3_checksum; - __le32 rule_indication0; - __le32 rule_indication1; - __le16 info3; - __le16 l3_type; - __le32 ipv6_options_crc; - __le32 tcp_seq_num; - __le32 tcp_ack_num; - __le16 info4; - __le16 window_size; - __le16 tcp_udp_chksum; - __le16 info5; - __le16 sa_idx; - __le16 da_idx_or_sw_peer_id; - __le32 info6; - __le32 fse_metadata; - __le16 cce_metadata; - __le16 sa_sw_peer_id; - __le16 info7; - __le16 rsvd0; - __le16 cumulative_l4_checksum; - __le16 cumulative_ip_length; - __le32 info9; - __le32 info10; - __le32 info11; - __le32 toeplitz_hash_2_or_4; - __le32 flow_id_toeplitz; - __le32 info12; - __le32 ppdu_start_timestamp_31_0; - __le32 ppdu_start_timestamp_63_32; - __le32 phy_meta_data; - __le16 vlan_ctag_ci; - __le16 vlan_stag_ci; - __le32 rsvd[3]; - __le32 info13; - __le32 info14; -} __packed; - /* rx_msdu_end * * rxpcu_mpdu_filter_in_category @@ -1578,7 +1518,7 @@ struct rx_pkt_hdr_tlv { struct hal_rx_desc_wcn7850 { __le64 msdu_end_tag; - struct rx_msdu_end_wcn7850 msdu_end; + struct rx_msdu_end_qcn9274 msdu_end; u8 rx_padding0[RX_BE_PADDING0_BYTES]; __le64 mpdu_start_tag; struct rx_mpdu_start_qcn9274 mpdu_start; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 2cd3ff9b0164..dced2aa9ba1a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6687,7 +6687,8 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab, const u32 *vdev_ids) { int i; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; + struct ath12k_vif *ahvif; /* Finish CSA once the switch count becomes NULL */ if (ev->current_switch_count) @@ -6702,9 +6703,10 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab, vdev_ids[i]); continue; } + ahvif = arvif->ahvif; - if (arvif->is_up && arvif->vif->bss_conf.csa_active) - ieee80211_csa_finish(arvif->vif, 0); + if (arvif->is_up && ahvif->vif->bss_conf.csa_active) + ieee80211_csa_finish(ahvif->vif, 0); } rcu_read_unlock(); } @@ -7098,7 +7100,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, struct sk_buff *skb) { const struct wmi_gtk_offload_status_event *ev; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; __be64 replay_ctr_be; u64 replay_ctr; const void **tb; @@ -7136,7 +7138,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, /* supplicant expects big-endian replay counter */ replay_ctr_be = cpu_to_be64(replay_ctr); - ieee80211_gtk_rekey_notify(arvif->vif, arvif->bssid, + ieee80211_gtk_rekey_notify(arvif->ahvif->vif, arvif->bssid, (void *)&replay_ctr_be, GFP_ATOMIC); rcu_read_unlock(); @@ -7284,9 +7286,11 @@ static int ath12k_connect_pdev_htc_service(struct ath12k_base *ab, u32 pdev_idx) { int status; - u32 svc_id[] = { ATH12K_HTC_SVC_ID_WMI_CONTROL, - ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1, - ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2 }; + static const u32 svc_id[] = { + ATH12K_HTC_SVC_ID_WMI_CONTROL, + ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1, + ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2 + }; struct ath12k_htc_svc_conn_req conn_req = {}; struct ath12k_htc_svc_conn_resp conn_resp = {}; @@ -7372,13 +7376,13 @@ ath12k_wmi_send_unit_test_cmd(struct ath12k *ar, int ath12k_wmi_simulate_radar(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; u32 dfs_args[DFS_MAX_TEST_ARGS]; struct wmi_unit_test_cmd wmi_ut; bool arvif_found = false; list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) { + if (arvif->is_started && arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP) { arvif_found = true; break; } @@ -7940,7 +7944,7 @@ static void ath12k_wmi_fill_arp_offload(struct ath12k *ar, } int ath12k_wmi_arp_ns_offload(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct wmi_arp_ns_offload_arg *offload, bool enable) { @@ -7989,7 +7993,7 @@ int ath12k_wmi_arp_ns_offload(struct ath12k *ar, } int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, - struct ath12k_vif *arvif, bool enable) + struct ath12k_link_vif *arvif, bool enable) { struct ath12k_rekey_data *rekey_data = &arvif->rekey_data; struct wmi_gtk_rekey_offload_cmd *cmd; @@ -8026,7 +8030,7 @@ int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, } int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, - struct ath12k_vif *arvif) + struct ath12k_link_vif *arvif) { struct wmi_gtk_rekey_offload_cmd *cmd; struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 6a913f9b8315..6f55dbdf629d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -24,7 +24,7 @@ struct ath12k_base; struct ath12k; -struct ath12k_vif; +struct ath12k_link_vif; /* There is no signed version of __le32, so for a temporary solution come * up with our own version. The idea is from fs/ntfs/endian.h. @@ -5627,13 +5627,13 @@ int ath12k_wmi_wow_config_pno(struct ath12k *ar, u32 vdev_id, int ath12k_wmi_hw_data_filter_cmd(struct ath12k *ar, struct wmi_hw_data_filter_arg *arg); int ath12k_wmi_arp_ns_offload(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct wmi_arp_ns_offload_arg *offload, bool enable); int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, - struct ath12k_vif *arvif, bool enable); + struct ath12k_link_vif *arvif, bool enable); int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, - struct ath12k_vif *arvif); + struct ath12k_link_vif *arvif); int ath12k_wmi_sta_keepalive(struct ath12k *ar, const struct wmi_sta_keepalive_arg *arg); diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index 9b8684abbe40..9e1c0bfd212f 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -29,11 +29,11 @@ static const struct wiphy_wowlan_support ath12k_wowlan_support = { .max_pkt_offset = WOW_MAX_PKT_OFFSET, }; -static inline bool ath12k_wow_is_p2p_vdev(struct ath12k_vif *arvif) +static inline bool ath12k_wow_is_p2p_vdev(struct ath12k_vif *ahvif) { - return (arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_DEVICE || - arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_CLIENT || - arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_GO); + return (ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_DEVICE || + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_CLIENT || + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_GO); } int ath12k_wow_enable(struct ath12k *ar) @@ -101,7 +101,7 @@ int ath12k_wow_wakeup(struct ath12k *ar) return 0; } -static int ath12k_wow_vif_cleanup(struct ath12k_vif *arvif) +static int ath12k_wow_vif_cleanup(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; int i, ret; @@ -129,10 +129,10 @@ static int ath12k_wow_vif_cleanup(struct ath12k_vif *arvif) static int ath12k_wow_cleanup(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { ret = ath12k_wow_vif_cleanup(arvif); @@ -191,7 +191,7 @@ ath12k_wow_convert_8023_to_80211(struct ath12k *ar, memcpy(bytemask, eth_bytemask, eth_pat_len); pat_len = eth_pat_len; - } else if (eth_pkt_ofs + eth_pat_len < prot_ofs) { + } else if (size_add(eth_pkt_ofs, eth_pat_len) < prot_ofs) { memcpy(pat, eth_pat, ETH_ALEN - eth_pkt_ofs); memcpy(bytemask, eth_bytemask, ETH_ALEN - eth_pkt_ofs); @@ -354,7 +354,7 @@ ath12k_wow_pno_check_and_convert(struct ath12k *ar, u32 vdev_id, return 0; } -static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif, +static int ath12k_wow_vif_set_wakeups(struct ath12k_link_vif *arvif, struct cfg80211_wowlan *wowlan) { const struct cfg80211_pkt_pattern *patterns = wowlan->patterns; @@ -364,7 +364,7 @@ static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif, int ret, i, j; /* Setup requested WOW features */ - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_IBSS: __set_bit(WOW_BEACON_EVENT, &wow_mask); fallthrough; @@ -473,13 +473,13 @@ static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif, static int ath12k_wow_set_wakeups(struct ath12k *ar, struct cfg80211_wowlan *wowlan) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (ath12k_wow_is_p2p_vdev(arvif)) + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) continue; ret = ath12k_wow_vif_set_wakeups(arvif, wowlan); if (ret) { @@ -518,11 +518,11 @@ out: return ret; } -static int ath12k_wow_vif_clean_nlo(struct ath12k_vif *arvif) +static int ath12k_wow_vif_clean_nlo(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_STA: return ath12k_wow_vdev_clean_nlo(ar, arvif->vdev_id); default: @@ -532,13 +532,13 @@ static int ath12k_wow_vif_clean_nlo(struct ath12k_vif *arvif) static int ath12k_wow_nlo_cleanup(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (ath12k_wow_is_p2p_vdev(arvif)) + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) continue; ret = ath12k_wow_vif_clean_nlo(arvif); @@ -555,13 +555,13 @@ static int ath12k_wow_nlo_cleanup(struct ath12k *ar) static int ath12k_wow_set_hw_filter(struct ath12k *ar) { struct wmi_hw_data_filter_arg arg; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA) continue; arg.vdev_id = arvif->vdev_id; @@ -581,13 +581,13 @@ static int ath12k_wow_set_hw_filter(struct ath12k *ar) static int ath12k_wow_clear_hw_filter(struct ath12k *ar) { struct wmi_hw_data_filter_arg arg; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA) continue; arg.vdev_id = arvif->vdev_id; @@ -626,10 +626,10 @@ static void ath12k_wow_generate_ns_mc_addr(struct ath12k_base *ab, } } -static void ath12k_wow_prepare_ns_offload(struct ath12k_vif *arvif, +static void ath12k_wow_prepare_ns_offload(struct ath12k_link_vif *arvif, struct wmi_arp_ns_offload_arg *offload) { - struct net_device *ndev = ieee80211_vif_to_wdev(arvif->vif)->netdev; + struct net_device *ndev = ieee80211_vif_to_wdev(arvif->ahvif->vif)->netdev; struct ath12k_base *ab = arvif->ar->ab; struct inet6_ifaddr *ifa6; struct ifacaddr6 *ifaca6; @@ -710,10 +710,10 @@ unlock: ath12k_wow_generate_ns_mc_addr(ab, offload); } -static void ath12k_wow_prepare_arp_offload(struct ath12k_vif *arvif, +static void ath12k_wow_prepare_arp_offload(struct ath12k_link_vif *arvif, struct wmi_arp_ns_offload_arg *offload) { - struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif *vif = arvif->ahvif->vif; struct ieee80211_vif_cfg vif_cfg = vif->cfg; struct ath12k_base *ab = arvif->ar->ab; u32 ipv4_cnt; @@ -732,22 +732,25 @@ static void ath12k_wow_prepare_arp_offload(struct ath12k_vif *arvif, static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) { struct wmi_arp_ns_offload_arg *offload; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; + struct ath12k_vif *ahvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); offload = kmalloc(sizeof(*offload), GFP_KERNEL); if (!offload) return -ENOMEM; list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + ahvif = arvif->ahvif; + + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA) continue; memset(offload, 0, sizeof(*offload)); - memcpy(offload->mac_addr, arvif->vif->addr, ETH_ALEN); + memcpy(offload->mac_addr, ahvif->vif->addr, ETH_ALEN); ath12k_wow_prepare_ns_offload(arvif, offload); ath12k_wow_prepare_arp_offload(arvif, offload); @@ -766,13 +769,13 @@ static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) static int ath12k_gtk_rekey_offload(struct ath12k *ar, bool enable) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->vdev_type != WMI_VDEV_TYPE_STA || + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA || !arvif->is_up || !arvif->rekey_data.enable_offload) continue; @@ -824,10 +827,10 @@ static int ath12k_wow_set_keepalive(struct ath12k *ar, enum wmi_sta_keepalive_method method, u32 interval) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { ret = ath12k_mac_vif_set_keepalive(arvif, method, interval); @@ -845,7 +848,7 @@ int ath12k_wow_op_suspend(struct ieee80211_hw *hw, struct ath12k *ar = ath12k_ah_to_ar(ah, 0); int ret; - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); ret = ath12k_wow_cleanup(ar); if (ret) { @@ -913,7 +916,6 @@ cleanup: ath12k_wow_cleanup(ar); exit: - mutex_unlock(&ar->conf_mutex); return ret ? 1 : 0; } @@ -922,9 +924,9 @@ void ath12k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar = ath12k_ah_to_ar(ah, 0); - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); + device_set_wakeup_enable(ar->ab->dev, enabled); - mutex_unlock(&ar->conf_mutex); } int ath12k_wow_op_resume(struct ieee80211_hw *hw) @@ -933,7 +935,7 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw) struct ath12k *ar = ath12k_ah_to_ar(ah, 0); int ret; - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); ret = ath12k_hif_resume(ar->ab); if (ret) { @@ -995,7 +997,6 @@ exit: } } - mutex_unlock(&ar->conf_mutex); return ret; } diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index f27308ccb2f1..cb3e891ee1bd 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -218,10 +218,10 @@ static void ath_ahb_remove(struct platform_device *pdev) } static struct platform_driver ath_ahb_driver = { - .probe = ath_ahb_probe, - .remove_new = ath_ahb_remove, - .driver = { - .name = "ar231x-wmac", + .probe = ath_ahb_probe, + .remove = ath_ahb_remove, + .driver = { + .name = "ar231x-wmac", }, }; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index b51fce5ae260..f5ca2fe0d074 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -46,6 +46,8 @@ static const struct pci_device_id ath5k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */ { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */ { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */ + { PCI_VDEVICE(ATHEROS, 0xff16) }, /* Gigaset SX76[23] AR241[34]A */ + { PCI_VDEVICE(ATHEROS, 0xff1a) }, /* Arcadyan ARV45XX AR2417 */ { PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */ { 0 } }; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index b4fcfb72991c..68384159870b 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1249,7 +1249,7 @@ struct wmi_rssi_threshold_params_cmd { /* highest of upper */ a_sle16 thresh_above6_val; - /* lowest of bellow */ + /* lowest of below */ a_sle16 thresh_below1_val; a_sle16 thresh_below2_val; @@ -1257,7 +1257,7 @@ struct wmi_rssi_threshold_params_cmd { a_sle16 thresh_below4_val; a_sle16 thresh_below5_val; - /* highest of bellow */ + /* highest of below */ a_sle16 thresh_below6_val; /* "alpha" */ @@ -1287,13 +1287,13 @@ struct wmi_snr_threshold_params_cmd { /* highest of upper */ u8 thresh_above4_val; - /* lowest of bellow */ + /* lowest of below */ u8 thresh_below1_val; u8 thresh_below2_val; u8 thresh_below3_val; - /* highest of bellow */ + /* highest of below */ u8 thresh_below4_val; u8 reserved[3]; diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 1a6697b6e3b4..d4805e02b927 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -158,12 +158,12 @@ static void ath_ahb_remove(struct platform_device *pdev) } static struct platform_driver ath_ahb_driver = { - .probe = ath_ahb_probe, - .remove_new = ath_ahb_remove, - .driver = { - .name = "ath9k", + .probe = ath_ahb_probe, + .remove = ath_ahb_remove, + .driver = { + .name = "ath9k", }, - .id_table = ath9k_platform_id_table, + .id_table = ath9k_platform_id_table, }; MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index d0f1e8bcc846..45a7ca660f47 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -409,13 +409,11 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah) sram.valid = true; sram.rot_dir_att_db = - min(max(rot_dir_path_att_db, - (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB), - ATH_AIC_MAX_ROT_DIR_ATT_DB); + clamp(rot_dir_path_att_db, (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB, + ATH_AIC_MAX_ROT_DIR_ATT_DB); sram.rot_quad_att_db = - min(max(rot_quad_path_att_db, - (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB), - ATH_AIC_MAX_ROT_QUAD_ATT_DB); + clamp(rot_quad_path_att_db, (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB, + ATH_AIC_MAX_ROT_QUAD_ATT_DB); aic->aic_sram[i] = (SM(sram.vga_dir_sign, AR_PHY_AIC_SRAM_VGA_DIR_SIGN) | diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c index 004ca5f536be..fe1013a3a588 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c @@ -18,7 +18,6 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/ath9k_platform.h> #include <linux/nvmem-consumer.h> #include <linux/workqueue.h> diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 9b393a8f7c3a..ad3a3fda1b9c 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -16,7 +16,6 @@ #include <linux/export.h> #include <linux/types.h> -#include <linux/ath9k_platform.h> #include "hw.h" enum ath_bt_mode { @@ -115,23 +114,14 @@ static void ath9k_hw_btcoex_pin_init(struct ath_hw *ah, u8 wlanactive_gpio, u8 btactive_gpio, u8 btpriority_gpio) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - struct ath9k_platform_data *pdata = ah->dev->platform_data; if (btcoex_hw->scheme != ATH_BTCOEX_CFG_2WIRE && btcoex_hw->scheme != ATH_BTCOEX_CFG_3WIRE) return; - /* bt priority GPIO will be ignored by 2 wire scheme */ - if (pdata && (pdata->bt_active_pin || pdata->bt_priority_pin || - pdata->wlan_active_pin)) { - btcoex_hw->btactive_gpio = pdata->bt_active_pin; - btcoex_hw->wlanactive_gpio = pdata->wlan_active_pin; - btcoex_hw->btpriority_gpio = pdata->bt_priority_pin; - } else { - btcoex_hw->btactive_gpio = btactive_gpio; - btcoex_hw->wlanactive_gpio = wlanactive_gpio; - btcoex_hw->btpriority_gpio = btpriority_gpio; - } + btcoex_hw->btactive_gpio = btactive_gpio; + btcoex_hw->wlanactive_gpio = wlanactive_gpio; + btcoex_hw->btpriority_gpio = btpriority_gpio; } void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index efb7889142d4..df58dc02e104 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -15,7 +15,6 @@ */ #include "hw.h" -#include <linux/ath9k_platform.h> void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) { @@ -119,14 +118,6 @@ static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size, return true; } -static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata, - off_t offset, u16 *data) -{ - return ath9k_hw_nvram_read_array(pdata->eeprom_data, - ARRAY_SIZE(pdata->eeprom_data), - offset, data); -} - static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob, off_t offset, u16 *data) { @@ -146,15 +137,12 @@ static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset, bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_platform_data *pdata = ah->dev->platform_data; bool ret; if (ah->nvmem_blob) ret = ath9k_hw_nvram_read_nvmem(ah, off, data); else if (ah->eeprom_blob) ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data); - else if (pdata && !pdata->use_eeprom) - ret = ath9k_hw_nvram_read_pdata(pdata, off, data); else ret = common->bus_ops->eeprom_read(common, off, data); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 8a03bcc2789e..57094bd45d98 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1357,8 +1357,10 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, + u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED)) @@ -1883,7 +1885,7 @@ struct ieee80211_ops ath9k_htc_ops = { .sta_add = ath9k_htc_sta_add, .sta_remove = ath9k_htc_sta_remove, .conf_tx = ath9k_htc_conf_tx, - .sta_rc_update = ath9k_htc_sta_rc_update, + .link_sta_rc_update = ath9k_htc_sta_rc_update, .bss_info_changed = ath9k_htc_bss_info_changed, .set_key = ath9k_htc_set_key, .get_tsf = ath9k_htc_get_tsf, diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index eb631fd3336d..b5257b2b4aa5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -294,6 +294,9 @@ int htc_connect_service(struct htc_target *target, return -ETIMEDOUT; } + if (target->conn_rsp_epid < 0 || target->conn_rsp_epid >= ENDPOINT_MAX) + return -EINVAL; + *conn_rsp_epid = target->conn_rsp_epid; return 0; err: diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c3a6368bfc68..e2bef099adb3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -490,7 +490,7 @@ static void ath9k_hw_init_macaddr(struct ath_hw *ah) u16 eeval; static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; - /* MAC address may already be loaded via ath9k_platform_data */ + /* MAC address may already be loaded via NVMEM */ if (is_valid_ether_addr(common->macaddr)) return; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 7fad7e75af6a..f9e77c4624d9 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -18,7 +18,6 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> -#include <linux/ath9k_platform.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_net.h> @@ -583,8 +582,8 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) /* nvmem cell might not be defined, or the nvmem * subsystem isn't included. In this case, follow - * the established "just return 0;" convention of - * ath9k_init_platform to say: + * the established "just return 0;" convention + * to say: * "All good. Nothing to see here. Please go on." */ if (err == -ENOENT || err == -EOPNOTSUPP) @@ -620,49 +619,6 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) return 0; } -static int ath9k_init_platform(struct ath_softc *sc) -{ - struct ath9k_platform_data *pdata = sc->dev->platform_data; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int ret; - - if (!pdata) - return 0; - - if (!pdata->use_eeprom) { - ah->ah_flags &= ~AH_USE_EEPROM; - ah->gpio_mask = pdata->gpio_mask; - ah->gpio_val = pdata->gpio_val; - ah->led_pin = pdata->led_pin; - ah->is_clk_25mhz = pdata->is_clk_25mhz; - ah->get_mac_revision = pdata->get_mac_revision; - ah->external_reset = pdata->external_reset; - ah->disable_2ghz = pdata->disable_2ghz; - ah->disable_5ghz = pdata->disable_5ghz; - - if (!pdata->endian_check) - ah->ah_flags |= AH_NO_EEP_SWAP; - } - - if (pdata->eeprom_name) { - ret = ath9k_eeprom_request(sc, pdata->eeprom_name); - if (ret) - return ret; - } - - if (pdata->led_active_high) - ah->config.led_active_high = true; - - if (pdata->tx_gain_buffalo) - ah->config.tx_gain_buffalo = true; - - if (pdata->macaddr) - ether_addr_copy(common->macaddr, pdata->macaddr); - - return 0; -} - static int ath9k_of_init(struct ath_softc *sc) { struct device_node *np = sc->dev->of_node; @@ -748,10 +704,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, */ ath9k_init_pcoem_platform(sc); - ret = ath9k_init_platform(sc); - if (ret) - return ret; - ret = ath9k_of_init(sc); if (ret) return ret; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 408776562a7e..8557d4826a46 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1679,10 +1679,10 @@ static const struct of_device_id wcn36xx_of_match[] = { MODULE_DEVICE_TABLE(of, wcn36xx_of_match); static struct platform_driver wcn36xx_driver = { - .probe = wcn36xx_probe, - .remove_new = wcn36xx_remove, - .driver = { - .name = "wcn36xx", + .probe = wcn36xx_probe, + .remove = wcn36xx_remove, + .driver = { + .name = "wcn36xx", .of_match_table = wcn36xx_of_match, }, }; diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index bccc27de848d..7ee79593cd23 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -167,7 +167,7 @@ struct wcn36xx_vif { * @dpu_desc_index: DPU descriptor index is returned from HW after config_sta * call and is used in TX BD. * @bss_sta_index: STA index is returned from HW after config_bss call and is - * used in both SMD channel and TX BD. See table bellow when it is used. + * used in both SMD channel and TX BD. See table below when it is used. * @bss_dpu_desc_index: DPU descriptor index is returned from HW after * config_bss call and is used in TX BD. * ______________________________________________ diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index e8f1d30a8d73..a1a0a9223e74 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1493,6 +1493,7 @@ out: } static int wil_cfg80211_set_channel(struct wiphy *wiphy, + struct net_device *dev, struct cfg80211_chan_def *chandef) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index d35262335eaf..42d991d9f8cb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -770,7 +770,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, sdiodev->settings->bus.sdio.txglomsz); - nents += (nents >> 4) + 1; + nents *= 2; WARN_ON(nents > sdiodev->max_segment_count); @@ -947,8 +947,8 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) /* try to attach to the target device */ sdiodev->bus = brcmf_sdio_probe(sdiodev); - if (!sdiodev->bus) { - ret = -ENODEV; + if (IS_ERR(sdiodev->bus)) { + ret = PTR_ERR(sdiodev->bus); goto out; } brcmf_sdiod_host_fixup(sdiodev->func2->card->host); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 349aa3439502..297a7c738c01 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -7820,13 +7820,6 @@ s32 brcmf_cfg80211_down(struct net_device *ndev) return err; } -enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp) -{ - struct wireless_dev *wdev = &ifp->vif->wdev; - - return wdev->iftype; -} - bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index dc3a6a537507..2abae8894614 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -443,7 +443,6 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); s32 brcmf_cfg80211_up(struct net_device *ndev); s32 brcmf_cfg80211_down(struct net_device *ndev); struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings); -enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp); struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, enum nl80211_iftype type); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index b24faae35873..cfcf01eb0daa 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -561,7 +561,8 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, if (!found) { /* No platform data for this device, try OF and DMI data */ brcmf_dmi_probe(settings, chip, chiprev); - brcmf_of_probe(dev, bus_type, settings); + if (brcmf_of_probe(dev, bus_type, settings) == -EPROBE_DEFER) + return ERR_PTR(-EPROBE_DEFER); brcmf_acpi_probe(dev, bus_type, settings); } return settings; @@ -593,7 +594,7 @@ static void brcmf_common_pd_remove(struct platform_device *pdev) } static struct platform_driver brcmf_pd = { - .remove_new = brcmf_common_pd_remove, + .remove = brcmf_common_pd_remove, .driver = { .name = BRCMFMAC_PDATA_NAME, } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index fe4f65756105..c1f18e2fe540 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -6,6 +6,7 @@ #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_net.h> +#include <linux/clk.h> #include <defs.h> #include "debug.h" @@ -65,12 +66,13 @@ static int brcmf_of_get_country_codes(struct device *dev, return 0; } -void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings) +int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + struct brcmf_mp_device *settings) { struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio; struct device_node *root, *np = dev->of_node; struct of_phandle_args oirq; + struct clk *clk; const char *prop; int irq; int err; @@ -106,16 +108,21 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, board_type = devm_kstrdup(dev, tmp, GFP_KERNEL); if (!board_type) { of_node_put(root); - return; + return 0; } strreplace(board_type, '/', '-'); settings->board_type = board_type; - - of_node_put(root); } + of_node_put(root); + + clk = devm_clk_get_optional_enabled_with_rate(dev, "lpo", 32768); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + brcmf_dbg(INFO, "%s LPO clock\n", clk ? "enable" : "no"); if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) - return; + return 0; err = brcmf_of_get_country_codes(dev, settings); if (err) @@ -124,23 +131,25 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, of_get_mac_address(np, settings->mac); if (bus_type != BRCMF_BUSTYPE_SDIO) - return; + return 0; if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) sdio->drive_strength = val; /* make sure there are interrupts defined in the node */ if (of_irq_parse_one(np, 0, &oirq)) - return; + return 0; irq = irq_create_of_mapping(&oirq); if (!irq) { brcmf_err("interrupt could not be mapped\n"); - return; + return 0; } - irqf = irqd_get_trigger_type(irq_get_irq_data(irq)); + irqf = irq_get_trigger_type(irq); sdio->oob_irq_supported = true; sdio->oob_irq_nr = irq; sdio->oob_irq_flags = irqf; + + return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h index 10bf52253337..ae124c73fc3b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h @@ -3,11 +3,12 @@ * Copyright (c) 2014 Broadcom Corporation */ #ifdef CONFIG_OF -void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings); +int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + struct brcmf_mp_device *settings); #else -static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings) +static int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + struct brcmf_mp_device *settings) { + return 0; } #endif /* CONFIG_OF */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 5dee54819fbd..e4395b1f8c11 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -66,6 +66,7 @@ BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie"); BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); +BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-pcie"); BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie"); @@ -104,6 +105,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), + BRCMF_FW_ENTRY(BRCM_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752), BRCMF_FW_ENTRY(BRCM_CC_4377_CHIP_ID, 0xFFFFFFFF, 4377B3), /* revision ID 4 */ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0x0000000F, 4378B1), /* revision ID 3 */ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFE0, 4378B3), /* revision ID 5 */ @@ -353,6 +355,7 @@ struct brcmf_pciedev_info { u16 value); struct brcmf_mp_device *settings; struct brcmf_otp_params otp; + bool fwseed; #ifdef DEBUG u32 console_interval; bool console_active; @@ -1715,14 +1718,14 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, memcpy_toio(devinfo->tcm + address, nvram, nvram_len); brcmf_fw_nvram_free(nvram); - if (devinfo->otp.valid) { + if (devinfo->fwseed) { size_t rand_len = BRCMF_RANDOM_SEED_LENGTH; struct brcmf_random_seed_footer footer = { .length = cpu_to_le32(rand_len), .magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC), }; - /* Some Apple chips/firmwares expect a buffer of random + /* Some chips/firmwares expect a buffer of random * data to be present before NVRAM */ brcmf_dbg(PCIE, "Download random seed\n"); @@ -2394,6 +2397,37 @@ static void brcmf_pcie_debugfs_create(struct device *dev) } #endif +struct brcmf_pcie_drvdata { + enum brcmf_fwvendor vendor; + bool fw_seed; +}; + +enum { + BRCMF_DRVDATA_CYW, + BRCMF_DRVDATA_BCA, + BRCMF_DRVDATA_WCC, + BRCMF_DRVDATA_WCC_SEED, +}; + +static const struct brcmf_pcie_drvdata drvdata[] = { + [BRCMF_DRVDATA_CYW] = { + .vendor = BRCMF_FWVENDOR_CYW, + .fw_seed = false, + }, + [BRCMF_DRVDATA_BCA] = { + .vendor = BRCMF_FWVENDOR_BCA, + .fw_seed = false, + }, + [BRCMF_DRVDATA_WCC] = { + .vendor = BRCMF_FWVENDOR_WCC, + .fw_seed = false, + }, + [BRCMF_DRVDATA_WCC_SEED] = { + .vendor = BRCMF_FWVENDOR_WCC, + .fw_seed = true, + }, +}; + /* Forward declaration for pci_match_id() call */ static const struct pci_device_id brcmf_pcie_devid_table[]; @@ -2452,6 +2486,9 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = -ENOMEM; goto fail; } + ret = PTR_ERR_OR_ZERO(devinfo->settings); + if (ret < 0) + goto fail; bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (!bus) { @@ -2472,9 +2509,10 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) bus->bus_priv.pcie = pcie_bus_dev; bus->ops = &brcmf_pcie_bus_ops; bus->proto_type = BRCMF_PROTO_MSGBUF; - bus->fwvid = id->driver_data; bus->chip = devinfo->coreid; bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot); + bus->fwvid = drvdata[id->driver_data].vendor; + devinfo->fwseed = drvdata[id->driver_data].fw_seed; dev_set_drvdata(&pdev->dev, bus); ret = brcmf_alloc(&devinfo->pdev->dev, devinfo->settings); @@ -2660,14 +2698,14 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = { BRCM_PCIE_VENDOR_ID_BROADCOM, (dev_id), \ PCI_ANY_ID, PCI_ANY_ID, \ PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \ - BRCMF_FWVENDOR_ ## fw_vend \ + BRCMF_DRVDATA_ ## fw_vend \ } #define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev, fw_vend) \ { \ BRCM_PCIE_VENDOR_ID_BROADCOM, (dev_id), \ (subvend), (subdev), \ PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \ - BRCMF_FWVENDOR_ ## fw_vend \ + BRCMF_DRVDATA_ ## fw_vend \ } static const struct pci_device_id brcmf_pcie_devid_table[] = { @@ -2695,9 +2733,10 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID, BCA), BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID, WCC), BRCMF_PCIE_DEVICE(BRCM_PCIE_43596_DEVICE_ID, CYW), - BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC), - BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC), - BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC_SEED), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC_SEED), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC_SEED), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43752_DEVICE_ID, WCC_SEED), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 7b936668c1b6..b1727f35217b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -3943,7 +3943,7 @@ static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = { .write32 = brcmf_sdio_buscore_write32, }; -static bool +static int brcmf_sdio_probe_attach(struct brcmf_sdio *bus) { struct brcmf_sdio_dev *sdiodev; @@ -3953,6 +3953,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) u32 reg_val; u32 drivestrength; u32 enum_base; + int ret = -EBADE; sdiodev = bus->sdiodev; sdio_claim_host(sdiodev->func1); @@ -4001,8 +4002,9 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) BRCMF_BUSTYPE_SDIO, bus->ci->chip, bus->ci->chiprev); - if (!sdiodev->settings) { + if (IS_ERR_OR_NULL(sdiodev->settings)) { brcmf_err("Failed to get device parameters\n"); + ret = PTR_ERR_OR_ZERO(sdiodev->settings); goto fail; } /* platform specific configuration: @@ -4071,7 +4073,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) /* allocate header buffer */ bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL); if (!bus->hdrbuf) - return false; + return -ENOMEM; /* Locate an appropriately-aligned portion of hdrbuf */ bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], bus->head_align); @@ -4082,11 +4084,11 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) if (bus->poll) bus->pollrate = 1; - return true; + return 0; fail: sdio_release_host(sdiodev->func1); - return false; + return ret; } static int @@ -4451,8 +4453,10 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) /* Allocate private bus interface state */ bus = kzalloc(sizeof(*bus), GFP_ATOMIC); - if (!bus) + if (!bus) { + ret = -ENOMEM; goto fail; + } bus->sdiodev = sdiodev; sdiodev->bus = bus; @@ -4467,6 +4471,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) dev_name(&sdiodev->func1->dev)); if (!wq) { brcmf_err("insufficient memory to create txworkqueue\n"); + ret = -ENOMEM; goto fail; } brcmf_sdiod_freezer_count(sdiodev); @@ -4474,7 +4479,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->brcmf_wq = wq; /* attempt to attach to the dongle */ - if (!(brcmf_sdio_probe_attach(bus))) { + ret = brcmf_sdio_probe_attach(bus); + if (ret < 0) { brcmf_err("brcmf_sdio_probe_attach failed\n"); goto fail; } @@ -4546,7 +4552,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) fail: brcmf_sdio_remove(bus); - return NULL; + return ERR_PTR(ret); } /* Detach and free everything */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 8afbf529c745..2821c27f317e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1272,6 +1272,9 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, ret = -ENOMEM; goto fail; } + ret = PTR_ERR_OR_ZERO(devinfo->settings); + if (ret < 0) + goto fail; if (!brcmf_usb_dlneeded(devinfo)) { ret = brcmf_alloc(devinfo->dev, devinfo->settings); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c index 6d776ef6ff54..81df41c7fbb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c @@ -56,11 +56,6 @@ void brcms_debugfs_detach(struct brcms_pub *drvr) debugfs_remove_recursive(drvr->dbgfs_dir); } -struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr) -{ - return drvr->dbgfs_dir; -} - static int brcms_debugfs_hardware_read(struct seq_file *s, void *data) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h index 56898e6d789d..d30a9fa30f1b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h @@ -70,7 +70,6 @@ void brcms_debugfs_init(void); void brcms_debugfs_exit(void); void brcms_debugfs_attach(struct brcms_pub *drvr); void brcms_debugfs_detach(struct brcms_pub *drvr); -struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr); void brcms_debugfs_create_files(struct brcms_pub *drvr); #endif /* _BRCMS_DEBUG_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c index bd480239368a..80c35027787a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c @@ -1426,15 +1426,6 @@ int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, return -ENOSPC; } -void dma_txflush(struct dma_pub *pub) -{ - struct dma_info *di = container_of(pub, struct dma_info, dma); - struct brcms_ampdu_session *session = &di->ampdu_session; - - if (!skb_queue_empty(&session->skb_list)) - ampdu_finalize(di); -} - int dma_txpending(struct dma_pub *pub) { struct dma_info *di = container_of(pub, struct dma_info, dma); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h index ff5b80b09046..7905fd081721 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h @@ -88,7 +88,6 @@ bool dma_txreset(struct dma_pub *pub); void dma_txinit(struct dma_pub *pub); int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, struct sk_buff *p0); -void dma_txflush(struct dma_pub *pub); int dma_txpending(struct dma_pub *pub); void dma_kick_tx(struct dma_pub *pub); void dma_txsuspend(struct dma_pub *pub); diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 44684bf1b9ac..c1e22c589d85 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -52,6 +52,7 @@ #define BRCM_CC_43664_CHIP_ID 43664 #define BRCM_CC_43666_CHIP_ID 43666 #define BRCM_CC_4371_CHIP_ID 0x4371 +#define BRCM_CC_43752_CHIP_ID 43752 #define BRCM_CC_4377_CHIP_ID 0x4377 #define BRCM_CC_4378_CHIP_ID 0x4378 #define BRCM_CC_4387_CHIP_ID 0x4387 @@ -94,6 +95,7 @@ #define BRCM_PCIE_4366_5G_DEVICE_ID 0x43c5 #define BRCM_PCIE_4371_DEVICE_ID 0x440d #define BRCM_PCIE_43596_DEVICE_ID 0x4415 +#define BRCM_PCIE_43752_DEVICE_ID 0x449d #define BRCM_PCIE_4377_DEVICE_ID 0x4488 #define BRCM_PCIE_4378_DEVICE_ID 0x4425 #define BRCM_PCIE_4387_DEVICE_ID 0x4433 diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig index 1650d5865aa0..b92df91adb3a 100644 --- a/drivers/net/wireless/intel/ipw2x00/Kconfig +++ b/drivers/net/wireless/intel/ipw2x00/Kconfig @@ -7,10 +7,8 @@ config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" depends on PCI && CFG80211 select WIRELESS_EXT - select WEXT_SPY select WEXT_PRIV select FW_LOADER - select LIB80211 select LIBIPW help A driver for the Intel PRO/Wireless 2100 Network @@ -67,12 +65,9 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" depends on PCI && CFG80211 - select CFG80211_WEXT_EXPORT select WIRELESS_EXT - select WEXT_SPY select WEXT_PRIV select FW_LOADER - select LIB80211 select LIBIPW help A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network @@ -158,14 +153,10 @@ config LIBIPW tristate depends on PCI && CFG80211 select WIRELESS_EXT - select WEXT_SPY select CRYPTO select CRYPTO_MICHAEL_MIC + select CRYPTO_LIB_ARC4 select CRC32 - select LIB80211 - select LIB80211_CRYPT_WEP - select LIB80211_CRYPT_TKIP - select LIB80211_CRYPT_CCMP help This option enables the hardware independent IEEE 802.11 networking stack. This component is deprecated in favor of the diff --git a/drivers/net/wireless/intel/ipw2x00/Makefile b/drivers/net/wireless/intel/ipw2x00/Makefile index e1ec50359dff..91e6091c4ebf 100644 --- a/drivers/net/wireless/intel/ipw2x00/Makefile +++ b/drivers/net/wireless/intel/ipw2x00/Makefile @@ -12,4 +12,9 @@ libipw-objs := \ libipw_tx.o \ libipw_rx.o \ libipw_wx.o \ - libipw_geo.o + libipw_geo.o \ + libipw_spy.o \ + libipw_crypto.o \ + libipw_crypto_ccmp.o \ + libipw_crypto_tkip.o \ + libipw_crypto_wep.o diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index fe75941c584d..215814861cbd 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -148,9 +148,6 @@ that only one external action is invoked at a time. #include <linux/acpi.h> #include <linux/ctype.h> #include <linux/pm_qos.h> - -#include <net/lib80211.h> - #include "ipw2100.h" #include "ipw.h" @@ -6025,8 +6022,6 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, dev->netdev_ops = &ipw2100_netdev_ops; dev->ethtool_ops = &ipw2100_ethtool_ops; dev->wireless_handlers = &ipw2100_wx_handler_def; - priv->wireless_data.libipw = priv->ieee; - dev->wireless_data = &priv->wireless_data; dev->watchdog_timeo = 3 * HZ; dev->irq = 0; dev->min_mtu = 68; @@ -7571,7 +7566,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, struct ipw2100_priv *priv = libipw_priv(dev); struct libipw_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -7663,7 +7658,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, { struct ipw2100_priv *priv = libipw_priv(dev); struct libipw_device *ieee = priv->ieee; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; struct iw_param *param = &wrqu->param; switch (param->flags & IW_AUTH_INDEX) { diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h index b34085ade3aa..6f81f509b9cb 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.h @@ -554,8 +554,6 @@ struct ipw2100_priv { struct net_device *net_dev; struct iw_statistics wstats; - struct iw_public_data wireless_data; - struct tasklet_struct irq_tasklet; struct delayed_work reset_work; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index eed9ef17bc29..be1d971b3d32 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -6463,6 +6463,14 @@ static int ipw_set_rsn_capa(struct ipw_priv *priv, * WE-18 support */ +static int ipw_wx_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + strcpy(wrqu->name, "IEEE 802.11"); + return 0; +} + /* SIOCSIWGENIE */ static int ipw_wx_set_genie(struct net_device *dev, struct iw_request_info *info, @@ -6549,7 +6557,7 @@ static int ipw_wx_set_auth(struct net_device *dev, struct ipw_priv *priv = libipw_priv(dev); struct libipw_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -6648,7 +6656,7 @@ static int ipw_wx_get_auth(struct net_device *dev, { struct ipw_priv *priv = libipw_priv(dev); struct libipw_device *ieee = priv->ieee; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; struct iw_param *param = &wrqu->param; switch (param->flags & IW_AUTH_INDEX) { @@ -9826,7 +9834,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, /* Rebase the WE IOCTLs to zero for the handler array */ static iw_handler ipw_wx_handlers[] = { - IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), + IW_HANDLER(SIOCGIWNAME, ipw_wx_get_name), IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq), IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq), IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode), @@ -9856,10 +9864,10 @@ static iw_handler ipw_wx_handlers[] = { IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode), IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power), IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), + IW_HANDLER(SIOCSIWSPY, ipw_wx_set_spy), + IW_HANDLER(SIOCGIWSPY, ipw_wx_get_spy), + IW_HANDLER(SIOCSIWTHRSPY, ipw_wx_set_thrspy), + IW_HANDLER(SIOCGIWTHRSPY, ipw_wx_get_thrspy), IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie), IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie), IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme), @@ -11636,8 +11644,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, priv->ieee->worst_rssi = -85; net_dev->netdev_ops = &ipw_netdev_ops; - priv->wireless_data.spy_data = &priv->ieee->spy_data; - net_dev->wireless_data = &priv->wireless_data; + priv->ieee->spy_enabled = true; net_dev->wireless_handlers = &ipw_wx_handler_def; net_dev->ethtool_ops = &ipw_ethtool_ops; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h index 226286cb7eb8..19310fd0d8eb 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.h @@ -31,8 +31,6 @@ #include <linux/wireless.h> #include <linux/jiffies.h> #include <asm/io.h> - -#include <net/lib80211.h> #include <net/ieee80211_radiotap.h> #define DRV_NAME "ipw2200" @@ -1276,8 +1274,6 @@ struct ipw_priv { struct iw_statistics wstats; - struct iw_public_data wireless_data; - int user_requested_scan; u8 direct_scan_ssid[IW_ESSID_MAX_SIZE]; u8 direct_scan_ssid_len; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h index bad080d33c07..3c20353e5a41 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw.h +++ b/drivers/net/wireless/intel/ipw2x00/libipw.h @@ -25,8 +25,6 @@ #include <linux/kernel.h> /* ARRAY_SIZE */ #include <linux/wireless.h> #include <linux/ieee80211.h> - -#include <net/lib80211.h> #include <net/cfg80211.h> #define LIBIPW_VERSION "git-1.1.13" @@ -699,6 +697,76 @@ struct libipw_geo { struct libipw_channel a[LIBIPW_52GHZ_CHANNELS]; }; +#define NUM_WEP_KEYS 4 + +enum { + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0), +}; + +struct module; + +struct libipw_crypto_ops { + const char *name; + struct list_head list; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void *(*init) (int keyidx); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit) (void *priv); + + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return + * value from decrypt_mpdu is passed as the keyidx value for + * decrypt_msdu. skb must have enough head and tail room for the + * encryption; if not, error will be returned; these functions are + * called for all MPDUs (i.e., fragments). + */ + int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + + /* These functions are called for full MSDUs, i.e. full frames. + * These can be NULL if full MSDU operations are not needed. */ + int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len, + void *priv); + + int (*set_key) (void *key, int len, u8 * seq, void *priv); + int (*get_key) (void *key, int len, u8 * seq, void *priv); + + /* procfs handler for printing out key information and possible + * statistics */ + void (*print_stats) (struct seq_file *m, void *priv); + + /* Crypto specific flag get/set for configuration settings */ + unsigned long (*get_flags) (void *priv); + unsigned long (*set_flags) (unsigned long flags, void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_mpdu_prefix_len, extra_mpdu_postfix_len; + int extra_msdu_prefix_len, extra_msdu_postfix_len; + + struct module *owner; +}; + +struct libipw_crypt_info { + char *name; + /* Most clients will already have a lock, + so just point to that. */ + spinlock_t *lock; + + struct libipw_crypt_data *crypt[NUM_WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct list_head crypt_deinit_list; + struct timer_list crypt_deinit_timer; + int crypt_quiesced; +}; + struct libipw_device { struct net_device *dev; struct wireless_dev wdev; @@ -720,6 +788,7 @@ struct libipw_device { int iw_mode; /* operating mode (IW_MODE_*) */ struct iw_spy_data spy_data; /* iwspy support */ + bool spy_enabled; spinlock_t lock; @@ -751,7 +820,7 @@ struct libipw_device { size_t wpa_ie_len; u8 *wpa_ie; - struct lib80211_crypt_info crypt_info; + struct libipw_crypt_info crypt_info; int bcrx_sta_key; /* use individual keys to override default keys even * with RX of broad/multicast frames */ @@ -988,4 +1057,43 @@ static inline int libipw_get_scans(struct libipw_device *ieee) return ieee->scans; } +struct libipw_crypt_data { + struct list_head list; /* delayed deletion list */ + const struct libipw_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +int libipw_crypt_info_init(struct libipw_crypt_info *info, char *name, + spinlock_t *lock); +void libipw_crypt_info_free(struct libipw_crypt_info *info); +int libipw_register_crypto_ops(const struct libipw_crypto_ops *ops); +int libipw_unregister_crypto_ops(const struct libipw_crypto_ops *ops); +const struct libipw_crypto_ops *libipw_get_crypto_ops(const char *name); +void libipw_crypt_delayed_deinit(struct libipw_crypt_info *info, + struct libipw_crypt_data **crypt); + +/* must be called in the listed order */ +int libipw_crypto_init(void); +int libipw_crypto_ccmp_init(void); +int libipw_crypto_tkip_init(void); +int libipw_crypto_wep_init(void); + +void libipw_crypto_wep_exit(void); +void libipw_crypto_tkip_exit(void); +void libipw_crypto_ccmp_exit(void); +void libipw_crypto_exit(void); + + +int ipw_wx_set_spy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +int ipw_wx_get_spy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +int ipw_wx_set_thrspy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +int ipw_wx_get_thrspy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +void libipw_spy_update(struct net_device *dev, unsigned char *address, + struct iw_quality *wstats); + #endif /* LIBIPW_H */ diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c new file mode 100644 index 000000000000..32639e0e8430 --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * libipw -- common bits for IPW drivers + * + * Copyright(c) 2008 John W. Linville <linville@tuxdriver.com> + * + * Portions copied from old ieee80211 component, w/ original copyright + * notices below: + * + * Host AP crypto routines + * + * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> + * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com> + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/ctype.h> +#include <linux/ieee80211.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/string.h> +#include "libipw.h" + +struct libipw_crypto_alg { + struct list_head list; + const struct libipw_crypto_ops *ops; +}; + +static LIST_HEAD(libipw_crypto_algs); +static DEFINE_SPINLOCK(libipw_crypto_lock); + +static void libipw_crypt_deinit_entries(struct libipw_crypt_info *info, + int force); +static void libipw_crypt_quiescing(struct libipw_crypt_info *info); +static void libipw_crypt_deinit_handler(struct timer_list *t); + +int libipw_crypt_info_init(struct libipw_crypt_info *info, char *name, + spinlock_t *lock) +{ + memset(info, 0, sizeof(*info)); + + info->name = name; + info->lock = lock; + + INIT_LIST_HEAD(&info->crypt_deinit_list); + timer_setup(&info->crypt_deinit_timer, libipw_crypt_deinit_handler, + 0); + + return 0; +} +EXPORT_SYMBOL(libipw_crypt_info_init); + +void libipw_crypt_info_free(struct libipw_crypt_info *info) +{ + int i; + + libipw_crypt_quiescing(info); + del_timer_sync(&info->crypt_deinit_timer); + libipw_crypt_deinit_entries(info, 1); + + for (i = 0; i < NUM_WEP_KEYS; i++) { + struct libipw_crypt_data *crypt = info->crypt[i]; + if (crypt) { + if (crypt->ops) { + crypt->ops->deinit(crypt->priv); + module_put(crypt->ops->owner); + } + kfree(crypt); + info->crypt[i] = NULL; + } + } +} +EXPORT_SYMBOL(libipw_crypt_info_free); + +static void libipw_crypt_deinit_entries(struct libipw_crypt_info *info, + int force) +{ + struct libipw_crypt_data *entry, *next; + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) { + if (atomic_read(&entry->refcnt) != 0 && !force) + continue; + + list_del(&entry->list); + + if (entry->ops) { + entry->ops->deinit(entry->priv); + module_put(entry->ops->owner); + } + kfree(entry); + } + spin_unlock_irqrestore(info->lock, flags); +} + +/* After this, crypt_deinit_list won't accept new members */ +static void libipw_crypt_quiescing(struct libipw_crypt_info *info) +{ + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + info->crypt_quiesced = 1; + spin_unlock_irqrestore(info->lock, flags); +} + +static void libipw_crypt_deinit_handler(struct timer_list *t) +{ + struct libipw_crypt_info *info = from_timer(info, t, + crypt_deinit_timer); + unsigned long flags; + + libipw_crypt_deinit_entries(info, 0); + + spin_lock_irqsave(info->lock, flags); + if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) { + printk(KERN_DEBUG "%s: entries remaining in delayed crypt " + "deletion list\n", info->name); + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + spin_unlock_irqrestore(info->lock, flags); +} + +void libipw_crypt_delayed_deinit(struct libipw_crypt_info *info, + struct libipw_crypt_data **crypt) +{ + struct libipw_crypt_data *tmp; + unsigned long flags; + + if (*crypt == NULL) + return; + + tmp = *crypt; + *crypt = NULL; + + /* must not run ops->deinit() while there may be pending encrypt or + * decrypt operations. Use a list of delayed deinits to avoid needing + * locking. */ + + spin_lock_irqsave(info->lock, flags); + if (!info->crypt_quiesced) { + list_add(&tmp->list, &info->crypt_deinit_list); + if (!timer_pending(&info->crypt_deinit_timer)) { + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + } + spin_unlock_irqrestore(info->lock, flags); +} +EXPORT_SYMBOL(libipw_crypt_delayed_deinit); + +int libipw_register_crypto_ops(const struct libipw_crypto_ops *ops) +{ + unsigned long flags; + struct libipw_crypto_alg *alg; + + alg = kzalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) + return -ENOMEM; + + alg->ops = ops; + + spin_lock_irqsave(&libipw_crypto_lock, flags); + list_add(&alg->list, &libipw_crypto_algs); + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + + printk(KERN_DEBUG "libipw_crypt: registered algorithm '%s'\n", + ops->name); + + return 0; +} +EXPORT_SYMBOL(libipw_register_crypto_ops); + +int libipw_unregister_crypto_ops(const struct libipw_crypto_ops *ops) +{ + struct libipw_crypto_alg *alg; + unsigned long flags; + + spin_lock_irqsave(&libipw_crypto_lock, flags); + list_for_each_entry(alg, &libipw_crypto_algs, list) { + if (alg->ops == ops) + goto found; + } + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + return -EINVAL; + + found: + printk(KERN_DEBUG "libipw_crypt: unregistered algorithm '%s'\n", + ops->name); + list_del(&alg->list); + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + kfree(alg); + return 0; +} +EXPORT_SYMBOL(libipw_unregister_crypto_ops); + +const struct libipw_crypto_ops *libipw_get_crypto_ops(const char *name) +{ + struct libipw_crypto_alg *alg; + unsigned long flags; + + spin_lock_irqsave(&libipw_crypto_lock, flags); + list_for_each_entry(alg, &libipw_crypto_algs, list) { + if (strcmp(alg->ops->name, name) == 0) + goto found; + } + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + return NULL; + + found: + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + return alg->ops; +} +EXPORT_SYMBOL(libipw_get_crypto_ops); + +static void *libipw_crypt_null_init(int keyidx) +{ + return (void *)1; +} + +static void libipw_crypt_null_deinit(void *priv) +{ +} + +static const struct libipw_crypto_ops libipw_crypt_null = { + .name = "NULL", + .init = libipw_crypt_null_init, + .deinit = libipw_crypt_null_deinit, + .owner = THIS_MODULE, +}; + +int __init libipw_crypto_init(void) +{ + return libipw_register_crypto_ops(&libipw_crypt_null); +} + +void libipw_crypto_exit(void) +{ + libipw_unregister_crypto_ops(&libipw_crypt_null); + BUG_ON(!list_empty(&libipw_crypto_algs)); +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c new file mode 100644 index 000000000000..bf900d8c8ad3 --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * libipw crypt: host-based CCMP encryption implementation for libipw + * + * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com> + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> +#include <asm/string.h> +#include <linux/wireless.h> +#include <linux/ieee80211.h> +#include <linux/crypto.h> +#include <crypto/aead.h> +#include "libipw.h" + +#define AES_BLOCK_LEN 16 +#define CCMP_HDR_LEN 8 +#define CCMP_MIC_LEN 8 +#define CCMP_TK_LEN 16 +#define CCMP_PN_LEN 6 + +struct libipw_ccmp_data { + u8 key[CCMP_TK_LEN]; + int key_set; + + u8 tx_pn[CCMP_PN_LEN]; + u8 rx_pn[CCMP_PN_LEN]; + + u32 dot11RSNAStatsCCMPFormatErrors; + u32 dot11RSNAStatsCCMPReplays; + u32 dot11RSNAStatsCCMPDecryptErrors; + + int key_idx; + + struct crypto_aead *tfm; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 tx_aad[2 * AES_BLOCK_LEN]; + u8 rx_aad[2 * AES_BLOCK_LEN]; +}; + +static void *libipw_ccmp_init(int key_idx) +{ + struct libipw_ccmp_data *priv; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + priv->key_idx = key_idx; + + priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tfm)) { + priv->tfm = NULL; + goto fail; + } + + return priv; + + fail: + if (priv) { + if (priv->tfm) + crypto_free_aead(priv->tfm); + kfree(priv); + } + + return NULL; +} + +static void libipw_ccmp_deinit(void *priv) +{ + struct libipw_ccmp_data *_priv = priv; + if (_priv && _priv->tfm) + crypto_free_aead(_priv->tfm); + kfree(priv); +} + +static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr, + const u8 *pn, u8 *iv, u8 *aad) +{ + u8 *pos, qc = 0; + size_t aad_len; + int a4_included, qc_included; + + a4_included = ieee80211_has_a4(hdr->frame_control); + qc_included = ieee80211_is_data_qos(hdr->frame_control); + + aad_len = 22; + if (a4_included) + aad_len += 6; + if (qc_included) { + pos = (u8 *) & hdr->addr4; + if (a4_included) + pos += 6; + qc = *pos & 0x0f; + aad_len += 2; + } + + /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC + * mode authentication are not allowed to collide, yet both are derived + * from the same vector. We only set L := 1 here to indicate that the + * data size can be represented in (L+1) bytes. The CCM layer will take + * care of storing the data length in the top (L+1) bytes and setting + * and clearing the other bits as is required to derive the two IVs. + */ + iv[0] = 0x1; + + /* Nonce: QC | A2 | PN */ + iv[1] = qc; + memcpy(iv + 2, hdr->addr2, ETH_ALEN); + memcpy(iv + 8, pn, CCMP_PN_LEN); + + /* AAD: + * FC with bits 4..6 and 11..13 masked to zero; 14 is always one + * A1 | A2 | A3 + * SC with bits 4..15 (seq#) masked to zero + * A4 (if present) + * QC (if present) + */ + pos = (u8 *) hdr; + aad[0] = pos[0] & 0x8f; + aad[1] = pos[1] & 0xc7; + memcpy(aad + 2, &hdr->addrs, 3 * ETH_ALEN); + pos = (u8 *) & hdr->seq_ctrl; + aad[20] = pos[0] & 0x0f; + aad[21] = 0; /* all bits masked */ + memset(aad + 22, 0, 8); + if (a4_included) + memcpy(aad + 22, hdr->addr4, ETH_ALEN); + if (qc_included) { + aad[a4_included ? 28 : 22] = qc; + /* rest of QC masked */ + } + return aad_len; +} + +static int libipw_ccmp_hdr(struct sk_buff *skb, int hdr_len, + u8 *aeskey, int keylen, void *priv) +{ + struct libipw_ccmp_data *key = priv; + int i; + u8 *pos; + + if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len) + return -1; + + if (aeskey != NULL && keylen >= CCMP_TK_LEN) + memcpy(aeskey, key->key, CCMP_TK_LEN); + + pos = skb_push(skb, CCMP_HDR_LEN); + memmove(pos, pos + CCMP_HDR_LEN, hdr_len); + pos += hdr_len; + + i = CCMP_PN_LEN - 1; + while (i >= 0) { + key->tx_pn[i]++; + if (key->tx_pn[i] != 0) + break; + i--; + } + + *pos++ = key->tx_pn[5]; + *pos++ = key->tx_pn[4]; + *pos++ = 0; + *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ; + *pos++ = key->tx_pn[3]; + *pos++ = key->tx_pn[2]; + *pos++ = key->tx_pn[1]; + *pos++ = key->tx_pn[0]; + + return CCMP_HDR_LEN; +} + +static int libipw_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_ccmp_data *key = priv; + struct ieee80211_hdr *hdr; + struct aead_request *req; + struct scatterlist sg[2]; + u8 *aad = key->tx_aad; + u8 iv[AES_BLOCK_LEN]; + int len, data_len, aad_len; + int ret; + + if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len) + return -1; + + data_len = skb->len - hdr_len; + len = libipw_ccmp_hdr(skb, hdr_len, NULL, 0, priv); + if (len < 0) + return -1; + + req = aead_request_alloc(key->tfm, GFP_ATOMIC); + if (!req) + return -ENOMEM; + + hdr = (struct ieee80211_hdr *)skb->data; + aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad); + + skb_put(skb, CCMP_MIC_LEN); + + sg_init_table(sg, 2); + sg_set_buf(&sg[0], aad, aad_len); + sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN, + data_len + CCMP_MIC_LEN); + + aead_request_set_callback(req, 0, NULL, NULL); + aead_request_set_ad(req, aad_len); + aead_request_set_crypt(req, sg, sg, data_len, iv); + + ret = crypto_aead_encrypt(req); + aead_request_free(req); + + return ret; +} + +/* + * deal with seq counter wrapping correctly. + * refer to timer_after() for jiffies wrapping handling + */ +static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o) +{ + u32 iv32_n, iv16_n; + u32 iv32_o, iv16_o; + + iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3]; + iv16_n = (pn_n[4] << 8) | pn_n[5]; + + iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3]; + iv16_o = (pn_o[4] << 8) | pn_o[5]; + + if ((s32)iv32_n - (s32)iv32_o < 0 || + (iv32_n == iv32_o && iv16_n <= iv16_o)) + return 1; + return 0; +} + +static int libipw_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_ccmp_data *key = priv; + u8 keyidx, *pos; + struct ieee80211_hdr *hdr; + struct aead_request *req; + struct scatterlist sg[2]; + u8 *aad = key->rx_aad; + u8 iv[AES_BLOCK_LEN]; + u8 pn[6]; + int aad_len, ret; + size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN; + + if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { + key->dot11RSNAStatsCCMPFormatErrors++; + return -1; + } + + hdr = (struct ieee80211_hdr *)skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + net_dbg_ratelimited("CCMP: received packet without ExtIV flag from %pM\n", + hdr->addr2); + key->dot11RSNAStatsCCMPFormatErrors++; + return -2; + } + keyidx >>= 6; + if (key->key_idx != keyidx) { + net_dbg_ratelimited("CCMP: RX tkey->key_idx=%d frame keyidx=%d\n", + key->key_idx, keyidx); + return -6; + } + if (!key->key_set) { + net_dbg_ratelimited("CCMP: received packet from %pM with keyid=%d that does not have a configured key\n", + hdr->addr2, keyidx); + return -3; + } + + pn[0] = pos[7]; + pn[1] = pos[6]; + pn[2] = pos[5]; + pn[3] = pos[4]; + pn[4] = pos[1]; + pn[5] = pos[0]; + pos += 8; + + if (ccmp_replay_check(pn, key->rx_pn)) { +#ifdef CONFIG_LIBIPW_DEBUG + net_dbg_ratelimited("CCMP: replay detected: STA=%pM previous PN %02x%02x%02x%02x%02x%02x received PN %02x%02x%02x%02x%02x%02x\n", + hdr->addr2, + key->rx_pn[0], key->rx_pn[1], key->rx_pn[2], + key->rx_pn[3], key->rx_pn[4], key->rx_pn[5], + pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); +#endif + key->dot11RSNAStatsCCMPReplays++; + return -4; + } + + req = aead_request_alloc(key->tfm, GFP_ATOMIC); + if (!req) + return -ENOMEM; + + aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad); + + sg_init_table(sg, 2); + sg_set_buf(&sg[0], aad, aad_len); + sg_set_buf(&sg[1], pos, data_len); + + aead_request_set_callback(req, 0, NULL, NULL); + aead_request_set_ad(req, aad_len); + aead_request_set_crypt(req, sg, sg, data_len, iv); + + ret = crypto_aead_decrypt(req); + aead_request_free(req); + + if (ret) { + net_dbg_ratelimited("CCMP: decrypt failed: STA=%pM (%d)\n", + hdr->addr2, ret); + key->dot11RSNAStatsCCMPDecryptErrors++; + return -5; + } + + memcpy(key->rx_pn, pn, CCMP_PN_LEN); + + /* Remove hdr and MIC */ + memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, CCMP_HDR_LEN); + skb_trim(skb, skb->len - CCMP_MIC_LEN); + + return keyidx; +} + +static int libipw_ccmp_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_ccmp_data *data = priv; + int keyidx; + struct crypto_aead *tfm = data->tfm; + + keyidx = data->key_idx; + memset(data, 0, sizeof(*data)); + data->key_idx = keyidx; + data->tfm = tfm; + if (len == CCMP_TK_LEN) { + memcpy(data->key, key, CCMP_TK_LEN); + data->key_set = 1; + if (seq) { + data->rx_pn[0] = seq[5]; + data->rx_pn[1] = seq[4]; + data->rx_pn[2] = seq[3]; + data->rx_pn[3] = seq[2]; + data->rx_pn[4] = seq[1]; + data->rx_pn[5] = seq[0]; + } + if (crypto_aead_setauthsize(data->tfm, CCMP_MIC_LEN) || + crypto_aead_setkey(data->tfm, data->key, CCMP_TK_LEN)) + return -1; + } else if (len == 0) + data->key_set = 0; + else + return -1; + + return 0; +} + +static int libipw_ccmp_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_ccmp_data *data = priv; + + if (len < CCMP_TK_LEN) + return -1; + + if (!data->key_set) + return 0; + memcpy(key, data->key, CCMP_TK_LEN); + + if (seq) { + seq[0] = data->tx_pn[5]; + seq[1] = data->tx_pn[4]; + seq[2] = data->tx_pn[3]; + seq[3] = data->tx_pn[2]; + seq[4] = data->tx_pn[1]; + seq[5] = data->tx_pn[0]; + } + + return CCMP_TK_LEN; +} + +static void libipw_ccmp_print_stats(struct seq_file *m, void *priv) +{ + struct libipw_ccmp_data *ccmp = priv; + + seq_printf(m, + "key[%d] alg=CCMP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "format_errors=%d replays=%d decrypt_errors=%d\n", + ccmp->key_idx, ccmp->key_set, + ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2], + ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5], + ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2], + ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5], + ccmp->dot11RSNAStatsCCMPFormatErrors, + ccmp->dot11RSNAStatsCCMPReplays, + ccmp->dot11RSNAStatsCCMPDecryptErrors); +} + +static const struct libipw_crypto_ops libipw_crypt_ccmp = { + .name = "CCMP", + .init = libipw_ccmp_init, + .deinit = libipw_ccmp_deinit, + .encrypt_mpdu = libipw_ccmp_encrypt, + .decrypt_mpdu = libipw_ccmp_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = libipw_ccmp_set_key, + .get_key = libipw_ccmp_get_key, + .print_stats = libipw_ccmp_print_stats, + .extra_mpdu_prefix_len = CCMP_HDR_LEN, + .extra_mpdu_postfix_len = CCMP_MIC_LEN, + .owner = THIS_MODULE, +}; + +int __init libipw_crypto_ccmp_init(void) +{ + return libipw_register_crypto_ops(&libipw_crypt_ccmp); +} + +void libipw_crypto_ccmp_exit(void) +{ + libipw_unregister_crypto_ops(&libipw_crypt_ccmp); +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c new file mode 100644 index 000000000000..32288697da4f --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c @@ -0,0 +1,728 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * libipw crypt: host-based TKIP encryption implementation for libipw + * + * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/err.h> +#include <linux/fips.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/scatterlist.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/mm.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> +#include <asm/string.h> +#include <linux/wireless.h> +#include <linux/ieee80211.h> +#include <net/iw_handler.h> +#include <crypto/arc4.h> +#include <crypto/hash.h> +#include <linux/crypto.h> +#include <linux/crc32.h> +#include "libipw.h" + +#define TKIP_HDR_LEN 8 + +struct libipw_tkip_data { +#define TKIP_KEY_LEN 32 + u8 key[TKIP_KEY_LEN]; + int key_set; + + u32 tx_iv32; + u16 tx_iv16; + u16 tx_ttak[5]; + int tx_phase1_done; + + u32 rx_iv32; + u16 rx_iv16; + u16 rx_ttak[5]; + int rx_phase1_done; + u32 rx_iv32_new; + u16 rx_iv16_new; + + u32 dot11RSNAStatsTKIPReplays; + u32 dot11RSNAStatsTKIPICVErrors; + u32 dot11RSNAStatsTKIPLocalMICFailures; + + int key_idx; + + struct arc4_ctx rx_ctx_arc4; + struct arc4_ctx tx_ctx_arc4; + struct crypto_shash *rx_tfm_michael; + struct crypto_shash *tx_tfm_michael; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 rx_hdr[16], tx_hdr[16]; + + unsigned long flags; +}; + +static unsigned long libipw_tkip_set_flags(unsigned long flags, void *priv) +{ + struct libipw_tkip_data *_priv = priv; + unsigned long old_flags = _priv->flags; + _priv->flags = flags; + return old_flags; +} + +static unsigned long libipw_tkip_get_flags(void *priv) +{ + struct libipw_tkip_data *_priv = priv; + return _priv->flags; +} + +static void *libipw_tkip_init(int key_idx) +{ + struct libipw_tkip_data *priv; + + if (fips_enabled) + return NULL; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + + priv->key_idx = key_idx; + + priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0); + if (IS_ERR(priv->tx_tfm_michael)) { + priv->tx_tfm_michael = NULL; + goto fail; + } + + priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0); + if (IS_ERR(priv->rx_tfm_michael)) { + priv->rx_tfm_michael = NULL; + goto fail; + } + + return priv; + + fail: + if (priv) { + crypto_free_shash(priv->tx_tfm_michael); + crypto_free_shash(priv->rx_tfm_michael); + kfree(priv); + } + + return NULL; +} + +static void libipw_tkip_deinit(void *priv) +{ + struct libipw_tkip_data *_priv = priv; + if (_priv) { + crypto_free_shash(_priv->tx_tfm_michael); + crypto_free_shash(_priv->rx_tfm_michael); + } + kfree_sensitive(priv); +} + +static inline u16 RotR1(u16 val) +{ + return (val >> 1) | (val << 15); +} + +static inline u8 Lo8(u16 val) +{ + return val & 0xff; +} + +static inline u8 Hi8(u16 val) +{ + return val >> 8; +} + +static inline u16 Lo16(u32 val) +{ + return val & 0xffff; +} + +static inline u16 Hi16(u32 val) +{ + return val >> 16; +} + +static inline u16 Mk16(u8 hi, u8 lo) +{ + return lo | (((u16) hi) << 8); +} + +static inline u16 Mk16_le(__le16 * v) +{ + return le16_to_cpu(*v); +} + +static const u16 Sbox[256] = { + 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, + 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, + 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, + 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, + 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, + 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, + 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, + 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, + 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, + 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, + 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, + 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, + 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, + 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, + 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, + 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, + 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, + 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, + 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, + 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, + 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, + 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, + 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, + 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, + 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, + 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, + 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, + 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, + 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, + 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, + 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, + 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, +}; + +static inline u16 _S_(u16 v) +{ + u16 t = Sbox[Hi8(v)]; + return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); +} + +#define PHASE1_LOOP_COUNT 8 + +static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA, + u32 IV32) +{ + int i, j; + + /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ + TTAK[0] = Lo16(IV32); + TTAK[1] = Hi16(IV32); + TTAK[2] = Mk16(TA[1], TA[0]); + TTAK[3] = Mk16(TA[3], TA[2]); + TTAK[4] = Mk16(TA[5], TA[4]); + + for (i = 0; i < PHASE1_LOOP_COUNT; i++) { + j = 2 * (i & 1); + TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); + TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); + TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); + TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); + TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; + } +} + +static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK, + u16 IV16) +{ + /* Make temporary area overlap WEP seed so that the final copy can be + * avoided on little endian hosts. */ + u16 *PPK = (u16 *) & WEPSeed[4]; + + /* Step 1 - make copy of TTAK and bring in TSC */ + PPK[0] = TTAK[0]; + PPK[1] = TTAK[1]; + PPK[2] = TTAK[2]; + PPK[3] = TTAK[3]; + PPK[4] = TTAK[4]; + PPK[5] = TTAK[4] + IV16; + + /* Step 2 - 96-bit bijective mixing using S-box */ + PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0])); + PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2])); + PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4])); + PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6])); + PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8])); + PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10])); + + PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12])); + PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14])); + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + + /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value + * WEPSeed[0..2] is transmitted as WEP IV */ + WEPSeed[0] = Hi8(IV16); + WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; + WEPSeed[2] = Lo8(IV16); + WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1); + +#ifdef __BIG_ENDIAN + { + int i; + for (i = 0; i < 6; i++) + PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); + } +#endif +} + +static int libipw_tkip_hdr(struct sk_buff *skb, int hdr_len, + u8 * rc4key, int keylen, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + u8 *pos; + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)skb->data; + + if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len) + return -1; + + if (rc4key == NULL || keylen < 16) + return -1; + + if (!tkey->tx_phase1_done) { + tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, + tkey->tx_iv32); + tkey->tx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); + + pos = skb_push(skb, TKIP_HDR_LEN); + memmove(pos, pos + TKIP_HDR_LEN, hdr_len); + pos += hdr_len; + + *pos++ = *rc4key; + *pos++ = *(rc4key + 1); + *pos++ = *(rc4key + 2); + *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ; + *pos++ = tkey->tx_iv32 & 0xff; + *pos++ = (tkey->tx_iv32 >> 8) & 0xff; + *pos++ = (tkey->tx_iv32 >> 16) & 0xff; + *pos++ = (tkey->tx_iv32 >> 24) & 0xff; + + tkey->tx_iv16++; + if (tkey->tx_iv16 == 0) { + tkey->tx_phase1_done = 0; + tkey->tx_iv32++; + } + + return TKIP_HDR_LEN; +} + +static int libipw_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + int len; + u8 rc4key[16], *pos, *icv; + u32 crc; + + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + net_dbg_ratelimited("TKIP countermeasures: dropped TX packet to %pM\n", + hdr->addr1); + return -1; + } + + if (skb_tailroom(skb) < 4 || skb->len < hdr_len) + return -1; + + len = skb->len - hdr_len; + pos = skb->data + hdr_len; + + if ((libipw_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) + return -1; + + crc = ~crc32_le(~0, pos, len); + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16); + arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4); + + return 0; +} + +/* + * deal with seq counter wrapping correctly. + * refer to timer_after() for jiffies wrapping handling + */ +static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n, + u32 iv32_o, u16 iv16_o) +{ + if ((s32)iv32_n - (s32)iv32_o < 0 || + (iv32_n == iv32_o && iv16_n <= iv16_o)) + return 1; + return 0; +} + +static int libipw_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + u8 rc4key[16]; + u8 keyidx, *pos; + u32 iv32; + u16 iv16; + struct ieee80211_hdr *hdr; + u8 icv[4]; + u32 crc; + int plen; + + hdr = (struct ieee80211_hdr *)skb->data; + + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { + net_dbg_ratelimited("TKIP countermeasures: dropped received packet from %pM\n", + hdr->addr2); + return -1; + } + + if (skb->len < hdr_len + TKIP_HDR_LEN + 4) + return -1; + + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + net_dbg_ratelimited("TKIP: received packet without ExtIV flag from %pM\n", + hdr->addr2); + return -2; + } + keyidx >>= 6; + if (tkey->key_idx != keyidx) { + net_dbg_ratelimited("TKIP: RX tkey->key_idx=%d frame keyidx=%d\n", + tkey->key_idx, keyidx); + return -6; + } + if (!tkey->key_set) { + net_dbg_ratelimited("TKIP: received packet from %pM with keyid=%d that does not have a configured key\n", + hdr->addr2, keyidx); + return -3; + } + iv16 = (pos[0] << 8) | pos[2]; + iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); + pos += TKIP_HDR_LEN; + + if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { +#ifdef CONFIG_LIBIPW_DEBUG + net_dbg_ratelimited("TKIP: replay detected: STA=%pM previous TSC %08x%04x received TSC %08x%04x\n", + hdr->addr2, tkey->rx_iv32, tkey->rx_iv16, + iv32, iv16); +#endif + tkey->dot11RSNAStatsTKIPReplays++; + return -4; + } + + if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { + tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); + tkey->rx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); + + plen = skb->len - hdr_len - 12; + + arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16); + arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4); + + crc = ~crc32_le(~0, pos, plen); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + if (iv32 != tkey->rx_iv32) { + /* Previously cached Phase1 result was already lost, so + * it needs to be recalculated for the next packet. */ + tkey->rx_phase1_done = 0; + } +#ifdef CONFIG_LIBIPW_DEBUG + net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n", + hdr->addr2); +#endif + tkey->dot11RSNAStatsTKIPICVErrors++; + return -5; + } + + /* Update real counters only after Michael MIC verification has + * completed */ + tkey->rx_iv32_new = iv32; + tkey->rx_iv16_new = iv16; + + /* Remove IV and ICV */ + memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, TKIP_HDR_LEN); + skb_trim(skb, skb->len - 4); + + return keyidx; +} + +static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr, + u8 *data, size_t data_len, u8 *mic) +{ + SHASH_DESC_ON_STACK(desc, tfm_michael); + int err; + + if (tfm_michael == NULL) { + pr_warn("%s(): tfm_michael == NULL\n", __func__); + return -1; + } + + desc->tfm = tfm_michael; + + if (crypto_shash_setkey(tfm_michael, key, 8)) + return -1; + + err = crypto_shash_init(desc); + if (err) + goto out; + err = crypto_shash_update(desc, hdr, 16); + if (err) + goto out; + err = crypto_shash_update(desc, data, data_len); + if (err) + goto out; + err = crypto_shash_final(desc, mic); + +out: + shash_desc_zero(desc); + return err; +} + +static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) +{ + struct ieee80211_hdr *hdr11; + + hdr11 = (struct ieee80211_hdr *)skb->data; + + switch (le16_to_cpu(hdr11->frame_control) & + (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ + break; + default: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + } + + if (ieee80211_is_data_qos(hdr11->frame_control)) { + hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11))) + & IEEE80211_QOS_CTL_TID_MASK; + } else + hdr[12] = 0; /* priority */ + + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + +static int libipw_michael_mic_add(struct sk_buff *skb, int hdr_len, + void *priv) +{ + struct libipw_tkip_data *tkey = priv; + u8 *pos; + + if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { + printk(KERN_DEBUG "Invalid packet for Michael MIC add " + "(tailroom=%d hdr_len=%d skb->len=%d)\n", + skb_tailroom(skb), hdr_len, skb->len); + return -1; + } + + michael_mic_hdr(skb, tkey->tx_hdr); + pos = skb_put(skb, 8); + if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) + return -1; + + return 0; +} + +static void libipw_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr *hdr, + int keyidx) +{ + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + + /* TODO: needed parameters: count, keyid, key type, TSC */ + memset(&ev, 0, sizeof(ev)); + ev.flags = keyidx & IW_MICFAILURE_KEY_ID; + if (hdr->addr1[0] & 0x01) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + ev.src_addr.sa_family = ARPHRD_ETHER; + memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); +} + +static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx, + int hdr_len, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + u8 mic[8]; + + if (!tkey->key_set) + return -1; + + michael_mic_hdr(skb, tkey->rx_hdr); + if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) + return -1; + if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { + struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *)skb->data; + printk(KERN_DEBUG "%s: Michael MIC verification failed for " + "MSDU from %pM keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", hdr->addr2, + keyidx); + if (skb->dev) + libipw_michael_mic_failure(skb->dev, hdr, keyidx); + tkey->dot11RSNAStatsTKIPLocalMICFailures++; + return -1; + } + + /* Update TSC counters for RX now that the packet verification has + * completed. */ + tkey->rx_iv32 = tkey->rx_iv32_new; + tkey->rx_iv16 = tkey->rx_iv16_new; + + skb_trim(skb, skb->len - 8); + + return 0; +} + +static int libipw_tkip_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + int keyidx; + struct crypto_shash *tfm = tkey->tx_tfm_michael; + struct arc4_ctx *tfm2 = &tkey->tx_ctx_arc4; + struct crypto_shash *tfm3 = tkey->rx_tfm_michael; + struct arc4_ctx *tfm4 = &tkey->rx_ctx_arc4; + + keyidx = tkey->key_idx; + memset(tkey, 0, sizeof(*tkey)); + tkey->key_idx = keyidx; + tkey->tx_tfm_michael = tfm; + tkey->tx_ctx_arc4 = *tfm2; + tkey->rx_tfm_michael = tfm3; + tkey->rx_ctx_arc4 = *tfm4; + if (len == TKIP_KEY_LEN) { + memcpy(tkey->key, key, TKIP_KEY_LEN); + tkey->key_set = 1; + tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ + if (seq) { + tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | + (seq[3] << 8) | seq[2]; + tkey->rx_iv16 = (seq[1] << 8) | seq[0]; + } + } else if (len == 0) + tkey->key_set = 0; + else + return -1; + + return 0; +} + +static int libipw_tkip_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + + if (len < TKIP_KEY_LEN) + return -1; + + if (!tkey->key_set) + return 0; + memcpy(key, tkey->key, TKIP_KEY_LEN); + + if (seq) { + /* + * Not clear if this should return the value as is + * or - as the code previously seemed to partially + * have been written as - subtract one from it. It + * was working this way for a long time so leave it. + */ + seq[0] = tkey->tx_iv16; + seq[1] = tkey->tx_iv16 >> 8; + seq[2] = tkey->tx_iv32; + seq[3] = tkey->tx_iv32 >> 8; + seq[4] = tkey->tx_iv32 >> 16; + seq[5] = tkey->tx_iv32 >> 24; + } + + return TKIP_KEY_LEN; +} + +static void libipw_tkip_print_stats(struct seq_file *m, void *priv) +{ + struct libipw_tkip_data *tkip = priv; + seq_printf(m, + "key[%d] alg=TKIP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "replays=%d icv_errors=%d local_mic_failures=%d\n", + tkip->key_idx, tkip->key_set, + (tkip->tx_iv32 >> 24) & 0xff, + (tkip->tx_iv32 >> 16) & 0xff, + (tkip->tx_iv32 >> 8) & 0xff, + tkip->tx_iv32 & 0xff, + (tkip->tx_iv16 >> 8) & 0xff, + tkip->tx_iv16 & 0xff, + (tkip->rx_iv32 >> 24) & 0xff, + (tkip->rx_iv32 >> 16) & 0xff, + (tkip->rx_iv32 >> 8) & 0xff, + tkip->rx_iv32 & 0xff, + (tkip->rx_iv16 >> 8) & 0xff, + tkip->rx_iv16 & 0xff, + tkip->dot11RSNAStatsTKIPReplays, + tkip->dot11RSNAStatsTKIPICVErrors, + tkip->dot11RSNAStatsTKIPLocalMICFailures); +} + +static const struct libipw_crypto_ops libipw_crypt_tkip = { + .name = "TKIP", + .init = libipw_tkip_init, + .deinit = libipw_tkip_deinit, + .encrypt_mpdu = libipw_tkip_encrypt, + .decrypt_mpdu = libipw_tkip_decrypt, + .encrypt_msdu = libipw_michael_mic_add, + .decrypt_msdu = libipw_michael_mic_verify, + .set_key = libipw_tkip_set_key, + .get_key = libipw_tkip_get_key, + .print_stats = libipw_tkip_print_stats, + .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .extra_msdu_postfix_len = 8, /* MIC */ + .get_flags = libipw_tkip_get_flags, + .set_flags = libipw_tkip_set_flags, + .owner = THIS_MODULE, +}; + +int __init libipw_crypto_tkip_init(void) +{ + return libipw_register_crypto_ops(&libipw_crypt_tkip); +} + +void libipw_crypto_tkip_exit(void) +{ + libipw_unregister_crypto_ops(&libipw_crypt_tkip); +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c new file mode 100644 index 000000000000..c3a4ccb9de17 --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * libipw crypt: host-based WEP encryption implementation for libipw + * + * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008, John W. Linville <linville@tuxdriver.com> + */ + +#include <linux/err.h> +#include <linux/fips.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/scatterlist.h> +#include <linux/skbuff.h> +#include <linux/mm.h> +#include <asm/string.h> +#include <crypto/arc4.h> +#include <linux/crc32.h> +#include "libipw.h" + +struct libipw_wep_data { + u32 iv; +#define WEP_KEY_LEN 13 + u8 key[WEP_KEY_LEN + 1]; + u8 key_len; + u8 key_idx; + struct arc4_ctx tx_ctx; + struct arc4_ctx rx_ctx; +}; + +static void *libipw_wep_init(int keyidx) +{ + struct libipw_wep_data *priv; + + if (fips_enabled) + return NULL; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + return NULL; + priv->key_idx = keyidx; + + /* start WEP IV from a random value */ + get_random_bytes(&priv->iv, 4); + + return priv; +} + +static void libipw_wep_deinit(void *priv) +{ + kfree_sensitive(priv); +} + +/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ +static int libipw_wep_build_iv(struct sk_buff *skb, int hdr_len, + u8 *key, int keylen, void *priv) +{ + struct libipw_wep_data *wep = priv; + u32 klen; + u8 *pos; + + if (skb_headroom(skb) < 4 || skb->len < hdr_len) + return -1; + + pos = skb_push(skb, 4); + memmove(pos, pos + 4, hdr_len); + pos += hdr_len; + + klen = 3 + wep->key_len; + + wep->iv++; + + /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key + * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) + * can be used to speedup attacks, so avoid using them. */ + if ((wep->iv & 0xff00) == 0xff00) { + u8 B = (wep->iv >> 16) & 0xff; + if (B >= 3 && B < klen) + wep->iv += 0x0100; + } + + /* Prepend 24-bit IV to RC4 key and TX frame */ + *pos++ = (wep->iv >> 16) & 0xff; + *pos++ = (wep->iv >> 8) & 0xff; + *pos++ = wep->iv & 0xff; + *pos++ = wep->key_idx << 6; + + return 0; +} + +/* Perform WEP encryption on given skb that has at least 4 bytes of headroom + * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, + * so the payload length increases with 8 bytes. + * + * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) + */ +static int libipw_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_wep_data *wep = priv; + u32 crc, klen, len; + u8 *pos, *icv; + u8 key[WEP_KEY_LEN + 3]; + + /* other checks are in libipw_wep_build_iv */ + if (skb_tailroom(skb) < 4) + return -1; + + /* add the IV to the frame */ + if (libipw_wep_build_iv(skb, hdr_len, NULL, 0, priv)) + return -1; + + /* Copy the IV into the first 3 bytes of the key */ + skb_copy_from_linear_data_offset(skb, hdr_len, key, 3); + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + len = skb->len - hdr_len - 4; + pos = skb->data + hdr_len + 4; + klen = 3 + wep->key_len; + + /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */ + crc = ~crc32_le(~0, pos, len); + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + arc4_setkey(&wep->tx_ctx, key, klen); + arc4_crypt(&wep->tx_ctx, pos, pos, len + 4); + + return 0; +} + +/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of + * the frame: IV (4 bytes), encrypted payload (including SNAP header), + * ICV (4 bytes). len includes both IV and ICV. + * + * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on + * failure. If frame is OK, IV and ICV will be removed. + */ +static int libipw_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_wep_data *wep = priv; + u32 crc, klen, plen; + u8 key[WEP_KEY_LEN + 3]; + u8 keyidx, *pos, icv[4]; + + if (skb->len < hdr_len + 8) + return -1; + + pos = skb->data + hdr_len; + key[0] = *pos++; + key[1] = *pos++; + key[2] = *pos++; + keyidx = *pos++ >> 6; + if (keyidx != wep->key_idx) + return -1; + + klen = 3 + wep->key_len; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + /* Apply RC4 to data and compute CRC32 over decrypted data */ + plen = skb->len - hdr_len - 8; + + arc4_setkey(&wep->rx_ctx, key, klen); + arc4_crypt(&wep->rx_ctx, pos, pos, plen + 4); + + crc = ~crc32_le(~0, pos, plen); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + /* ICV mismatch - drop frame */ + return -2; + } + + /* Remove IV and ICV */ + memmove(skb->data + 4, skb->data, hdr_len); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + + return 0; +} + +static int libipw_wep_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_wep_data *wep = priv; + + if (len < 0 || len > WEP_KEY_LEN) + return -1; + + memcpy(wep->key, key, len); + wep->key_len = len; + + return 0; +} + +static int libipw_wep_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_wep_data *wep = priv; + + if (len < wep->key_len) + return -1; + + memcpy(key, wep->key, wep->key_len); + + return wep->key_len; +} + +static void libipw_wep_print_stats(struct seq_file *m, void *priv) +{ + struct libipw_wep_data *wep = priv; + seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); +} + +static const struct libipw_crypto_ops libipw_crypt_wep = { + .name = "WEP", + .init = libipw_wep_init, + .deinit = libipw_wep_deinit, + .encrypt_mpdu = libipw_wep_encrypt, + .decrypt_mpdu = libipw_wep_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = libipw_wep_set_key, + .get_key = libipw_wep_get_key, + .print_stats = libipw_wep_print_stats, + .extra_mpdu_prefix_len = 4, /* IV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .owner = THIS_MODULE, +}; + +int __init libipw_crypto_wep_init(void) +{ + return libipw_register_crypto_ops(&libipw_crypt_wep); +} + +void __exit libipw_crypto_wep_exit(void) +{ + libipw_unregister_crypto_ops(&libipw_crypt_wep); +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c index 43bab92a4148..0a16127bfd68 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c @@ -169,7 +169,7 @@ struct net_device *alloc_libipw(int sizeof_priv, int monitor) spin_lock_init(&ieee->lock); - lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock); + libipw_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock); ieee->wpa_enabled = 0; ieee->drop_unencrypted = 0; @@ -191,7 +191,7 @@ void free_libipw(struct net_device *dev, int monitor) { struct libipw_device *ieee = netdev_priv(dev); - lib80211_crypt_info_free(&ieee->crypt_info); + libipw_crypt_info_free(&ieee->crypt_info); libipw_networks_free(ieee); @@ -251,6 +251,7 @@ static const struct proc_ops debug_level_proc_ops = { static int __init libipw_init(void) { + int err; #ifdef CONFIG_LIBIPW_DEBUG struct proc_dir_entry *e; @@ -273,7 +274,33 @@ static int __init libipw_init(void) printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + err = libipw_crypto_init(); + if (err) + goto remove_debugfs; + err = libipw_crypto_ccmp_init(); + if (err) + goto uninit_crypto; + err = libipw_crypto_tkip_init(); + if (err) + goto uninit_crypto_ccmp; + err = libipw_crypto_wep_init(); + if (err) + goto uninit_crypto_tkip; + return 0; +uninit_crypto_tkip: + libipw_crypto_tkip_exit(); +uninit_crypto_ccmp: + libipw_crypto_ccmp_exit(); +uninit_crypto: + libipw_crypto_exit(); +remove_debugfs: +#ifdef CONFIG_LIBIPW_DEBUG + remove_proc_entry("debug_level", libipw_proc); + remove_proc_entry(DRV_PROCNAME, init_net.proc_net); + libipw_proc = NULL; +#endif + return err; } static void __exit libipw_exit(void) @@ -285,6 +312,11 @@ static void __exit libipw_exit(void) libipw_proc = NULL; } #endif /* CONFIG_LIBIPW_DEBUG */ + + libipw_crypto_ccmp_exit(); + libipw_crypto_tkip_exit(); + libipw_crypto_wep_exit(); + libipw_crypto_exit(); } #ifdef CONFIG_LIBIPW_DEBUG diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index 48d6870bbf4e..dc4e91f58bb4 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -27,9 +27,6 @@ #include <linux/etherdevice.h> #include <linux/uaccess.h> #include <linux/ctype.h> - -#include <net/lib80211.h> - #include "libipw.h" static void libipw_monitor_rx(struct libipw_device *ieee, @@ -266,7 +263,7 @@ static int libipw_is_eapol_frame(struct libipw_device *ieee, /* Called only as a tasklet (software IRQ), by libipw_rx */ static int libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb, - struct lib80211_crypt_data *crypt) + struct libipw_crypt_data *crypt) { struct libipw_hdr_3addr *hdr; int res, hdrlen; @@ -298,7 +295,7 @@ libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb, static int libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee, struct sk_buff *skb, int keyidx, - struct lib80211_crypt_data *crypt) + struct libipw_crypt_data *crypt) { struct libipw_hdr_3addr *hdr; int res, hdrlen; @@ -345,7 +342,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, #endif u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct lib80211_crypt_data *crypt = NULL; + struct libipw_crypt_data *crypt = NULL; int keyidx = 0; int can_be_decrypted = 0; @@ -396,7 +393,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, wstats.updated |= IW_QUAL_QUAL_INVALID; /* Update spy records */ - wireless_spy_update(ieee->dev, hdr->addr2, &wstats); + libipw_spy_update(ieee->dev, hdr->addr2, &wstats); } #endif /* IW_WIRELESS_SPY */ #endif /* CONFIG_WIRELESS_EXT */ @@ -870,8 +867,8 @@ void libipw_rx_any(struct libipw_device *ieee, switch (ieee->iw_mode) { case IW_MODE_ADHOC: /* our BSS and not from/to DS */ - if (ether_addr_equal(hdr->addr3, ieee->bssid)) - if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) { + if (ether_addr_equal(hdr->addr3, ieee->bssid) && + ((fc & (IEEE80211_FCTL_TODS + IEEE80211_FCTL_FROMDS)) == 0)) { /* promisc: get all */ if (ieee->dev->flags & IFF_PROMISC) is_packet_for_us = 1; @@ -885,8 +882,8 @@ void libipw_rx_any(struct libipw_device *ieee, break; case IW_MODE_INFRA: /* our BSS (== from our AP) and from DS */ - if (ether_addr_equal(hdr->addr2, ieee->bssid)) - if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) { + if (ether_addr_equal(hdr->addr2, ieee->bssid) && + ((fc & (IEEE80211_FCTL_TODS + IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS)) { /* promisc: get all */ if (ieee->dev->flags & IFF_PROMISC) is_packet_for_us = 1; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_spy.c b/drivers/net/wireless/intel/ipw2x00/libipw_spy.c new file mode 100644 index 000000000000..ba876e92f7f6 --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_spy.c @@ -0,0 +1,233 @@ +/* + * This file implement the Wireless Extensions spy API. + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ + +#include <linux/wireless.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/export.h> +#include <net/iw_handler.h> +#include <net/arp.h> +#include <net/wext.h> +#include "libipw.h" + +static struct iw_spy_data *get_spydata(struct net_device *dev) +{ + struct libipw_device *ieee = netdev_priv(dev); + + if (ieee->spy_enabled) + return &ieee->spy_data; + return NULL; +} + +int ipw_wx_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Disable spy collection while we copy the addresses. + * While we copy addresses, any call to libipw_spy_update() + * will NOP. This is OK, as anyway the addresses are changing. */ + spydata->spy_number = 0; + + /* We want to operate without locking, because libipw_spy_update() + * most likely will happen in the interrupt handler, and therefore + * have its own locking constraints and needs performance. + * The rtnl_lock() make sure we don't race with the other iw_handlers. + * This make sure libipw_spy_update() "see" that the spy list + * is temporarily disabled. */ + smp_wmb(); + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + int i; + + /* Copy addresses */ + for (i = 0; i < wrqu->data.length; i++) + memcpy(spydata->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(spydata->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + } + + /* Make sure above is updated before re-enabling */ + smp_wmb(); + + /* Enable addresses */ + spydata->spy_number = wrqu->data.length; + + return 0; +} +EXPORT_SYMBOL(ipw_wx_set_spy); + +int ipw_wx_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + int i; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + wrqu->data.length = spydata->spy_number; + + /* Copy addresses. */ + for (i = 0; i < spydata->spy_number; i++) { + memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if (spydata->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), + spydata->spy_stat, + sizeof(struct iw_quality) * spydata->spy_number); + /* Reset updated flags. */ + for (i = 0; i < spydata->spy_number; i++) + spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; + return 0; +} +EXPORT_SYMBOL(ipw_wx_get_spy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set spy threshold + */ +int ipw_wx_set_thrspy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + spydata->spy_thr_low = threshold->low; + spydata->spy_thr_high = threshold->high; + + /* Clear flag */ + memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); + + return 0; +} +EXPORT_SYMBOL(ipw_wx_set_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get spy threshold + */ +int ipw_wx_get_thrspy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + threshold->low = spydata->spy_thr_low; + threshold->high = spydata->spy_thr_high; + + return 0; +} +EXPORT_SYMBOL(ipw_wx_get_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Prepare and send a Spy Threshold event + */ +static void iw_send_thrspy_event(struct net_device * dev, + struct iw_spy_data * spydata, + unsigned char * address, + struct iw_quality * wstats) +{ + union iwreq_data wrqu; + struct iw_thrspy threshold; + + /* Init */ + wrqu.data.length = 1; + wrqu.data.flags = 0; + /* Copy address */ + memcpy(threshold.addr.sa_data, address, ETH_ALEN); + threshold.addr.sa_family = ARPHRD_ETHER; + /* Copy stats */ + threshold.qual = *wstats; + /* Copy also thresholds */ + threshold.low = spydata->spy_thr_low; + threshold.high = spydata->spy_thr_high; + + /* Send event to user space */ + wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); +} + +/* ---------------------------------------------------------------- */ +/* + * Call for the driver to update the spy data. + * For now, the spy data is a simple array. As the size of the array is + * small, this is good enough. If we wanted to support larger number of + * spy addresses, we should use something more efficient... + */ +void libipw_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats) +{ + struct iw_spy_data * spydata = get_spydata(dev); + int i; + int match = -1; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return; + + /* Update all records that match */ + for (i = 0; i < spydata->spy_number; i++) + if (ether_addr_equal(address, spydata->spy_address[i])) { + memcpy(&(spydata->spy_stat[i]), wstats, + sizeof(struct iw_quality)); + match = i; + } + + /* Generate an event if we cross the spy threshold. + * To avoid event storms, we have a simple hysteresis : we generate + * event only when we go under the low threshold or above the + * high threshold. */ + if (match >= 0) { + if (spydata->spy_thr_under[match]) { + if (wstats->level > spydata->spy_thr_high.level) { + spydata->spy_thr_under[match] = 0; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } else { + if (wstats->level < spydata->spy_thr_low.level) { + spydata->spy_thr_under[match] = 1; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } + } +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index e22a6732a4c3..80edaa3dea9c 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -138,7 +138,7 @@ static int libipw_copy_snap(u8 * data, __be16 h_proto) static int libipw_encrypt_fragment(struct libipw_device *ieee, struct sk_buff *frag, int hdr_len) { - struct lib80211_crypt_data *crypt = + struct libipw_crypt_data *crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; int res; @@ -255,7 +255,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) .qos_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; int priority = skb->priority; int snapped = 0; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c index dbc7153d0a3d..db71d81b0d4f 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c @@ -21,10 +21,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/jiffies.h> - -#include <net/lib80211.h> #include <linux/wireless.h> - #include "libipw.h" static const char *libipw_modes[] = { @@ -303,7 +300,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee, .flags = 0 }; int i, key, key_provided, len; - struct lib80211_crypt_data **crypt; + struct libipw_crypt_data **crypt; int host_crypto = ieee->host_encrypt || ieee->host_decrypt; LIBIPW_DEBUG_WX("SET_ENCODE\n"); @@ -328,7 +325,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee, if (key_provided && *crypt) { LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n", key); - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt); } else LIBIPW_DEBUG_WX("Disabling encryption.\n"); @@ -338,7 +335,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee, if (ieee->crypt_info.crypt[i] != NULL) { if (key_provided) break; - lib80211_crypt_delayed_deinit(&ieee->crypt_info, + libipw_crypt_delayed_deinit(&ieee->crypt_info, &ieee->crypt_info.crypt[i]); } } @@ -361,21 +358,21 @@ int libipw_wx_set_encode(struct libipw_device *ieee, strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm * on this key */ - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt); } if (*crypt == NULL && host_crypto) { - struct lib80211_crypt_data *new_crypt; + struct libipw_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), + new_crypt = kzalloc(sizeof(struct libipw_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; - new_crypt->ops = lib80211_get_crypto_ops("WEP"); + new_crypt->ops = libipw_get_crypto_ops("WEP"); if (!new_crypt->ops) { - request_module("lib80211_crypt_wep"); - new_crypt->ops = lib80211_get_crypto_ops("WEP"); + request_module("libipw_crypt_wep"); + new_crypt->ops = libipw_get_crypto_ops("WEP"); } if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) @@ -386,7 +383,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee, new_crypt = NULL; printk(KERN_WARNING "%s: could not initialize WEP: " - "load module lib80211_crypt_wep\n", dev->name); + "load module libipw_crypt_wep\n", dev->name); return -EOPNOTSUPP; } *crypt = new_crypt; @@ -509,8 +506,8 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, int i, idx, ret = 0; int group_key = 0; const char *alg, *module; - const struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; + const struct libipw_crypto_ops *ops; + struct libipw_crypt_data **crypt; struct libipw_security sec = { .flags = 0, @@ -541,7 +538,7 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, if ((encoding->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE) { if (*crypt) - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt); for (i = 0; i < WEP_KEYS; i++) if (ieee->crypt_info.crypt[i] != NULL) @@ -567,15 +564,15 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, switch (ext->alg) { case IW_ENCODE_ALG_WEP: alg = "WEP"; - module = "lib80211_crypt_wep"; + module = "libipw_crypt_wep"; break; case IW_ENCODE_ALG_TKIP: alg = "TKIP"; - module = "lib80211_crypt_tkip"; + module = "libipw_crypt_tkip"; break; case IW_ENCODE_ALG_CCMP: alg = "CCMP"; - module = "lib80211_crypt_ccmp"; + module = "libipw_crypt_ccmp"; break; default: LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -584,10 +581,10 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, goto done; } - ops = lib80211_get_crypto_ops(alg); + ops = libipw_get_crypto_ops(alg); if (ops == NULL) { request_module(module); - ops = lib80211_get_crypto_ops(alg); + ops = libipw_get_crypto_ops(alg); } if (ops == NULL) { LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -597,9 +594,9 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, } if (*crypt == NULL || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; + struct libipw_crypt_data *new_crypt; - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt); new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); if (new_crypt == NULL) { diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c index 14d2331ee6cb..b0656b143f77 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.c +++ b/drivers/net/wireless/intel/iwlegacy/3945.c @@ -566,7 +566,7 @@ il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR) || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { D_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status); - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + return; } /* Convert 3945's rssi indicator to dBm */ diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index fcccde7bb659..05c4af41bdb9 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -664,7 +664,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { D_RX("Bad CRC or FIFO: 0x%08X.\n", le32_to_cpu(rx_pkt_status)); - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + return; } /* This will be used in several places later */ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index fa1be8c54d3c..cd1fe8490ae5 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,10 +10,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 93 +#define IWL_BZ_UCODE_API_MAX 94 /* Lowest firmware API version supported */ -#define IWL_BZ_UCODE_API_MIN 90 +#define IWL_BZ_UCODE_API_MIN 92 /* NVM versions */ #define IWL_BZ_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index f1dd1c29f305..fc5e6e44c6aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,10 +10,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 93 +#define IWL_SC_UCODE_API_MAX 94 /* Lowest firmware API version supported */ -#define IWL_SC_UCODE_API_MIN 90 +#define IWL_SC_UCODE_API_MIN 92 /* NVM versions */ #define IWL_SC_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h index 2397fdc37fc5..9b942c4aabd9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h @@ -56,8 +56,6 @@ struct iwl_binding_cmd { } __packed; /* BINDING_CMD_API_S_VER_2 */ #define IWL_BINDING_CMD_SIZE_V1 sizeof(struct iwl_binding_cmd_v1) -#define IWL_LMAC_24G_INDEX 0 -#define IWL_LMAC_5G_INDEX 1 /* The maximal number of fragments in the FW's schedule session */ #define IWL_MVM_MAX_QUOTA 128 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h index 1fa5678c1cd6..a9fa5f054ce0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h @@ -40,4 +40,7 @@ enum iwl_ctxt_action { FW_CTXT_ACTION_REMOVE, }; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ +#define IWL_LMAC_24G_INDEX 0 +#define IWL_LMAC_5G_INDEX 1 + #endif /* __iwl_fw_api_context_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index ffee7927cf26..c2362bc786b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -368,7 +368,7 @@ enum iwl_wowlan_flags { }; /** - * struct iwl_wowlan_config_cmd - WoWLAN configuration (versions 5 and 6) + * struct iwl_wowlan_config_cmd_v6 - WoWLAN configuration (versions 5 and 6) * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters * @non_qos_seq: non-QoS sequence counter to use next. * Reserved if the struct has version >= 6. @@ -380,7 +380,7 @@ enum iwl_wowlan_flags { * @sta_id: station ID for wowlan. * @reserved: reserved */ -struct iwl_wowlan_config_cmd { +struct iwl_wowlan_config_cmd_v6 { __le32 wakeup_filter; __le16 non_qos_seq; __le16 qos_seq[8]; @@ -390,7 +390,27 @@ struct iwl_wowlan_config_cmd { u8 flags; u8 sta_id; u8 reserved; -} __packed; /* WOWLAN_CONFIG_API_S_VER_5 */ +} __packed; /* WOWLAN_CONFIG_API_S_VER_6 */ + +/** + * struct iwl_wowlan_config_cmd - WoWLAN configuration + * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters + * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down + * @is_11n_connection: indicates HT connection + * @offloading_tid: TID reserved for firmware use + * @flags: extra flags, see &enum iwl_wowlan_flags + * @sta_id: station ID for wowlan. + * @reserved: reserved + */ +struct iwl_wowlan_config_cmd { + __le32 wakeup_filter; + u8 wowlan_ba_teardown_tids; + u8 is_11n_connection; + u8 offloading_tid; + u8 flags; + u8 sta_id; + u8 reserved[3]; +} __packed; /* WOWLAN_CONFIG_API_S_VER_7 */ #define IWL_NUM_RSC 16 #define WOWLAN_KEY_MAX_SIZE 32 @@ -890,7 +910,7 @@ struct iwl_wowlan_mlo_gtk { } __packed; /* WOWLAN_MLO_GTK_KEY_API_S_VER_1 */ /** - * struct iwl_wowlan_info_notif - WoWLAN information notification + * struct iwl_wowlan_info_notif_v4 - WoWLAN information notification * @gtk: GTK data * @igtk: IGTK data * @bigtk: BIGTK data @@ -910,7 +930,7 @@ struct iwl_wowlan_mlo_gtk { * @reserved2: reserved * @mlo_gtks: array of GTKs of size num_mlo_link_keys for version >= 4 */ -struct iwl_wowlan_info_notif { +struct iwl_wowlan_info_notif_v4 { struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; @@ -930,6 +950,45 @@ struct iwl_wowlan_info_notif { } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */ /** + * struct iwl_wowlan_info_notif - WoWLAN information notification + * @gtk: GTK data + * @igtk: IGTK data + * @bigtk: BIGTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched patterns + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @tid_tear_down: bit mask of tids whose BA sessions were closed + * in suspend state + * @station_id: station id + * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs + * following this notif + * @tid_offloaded_tx: tid used by the firmware to transmit data packets + * while in wowlan + * @mlo_gtks: array of GTKs of size num_mlo_link_keys + */ +struct iwl_wowlan_info_notif { + struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 qos_seq_ctr; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + u8 tid_tear_down; + u8 station_id; + u8 num_mlo_link_keys; + u8 tid_offloaded_tx; + struct iwl_wowlan_mlo_gtk mlo_gtks[]; +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */ + +/** * struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification * @wake_packet_length: wakeup packet length * @station_id: station id diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 30a54c7fa001..b8dff139aa05 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -616,6 +616,9 @@ struct iwl_tof_range_req_ap_entry_v2 { * continue with the session and will provide the LMR feedback. * @IWL_INITIATOR_AP_FLAGS_TEST_INCORRECT_SAC: send an incorrect SAC in the * first NDP exchange. This is used for testing. + * @IWL_INITIATOR_AP_FLAGS_TEST_BAD_SLTF: use incorrect secure LTF tx key. This + * is used for testing. Only supported from version 15 of the range request + * command. */ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_ASAP = BIT(1), @@ -633,6 +636,7 @@ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_PMF = BIT(14), IWL_INITIATOR_AP_FLAGS_TERMINATE_ON_LMR_FEEDBACK = BIT(15), IWL_INITIATOR_AP_FLAGS_TEST_INCORRECT_SAC = BIT(16), + IWL_INITIATOR_AP_FLAGS_TEST_BAD_SLTF = BIT(17), }; /** @@ -767,7 +771,7 @@ enum iwl_location_cipher { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -814,7 +818,7 @@ struct iwl_tof_range_req_ap_entry_v6 { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -827,10 +831,10 @@ struct iwl_tof_range_req_ap_entry_v6 { * &IWL_INITIATOR_AP_FLAGS_TB is set. * @rx_pn: the next expected PN for protected management frames Rx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @tx_pn: the next PN to use for protected management frames Tx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. */ struct iwl_tof_range_req_ap_entry_v7 { __le32 initiator_ap_flags; @@ -872,7 +876,7 @@ struct iwl_tof_range_req_ap_entry_v7 { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -885,10 +889,10 @@ struct iwl_tof_range_req_ap_entry_v7 { * &IWL_INITIATOR_AP_FLAGS_TB is set. * @rx_pn: the next expected PN for protected management frames Rx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @tx_pn: the next PN to use for protected management frames Tx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. * bits 0 - 2: max LTF repetitions * bits 3 - 5: max number of spatial streams @@ -946,7 +950,7 @@ struct iwl_tof_range_req_ap_entry_v8 { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -961,10 +965,10 @@ struct iwl_tof_range_req_ap_entry_v8 { * &IWL_INITIATOR_AP_FLAGS_TB or &IWL_INITIATOR_AP_FLAGS_NON_TB is set. * @rx_pn: the next expected PN for protected management frames Rx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @tx_pn: the next PN to use for protected management frames Tx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. * bits 0 - 2: max LTF repetitions * bits 3 - 5: max number of spatial streams @@ -1029,7 +1033,7 @@ struct iwl_tof_range_req_ap_entry_v9 { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -1042,10 +1046,10 @@ struct iwl_tof_range_req_ap_entry_v9 { * &IWL_INITIATOR_AP_FLAGS_TB is set. * @rx_pn: the next expected PN for protected management frames Rx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @tx_pn: the next PN to use for protected management frames Tx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. * bits 0 - 2: max LTF repetitions * bits 3 - 5: max number of spatial streams diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index c46e24fc6a1e..b23d5fc4bbe6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -382,6 +382,8 @@ struct iwl_mac_config_cmd { * @LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwl_link_ctx_cfg_cmd::puncture_mask. * This flag can be set only if the MAC that this link relates to has * eht_support set to true. No longer used since _VER_3 of this command. + * @LINK_CONTEXT_MODIFY_BANDWIDTH: Covers iwl_link_ctx_cfg_cmd::modify_bandwidth. + * Request RX OMI to the AP to modify bandwidth of this link. * @LINK_CONTEXT_MODIFY_ALL: set all above flags */ enum iwl_link_ctx_modify_flags { @@ -393,6 +395,7 @@ enum iwl_link_ctx_modify_flags { LINK_CONTEXT_MODIFY_HE_PARAMS = BIT(5), LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE = BIT(6), LINK_CONTEXT_MODIFY_EHT_PARAMS = BIT(7), + LINK_CONTEXT_MODIFY_BANDWIDTH = BIT(8), LINK_CONTEXT_MODIFY_ALL = 0xff, }; /* LINK_CONTEXT_MODIFY_MASK_E_VER_1 */ @@ -434,6 +437,22 @@ enum iwl_link_ctx_flags { }; /* LINK_CONTEXT_FLAG_E_VER_1 */ /** + * enum iwl_link_modify_bandwidth - link modify (RX OMI) bandwidth + * @IWL_LINK_MODIFY_BW_20: request 20 MHz + * @IWL_LINK_MODIFY_BW_40: request 40 MHz + * @IWL_LINK_MODIFY_BW_80: request 80 MHz + * @IWL_LINK_MODIFY_BW_160: request 160 MHz + * @IWL_LINK_MODIFY_BW_320: request 320 MHz + */ +enum iwl_link_modify_bandwidth { + IWL_LINK_MODIFY_BW_20, + IWL_LINK_MODIFY_BW_40, + IWL_LINK_MODIFY_BW_80, + IWL_LINK_MODIFY_BW_160, + IWL_LINK_MODIFY_BW_320, +}; + +/** * struct iwl_link_config_cmd - command structure to configure the LINK context * in MLD API * ( LINK_CONFIG_CMD =0x9 ) @@ -457,6 +476,8 @@ enum iwl_link_ctx_flags { * @block_tx: tell the firmware that this link can't Tx. This should be used * only when a link is de-activated because of CSA with mode = 1. * Available since version 5. + * @modify_bandwidth: bandwidth request value for RX OMI (see also + * %LINK_CONTEXT_MODIFY_BANDWIDTH), from &enum iwl_link_modify_bandwidth. * @reserved1: in version 2, listen_lmac became reserved * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM @@ -500,10 +521,11 @@ struct iwl_link_config_cmd { __le32 modify_mask; __le32 active; union { - __le32 listen_lmac; + __le32 listen_lmac; /* only _VER_1 */ struct { - u8 block_tx; - u8 reserved1[3]; + u8 block_tx; /* since _VER_5 */ + u8 modify_bandwidth; /* since _VER_6 */ + u8 reserved1[2]; }; }; __le32 cck_rates; @@ -524,7 +546,7 @@ struct iwl_link_config_cmd { __le16 puncture_mask; /* removed in _VER_3 */ __le16 frame_time_rts_th; __le32 flags; - __le32 flags_mask; + __le32 flags_mask; /* removed in _VER_6 */ /* The below fields are for multi-bssid */ u8 ref_bssid_addr[6]; __le16 reserved_for_ref_bssid_addr; @@ -535,7 +557,7 @@ struct iwl_link_config_cmd { u8 ibss_bssid_addr[6]; __le16 reserved_for_ibss_bssid_addr; __le32 reserved3[8]; -} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5 */ +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5, _VER_6 */ /* Currently FW supports link ids in the range 0-3 and can have * at most two active links for each vif. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 977ca4ac166d..26301c0b06a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -17,7 +17,7 @@ #define NUM_MAC_INDEX_CDB (NUM_MAC_INDEX_DRIVER + 2) #define IWL_STATION_COUNT_MAX 16 -#define IWL_MVM_INVALID_STA 0xFF +#define IWL_INVALID_STA 0xFF enum iwl_ac { AC_BK, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 98d56e778d99..f4803b55adb9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2019, 2021-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2019, 2021-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -327,18 +327,19 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt); void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt, u32 timepoint, u32 timepoint_data); +bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id); void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt); void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt); -#define IWL_FW_CHECK_FAILED(_obj, _fmt, ...) \ - IWL_ERR_LIMIT(_obj, _fmt, __VA_ARGS__) +#define IWL_FW_CHECK_FAILED(_obj, ...) \ + IWL_ERR_LIMIT(_obj, __VA_ARGS__) #define IWL_FW_CHECK(_obj, _cond, _fmt, ...) \ ({ \ bool __cond = (_cond); \ \ if (unlikely(__cond)) \ - IWL_FW_CHECK_FAILED(_obj, _fmt, __VA_ARGS__); \ + IWL_FW_CHECK_FAILED(_obj, _fmt, ##__VA_ARGS__); \ \ unlikely(__cond); \ }) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index 8f107ceec407..8e0c85a1240d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -530,3 +530,28 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) } } IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs); + +bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id) +{ + struct error_table_start { + /* cf. struct iwl_error_event_table */ + u32 valid; + __le32 err_id; + } err_info = {}; + int ret; + + if (!base) + return false; + + ret = iwl_trans_read_mem_bytes(trans, base, + &err_info, sizeof(err_info)); + + if (ret) + return true; + + if (err_info.valid && err_id) + *err_id = le32_to_cpu(err_info.err_id); + + return !!err_info.valid; +} +IWL_EXPORT_SYMBOL(iwl_fwrt_read_err_table); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index e95ffe303547..c70da7281551 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1074,12 +1074,13 @@ int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs, void iwl_trans_debugfs_cleanup(struct iwl_trans *trans); #endif -#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \ - do { \ - if (__builtin_constant_p(bufsize)) \ - BUILD_BUG_ON((bufsize) % sizeof(u32)); \ - iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\ - } while (0) +#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \ + ({ \ + if (__builtin_constant_p(bufsize)) \ + BUILD_BUG_ON((bufsize) % sizeof(u32)); \ + iwl_trans_read_mem(trans, addr, buf, \ + (bufsize) / sizeof(u32)); \ + }) int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr, u64 src_addr, u32 byte_cnt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index b607961970e9..36726ea4b822 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -689,7 +689,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * Rssi update while not associated - can happen since the statistics * are handled asynchronously */ - if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA) + if (mvmvif->deflink.ap_sta_id == IWL_INVALID_STA) return; /* No BT - reports should be disabled */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index ddf484027d4f..776600ddaea6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -17,7 +17,9 @@ #define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC 30 #define IWL_MVM_TPT_COUNT_WINDOW_SEC 5 #define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS 5 -#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH 11 +#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH 15 +#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED 11 +#define IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH -72 #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) @@ -57,7 +59,6 @@ #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1 #define IWL_MVM_TOF_IS_RESPONDER 0 -#define IWL_MVM_HW_CSUM_DISABLE 0 #define IWL_MVM_ADWELL_ENABLE 1 #define IWL_MVM_ADWELL_MAX_BUDGET 0 #define IWL_MVM_TCM_LOAD_MEDIUM_THRESH 10 /* percentage */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 244ca8cab9d1..f85c01e04ebf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -922,7 +922,7 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) static int iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, struct cfg80211_wowlan *wowlan, - struct iwl_wowlan_config_cmd *wowlan_config_cmd, + struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, struct ieee80211_sta *ap_sta) { @@ -948,7 +948,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); } - iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); + if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 7) + iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); if (wowlan->disconnect) wowlan_config_cmd->wakeup_filter |= @@ -1122,7 +1123,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, static int iwl_mvm_wowlan_config(struct iwl_mvm *mvm, struct cfg80211_wowlan *wowlan, - struct iwl_wowlan_config_cmd *wowlan_config_cmd, + struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd_v6, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, struct iwl_mvm_vif_link_info *mvm_link, struct ieee80211_sta *ap_sta) @@ -1131,7 +1132,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - mvm->offload_tid = wowlan_config_cmd->offloading_tid; + mvm->offload_tid = wowlan_config_cmd_v6->offloading_tid; if (!unified_image) { ret = iwl_mvm_switch_to_d3(mvm); @@ -1147,9 +1148,26 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, if (ret) return ret; - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, - sizeof(*wowlan_config_cmd), - wowlan_config_cmd); + if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) > 6) { + struct iwl_wowlan_config_cmd wowlan_config_cmd = { + .wakeup_filter = wowlan_config_cmd_v6->wakeup_filter, + .wowlan_ba_teardown_tids = + wowlan_config_cmd_v6->wowlan_ba_teardown_tids, + .is_11n_connection = + wowlan_config_cmd_v6->is_11n_connection, + .offloading_tid = wowlan_config_cmd_v6->offloading_tid, + .flags = wowlan_config_cmd_v6->flags, + .sta_id = wowlan_config_cmd_v6->sta_id, + }; + + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, + sizeof(wowlan_config_cmd), + &wowlan_config_cmd); + } else { + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, + sizeof(*wowlan_config_cmd_v6), + wowlan_config_cmd_v6); + } if (ret) return ret; @@ -1288,7 +1306,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, goto out_noreset; } - if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) { + if (mvm_link->ap_sta_id == IWL_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) { ret = 1; @@ -1302,7 +1320,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvm->net_detect = true; } else { - struct iwl_wowlan_config_cmd wowlan_config_cmd = { + struct iwl_wowlan_config_cmd_v6 wowlan_config_cmd = { .offloading_tid = 0, }; @@ -1425,6 +1443,7 @@ struct iwl_wowlan_status_data { u16 non_qos_seq_ctr; u16 qos_seq_ctr[8]; u8 tid_tear_down; + u8 tid_offloaded_tx; struct { /* including RX MIC key for TKIP */ @@ -2474,7 +2493,64 @@ static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, struct iwl_wowlan_info_notif *data, struct iwl_wowlan_status_data *status, - u32 len, bool has_mlo_keys) + u32 len) +{ + u32 expected_len = sizeof(*data) + + data->num_mlo_link_keys * sizeof(status->mlo_keys[0]); + + if (!data) { + IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n"); + status = NULL; + return; + } + + if (len < expected_len) { + IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); + status = NULL; + return; + } + + if (mvm->fast_resume) + return; + + iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc); + iwl_mvm_convert_gtk_v3(status, data->gtk); + iwl_mvm_convert_igtk(status, &data->igtk[0]); + iwl_mvm_convert_bigtk(status, data->bigtk); + status->replay_ctr = le64_to_cpu(data->replay_ctr); + status->pattern_number = le16_to_cpu(data->pattern_number); + status->tid_offloaded_tx = data->tid_offloaded_tx; + if (IWL_FW_CHECK(mvm, + data->tid_offloaded_tx >= + ARRAY_SIZE(status->qos_seq_ctr), + "tid_offloaded_tx is out of bound %d\n", + data->tid_offloaded_tx)) + data->tid_offloaded_tx = 0; + status->qos_seq_ctr[data->tid_offloaded_tx] = + le16_to_cpu(data->qos_seq_ctr); + status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons); + status->num_of_gtk_rekeys = + le32_to_cpu(data->num_of_gtk_rekeys); + status->received_beacons = le32_to_cpu(data->received_beacons); + status->tid_tear_down = data->tid_tear_down; + + if (data->num_mlo_link_keys) { + status->num_mlo_keys = data->num_mlo_link_keys; + if (IWL_FW_CHECK(mvm, + status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, + "Too many mlo keys: %d, max %d\n", + status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) + status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; + memcpy(status->mlo_keys, data->mlo_gtks, + status->num_mlo_keys * sizeof(status->mlo_keys[0])); + } +} + +static void +iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm, + struct iwl_wowlan_info_notif_v4 *data, + struct iwl_wowlan_status_data *status, + u32 len, bool has_mlo_keys) { u32 i; u32 expected_len = sizeof(*data); @@ -2746,6 +2822,10 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int link_id = vif->active_links ? __ffs(vif->active_links) : 0; struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id]; + int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw, + PROT_OFFLOAD_GROUP, + WOWLAN_INFO_NOTIFICATION, + IWL_FW_CMD_VER_UNKNOWN); if (WARN_ON(!mvm_link)) goto out_unlock; @@ -2760,11 +2840,14 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, if (!mvm_ap_sta) goto out_unlock; - for (i = 0; i < IWL_MAX_TID_COUNT; i++) { - u16 seq = status->qos_seq_ctr[i]; - /* firmware stores last-used value, we store next value */ - seq += 0x10; - mvm_ap_sta->tid_data[i].seq_number = seq; + /* firmware stores last-used value, we store next value */ + if (wowlan_info_ver >= 5) { + mvm_ap_sta->tid_data[status->tid_offloaded_tx].seq_number = + status->qos_seq_ctr[status->tid_offloaded_tx] + 0x10; + } else { + for (i = 0; i < IWL_MAX_TID_COUNT; i++) + mvm_ap_sta->tid_data[i].seq_number = + status->qos_seq_ctr[i] + 0x10; } if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { @@ -3026,34 +3109,15 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, ieee80211_resume_disconnect(vif); } -static bool iwl_mvm_rt_status(struct iwl_trans *trans, u32 base, u32 *err_id) -{ - struct error_table_start { - /* cf. struct iwl_error_event_table */ - u32 valid; - __le32 err_id; - } err_info; - - if (!base) - return false; - - iwl_trans_read_mem_bytes(trans, base, - &err_info, sizeof(err_info)); - if (err_info.valid && err_id) - *err_id = le32_to_cpu(err_info.err_id); - - return !!err_info.valid; -} - static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { u32 err_id; /* check for lmac1 error */ - if (iwl_mvm_rt_status(mvm->trans, - mvm->trans->dbg.lmac_error_event_table[0], - &err_id)) { + if (iwl_fwrt_read_err_table(mvm->trans, + mvm->trans->dbg.lmac_error_event_table[0], + &err_id)) { if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) { struct cfg80211_wowlan_wakeup wakeup = { .rfkill_release = true, @@ -3065,13 +3129,15 @@ static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm, } /* check if we have lmac2 set and check for error */ - if (iwl_mvm_rt_status(mvm->trans, - mvm->trans->dbg.lmac_error_event_table[1], NULL)) + if (iwl_fwrt_read_err_table(mvm->trans, + mvm->trans->dbg.lmac_error_event_table[1], + NULL)) return true; /* check for umac error */ - if (iwl_mvm_rt_status(mvm->trans, - mvm->trans->dbg.umac_error_event_table, NULL)) + if (iwl_fwrt_read_err_table(mvm->trans, + mvm->trans->dbg.umac_error_event_table, + NULL)) return true; return false; @@ -3092,7 +3158,7 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm, /* if FW uses status notification, status shouldn't be NULL here */ if (!d3_data->status) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA : + u8 sta_id = mvm->net_detect ? IWL_INVALID_STA : mvmvif->deflink.ap_sta_id; /* bug - FW with MLO has status notification */ @@ -3264,13 +3330,19 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, d3_data->status, len); + } else if (wowlan_info_ver < 5) { + struct iwl_wowlan_info_notif_v4 *notif = + (void *)pkt->data; + + iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif, + d3_data->status, len, + wowlan_info_ver > 3); } else { struct iwl_wowlan_info_notif *notif = (void *)pkt->data; iwl_mvm_parse_wowlan_info_notif(mvm, notif, - d3_data->status, len, - wowlan_info_ver > 3); + d3_data->status, len); } d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO; @@ -3612,8 +3684,6 @@ void iwl_mvm_fast_suspend(struct iwl_mvm *mvm) IWL_ERR(mvm, "fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret); - WARN_ON(iwl_mvm_power_update_mac(mvm)); - ret = iwl_trans_d3_suspend(mvm->trans, false, false); if (ret) IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret); @@ -3635,22 +3705,31 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm) iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); if (iwl_mvm_check_rt_status(mvm, NULL)) { + IWL_ERR(mvm, + "iwl_mvm_check_rt_status failed, device is gone during suspend\n"); set_bit(STATUS_FW_ERROR, &mvm->trans->status); iwl_mvm_dump_nic_error_log(mvm); iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL); iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, false, 0); - return -ENODEV; + mvm->trans->state = IWL_TRANS_NO_FW; + ret = -ENODEV; + + goto out; } ret = iwl_mvm_d3_notif_wait(mvm, &d3_data); + + if (ret) { + IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret); + mvm->trans->state = IWL_TRANS_NO_FW; + } + +out: clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; mvm->fast_resume = false; - if (ret) - IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret); - return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 25f07e00db42..fbe4e4a50852 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -221,7 +221,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, mvmvif->deflink.queue_params[i].uapsd); if (vif->type == NL80211_IFTYPE_STATION && - ap_sta_id != IWL_MVM_INVALID_STA) { + ap_sta_id != IWL_INVALID_STA) { struct iwl_mvm_sta *mvm_sta; mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id); @@ -463,11 +463,13 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, - size_t count, loff_t *ppos) +static ssize_t +iwl_dbgfs_low_latency_write_handle(struct wiphy *wiphy, struct file *file, + char *buf, size_t count, void *data) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct ieee80211_vif *vif = data; u8 value; int ret; @@ -484,12 +486,28 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, return count; } -static ssize_t -iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf, - size_t count, loff_t *ppos) +static ssize_t iwl_dbgfs_low_latency_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) { + struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; + char buf[10] = {}; + + return wiphy_locked_debugfs_write(mvm->hw->wiphy, file, + buf, sizeof(buf), user_buf, count, + iwl_dbgfs_low_latency_write_handle, + vif); +} + +static ssize_t +iwl_dbgfs_low_latency_force_write_handle(struct wiphy *wiphy, struct file *file, + char *buf, size_t count, void *data) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct ieee80211_vif *vif = data; u8 value; int ret; @@ -517,6 +535,22 @@ iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf, return count; } +static ssize_t +iwl_dbgfs_low_latency_force_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[10] = {}; + + return wiphy_locked_debugfs_write(mvm->hw->wiphy, file, + buf, sizeof(buf), user_buf, count, + iwl_dbgfs_low_latency_force_write_handle, + vif); +} + static ssize_t iwl_dbgfs_low_latency_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -831,8 +865,20 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params); MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt); MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10); + +static const struct file_operations iwl_dbgfs_low_latency_ops = { + .write = iwl_dbgfs_low_latency_write, + .read = iwl_dbgfs_low_latency_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static const struct file_operations iwl_dbgfs_low_latency_force_ops = { + .write = iwl_dbgfs_low_latency_force_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 55245f913286..b26141c30c61 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -559,12 +559,12 @@ static int iwl_mvm_ftm_set_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, #ifdef CONFIG_IWLWIFI_DEBUGFS if (mvmvif->ftm_unprotected) { - *sta_id = IWL_MVM_INVALID_STA; + *sta_id = IWL_INVALID_STA; *flags &= ~cpu_to_le32(IWL_INITIATOR_AP_FLAGS_PMF); } #endif } else { - *sta_id = IWL_MVM_INVALID_STA; + *sta_id = IWL_INVALID_STA; } return 0; @@ -1063,6 +1063,8 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_FW_CMD_VER_UNKNOWN); switch (cmd_ver) { + case 15: + /* Version 15 has the same struct as 14 */ case 14: err = iwl_mvm_ftm_start_v14(mvm, vif, req); break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index e4caa362f597..e6e468e81ab3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -131,7 +131,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (cmd_ver == 10) { + if (cmd_ver >= 10) { cmd.band = iwl_mvm_phy_band_from_nl80211(chandef->chan->band); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index f30b0fc8eca9..5ea684802ad1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1401,6 +1401,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) int ret, i; struct ieee80211_supported_band *sband = NULL; + lockdep_assert_wiphy(mvm->hw->wiphy); lockdep_assert_held(&mvm->mutex); ret = iwl_trans_start_hw(mvm->trans); @@ -1484,7 +1485,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) for (i = 0; i < IWL_FW_MAX_LINK_ID + 1; i++) RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL); - mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; + mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA; /* reset quota debouncing buffer - 0xff will yield invalid data */ memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); @@ -1620,6 +1621,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) { int ret, i; + lockdep_assert_wiphy(mvm->hw->wiphy); lockdep_assert_held(&mvm->mutex); ret = iwl_trans_start_hw(mvm->trans); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 2b0652168002..272da41567ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -12,6 +12,7 @@ HOW(BLOCKED_FW) \ HOW(BLOCKED_NON_BSS) \ HOW(BLOCKED_ROC) \ + HOW(BLOCKED_TMP_NON_BSS) \ HOW(EXIT_MISSED_BEACON) \ HOW(EXIT_LOW_RSSI) \ HOW(EXIT_COEX) \ @@ -360,7 +361,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, send_cmd: cmd.modify_mask = cpu_to_le32(changes); cmd.flags = cpu_to_le32(flags); - cmd.flags_mask = cpu_to_le32(flags_mask); + if (cmd_ver < 6) + cmd.flags_mask = cpu_to_le32(flags_mask); cmd.spec_link_id = link_conf->link_id; if (cmd_ver < 2) cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); @@ -1165,3 +1167,14 @@ void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (!mvmvif->esr_disable_reason) iwl_mvm_esr_unblocked(mvm, vif); } + +void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link) +{ + link->bcast_sta.sta_id = IWL_INVALID_STA; + link->mcast_sta.sta_id = IWL_INVALID_STA; + link->ap_sta_id = IWL_INVALID_STA; + + for (int r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++) + link->smps_requests[r] = + IEEE80211_SMPS_AUTOMATIC; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index a7a10e716e65..2a13d70da46c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -216,7 +216,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) .preferred_tsf = NUM_TSF_IDS, .found_vif = false, }; - int ret, i; + int ret; lockdep_assert_held(&mvm->mutex); @@ -298,9 +298,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif->time_event_data.id = TE_MAX; mvmvif->roc_activity = ROC_NUM_ACTIVITIES; - mvmvif->deflink.bcast_sta.sta_id = IWL_MVM_INVALID_STA; - mvmvif->deflink.mcast_sta.sta_id = IWL_MVM_INVALID_STA; - mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA; + iwl_mvm_init_link(&mvmvif->deflink); /* No need to allocate data queues to P2P Device MAC and NAN.*/ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) @@ -316,9 +314,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif->deflink.cab_queue = IWL_MVM_DQA_GCAST_QUEUE; } - for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) - mvmvif->deflink.smps_requests[i] = IEEE80211_SMPS_AUTOMATIC; - return 0; exit_fail: @@ -1605,6 +1600,7 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, 0); u8 new_notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, MISSED_BEACONS_NOTIF, 0); + struct ieee80211_bss_conf *bss_conf; /* If the firmware uses the new notification (from MAC_CONF_GROUP), * refer to that notification's version. @@ -1617,9 +1613,9 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, /* before version four the ID in the notification refers to mac ID */ if (notif_ver < 4) { vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false); + bss_conf = &vif->bss_conf; } else { - struct ieee80211_bss_conf *bss_conf = - iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, false); + bss_conf = iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, false); if (!bss_conf) return; @@ -1664,6 +1660,8 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, rx_missed_bcon, rx_missed_bcon_since_rx); } } else if (link_id >= 0 && hweight16(vif->active_links) > 1) { + u32 bss_param_ch_cnt_link_id = + bss_conf->bss_param_ch_cnt_link_id; u32 scnd_lnk_bcn_lost = 0; if (notif_ver >= 5 && @@ -1677,10 +1675,14 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, /* Exit EMLSR if we lost more than * IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH on any link. + * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED + * and the link's bss_param_ch_count has changed. */ if ((rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS && scnd_lnk_bcn_lost >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) || - rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH) + rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH || + (bss_param_ch_cnt_link_id != link_id && + rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED)) iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_MISSED_BEACON, iwl_mvm_get_primary_link(vif)); @@ -1689,6 +1691,9 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, ieee80211_beacon_loss(vif); else ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC); + + /* try to switch links, no-op if we don't have MLO */ + iwl_mvm_int_mlo_scan(mvm, vif); } iwl_dbg_tlv_time_point(&mvm->fwrt, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 80b9a115245f..07778d55878b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1109,7 +1109,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE; for_each_mvm_vif_valid_link(mvmvif, link_id) { - mvmvif->link[link_id]->ap_sta_id = IWL_MVM_INVALID_STA; + mvmvif->link[link_id]->ap_sta_id = IWL_INVALID_STA; mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; mvmvif->link[link_id]->phy_ctxt = NULL; mvmvif->link[link_id]->active = 0; @@ -1237,6 +1237,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm) fast_resume = mvm->fast_resume; if (fast_resume) { + iwl_mvm_mei_device_state(mvm, true); ret = iwl_mvm_fast_resume(mvm); if (ret) { iwl_mvm_stop_device(mvm); @@ -1344,6 +1345,8 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) * of packets the FW sent out, so we must reconnect. */ iwl_mvm_teardown_tdls_peers(mvm); + + IWL_INFO(mvm, "restart completed\n"); } void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, @@ -1377,10 +1380,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm, bool suspend) iwl_mvm_rm_aux_sta(mvm); if (suspend && - mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { iwl_mvm_fast_suspend(mvm); - else + /* From this point on, we won't touch the device */ + iwl_mvm_mei_device_state(mvm, false); + } else { iwl_mvm_stop_device(mvm); + } iwl_mvm_async_handlers_purge(mvm); /* async_handlers_list is empty and will stay empty: HW is stopped */ @@ -1474,15 +1480,16 @@ struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) return NULL; } -int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, + struct ieee80211_bss_conf *link_conf, s16 tx_power) { u32 cmd_id = REDUCE_TX_POWER_CMD; + u32 mac_id = iwl_mvm_vif_from_mac80211(link_conf->vif)->id; int len; struct iwl_dev_tx_power_cmd_v3_v8 cmd = { .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), - .common.mac_context_id = - cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), + .common.mac_context_id = cpu_to_le32(mac_id), }; struct iwl_dev_tx_power_cmd cmd_v9_v10; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 3); @@ -1495,8 +1502,7 @@ int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (cmd_ver > 8) { /* Those fields sit on the same place for v9 and v10 */ cmd_v9_v10.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC); - cmd_v9_v10.common.mac_context_id = - cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id); + cmd_v9_v10.common.mac_context_id = cpu_to_le32(mac_id); cmd_v9_v10.common.pwr_restriction = cpu_to_le16(u_tx_power); cmd_data = &cmd_v9_v10; } @@ -1739,6 +1745,21 @@ static void iwl_mvm_unblock_esr_tpt(struct wiphy *wiphy, struct wiphy_work *wk) iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT); } +static void iwl_mvm_unblock_esr_tmp_non_bss(struct wiphy *wiphy, + struct wiphy_work *wk) +{ + struct iwl_mvm_vif *mvmvif = + container_of(wk, struct iwl_mvm_vif, + unblock_esr_tmp_non_bss_wk.work); + struct iwl_mvm *mvm = mvmvif->mvm; + struct ieee80211_vif *vif = + container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); + + mutex_lock(&mvm->mutex); + iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); + mutex_unlock(&mvm->mutex); +} + void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) { lockdep_assert_held(&mvm->mutex); @@ -1757,6 +1778,9 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) wiphy_work_init(&mvmvif->unblock_esr_tpt_wk, iwl_mvm_unblock_esr_tpt); + + wiphy_delayed_work_init(&mvmvif->unblock_esr_tmp_non_bss_wk, + iwl_mvm_unblock_esr_tmp_non_bss); } static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, @@ -1907,6 +1931,8 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, &mvmvif->mlo_int_scan_wk); wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); + wiphy_delayed_work_cancel(mvm->hw->wiphy, + &mvmvif->unblock_esr_tmp_non_bss_wk); cancel_delayed_work_sync(&mvmvif->csa_work); } @@ -2929,7 +2955,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_MVM_SMPS_REQ_PROT, IEEE80211_SMPS_DYNAMIC, 0); } - } else if (mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { + } else if (mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) { iwl_mvm_mei_host_disassociated(mvm); /* * If update fails - SF might be running in associated @@ -2965,7 +2991,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_ERR(mvm, "failed to remove AP station\n"); - mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA; + mvmvif->deflink.ap_sta_id = IWL_INVALID_STA; } /* remove quota for this interface */ @@ -3311,7 +3337,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_TXPOWER) { IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n", bss_conf->txpower); - iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); + iwl_mvm_set_tx_power(mvm, bss_conf, bss_conf->txpower); } } @@ -3422,7 +3448,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, */ break; case STA_NOTIFY_AWAKE: - if (WARN_ON(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON(mvmsta->deflink.sta_id == IWL_INVALID_STA)) break; if (txqs) @@ -3502,6 +3528,8 @@ void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); unsigned int link_id; + lockdep_assert_wiphy(mvm->hw->wiphy); + /* * This is called before mac80211 does RCU synchronisation, * so here we already invalidate our internal RCU-protected @@ -4083,6 +4111,8 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, &mvmvif->mlo_int_scan_wk); wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); + wiphy_delayed_work_cancel(mvm->hw->wiphy, + &mvmvif->unblock_esr_tmp_non_bss_wk); /* No need for the periodic statistics anymore */ if (ieee80211_vif_is_mld(vif) && mvmvif->esr_active) @@ -4244,8 +4274,9 @@ int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) } void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); if (changed & (IEEE80211_RC_BW_CHANGED | @@ -5075,7 +5106,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | IEEE80211_CHANCTX_CHANGE_RX_CHAINS | IEEE80211_CHANCTX_CHANGE_RADAR | - IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)), + IEEE80211_CHANCTX_CHANGE_MIN_DEF)), "Cannot change PHY. Ref=%d, changed=0x%X\n", phy_ctxt->ref, changed)) return; @@ -5083,7 +5114,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, guard(mvm)(mvm); /* we are only changing the min_width, may be a noop */ - if (changed == IEEE80211_CHANCTX_CHANGE_MIN_WIDTH) { + if (changed == IEEE80211_CHANCTX_CHANGE_MIN_DEF) { if (phy_ctxt->width == def->width) return; @@ -6570,7 +6601,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, - .sta_rc_update = iwl_mvm_sta_rc_update, + .link_sta_rc_update = iwl_mvm_sta_rc_update, .conf_tx = iwl_mvm_mac_conf_tx, .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index 455f5f417506..ef0be44207e1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -396,7 +396,7 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm, u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0); if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION || - link->ap_sta_id == IWL_MVM_INVALID_STA)) + link->ap_sta_id == IWL_INVALID_STA)) return; if (!sec_key_ver) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index e252f0dcea20..b807046144c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -339,33 +339,20 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, if (ret) goto out; - /* Initialize rate control for the AP station, since we might be - * doing a link switch here - we cannot initialize it before since - * this needs the phy context assigned (and in FW?), and we cannot - * do it later because it needs to be initialized as soon as we're - * able to TX on the link, i.e. when active. + /* + * if link switching (link not active yet) we'll activate it in + * firmware later on link-info change, which mac80211 guarantees + * for link switch after the stations are set up */ - if (mvmvif->ap_sta) { - struct ieee80211_link_sta *link_sta; - - rcu_read_lock(); - link_sta = rcu_dereference(mvmvif->ap_sta->link[link_id]); - - if (!WARN_ON_ONCE(!link_sta)) - iwl_mvm_rs_rate_init(mvm, vif, mvmvif->ap_sta, - link_conf, link_sta, - phy_ctxt->channel->band); - rcu_read_unlock(); + if (ieee80211_vif_link_active(vif, link_conf->link_id)) { + ret = iwl_mvm_link_changed(mvm, vif, link_conf, + LINK_CONTEXT_MODIFY_ACTIVE | + LINK_CONTEXT_MODIFY_RATES_INFO, + true); + if (ret) + goto out; } - /* then activate */ - ret = iwl_mvm_link_changed(mvm, vif, link_conf, - LINK_CONTEXT_MODIFY_ACTIVE | - LINK_CONTEXT_MODIFY_RATES_INFO, - true); - if (ret) - goto out; - if (vif->type == NL80211_IFTYPE_STATION) iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif, link_conf, @@ -783,6 +770,11 @@ iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, if (WARN_ON_ONCE(!mvmvif->link[link_conf->link_id])) return; + /* not yet marked active in vif means during link switch */ + if (!ieee80211_vif_link_active(vif, link_conf->link_id) && + vif->cfg.assoc && mvmvif->link[link_conf->link_id]->phy_ctxt) + link_changes |= LINK_CONTEXT_MODIFY_ACTIVE; + has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax; has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be; @@ -832,7 +824,7 @@ static bool iwl_mvm_mld_vif_have_valid_ap_sta(struct iwl_mvm_vif *mvmvif) int i; for_each_mvm_vif_valid_link(mvmvif, i) { - if (mvmvif->link[i]->ap_sta_id != IWL_MVM_INVALID_STA) + if (mvmvif->link[i]->ap_sta_id != IWL_INVALID_STA) return true; } @@ -859,7 +851,7 @@ static void iwl_mvm_mld_vif_delete_all_stas(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to remove AP station\n"); - link->ap_sta_id = IWL_MVM_INVALID_STA; + link->ap_sta_id = IWL_INVALID_STA; } } @@ -1046,7 +1038,7 @@ static void iwl_mvm_mld_link_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_TXPOWER) { IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n", link_conf->txpower); - iwl_mvm_set_tx_power(mvm, vif, link_conf->txpower); + iwl_mvm_set_tx_power(mvm, link_conf, link_conf->txpower); } } @@ -1177,8 +1169,6 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, int err, i; for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { - int r; - if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) break; @@ -1190,14 +1180,8 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, goto free; } - new_link[i]->bcast_sta.sta_id = IWL_MVM_INVALID_STA; - new_link[i]->mcast_sta.sta_id = IWL_MVM_INVALID_STA; - new_link[i]->ap_sta_id = IWL_MVM_INVALID_STA; new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; - - for (r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++) - new_link[i]->smps_requests[r] = - IEEE80211_SMPS_AUTOMATIC; + iwl_mvm_init_link(new_link[i]); } mutex_lock(&mvm->mutex); @@ -1388,6 +1372,36 @@ iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw, return ret; } +#define IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT (5 * HZ) + +static void iwl_mvm_mld_prep_add_interface(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); + struct iwl_mvm_vif *mvmvif; + int ret; + + IWL_DEBUG_MAC80211(mvm, "prep_add_interface: type=%u\n", + type); + + if (IS_ERR_OR_NULL(bss_vif) || + !(type == NL80211_IFTYPE_AP || + type == NL80211_IFTYPE_P2P_GO || + type == NL80211_IFTYPE_P2P_CLIENT)) + return; + + mvmvif = iwl_mvm_vif_from_mac80211(bss_vif); + ret = iwl_mvm_block_esr_sync(mvm, bss_vif, + IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); + if (ret) + return; + + wiphy_delayed_work_queue(mvmvif->mvm->hw->wiphy, + &mvmvif->unblock_esr_tmp_non_bss_wk, + IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT); +} + const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .tx = iwl_mvm_mac_tx, .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, @@ -1413,7 +1427,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, - .sta_rc_update = iwl_mvm_sta_rc_update, + .link_sta_rc_update = iwl_mvm_sta_rc_update, .conf_tx = iwl_mvm_mld_mac_conf_tx, .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, @@ -1484,4 +1498,5 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .change_sta_links = iwl_mvm_mld_change_sta_links, .can_activate_links = iwl_mvm_mld_can_activate_links, .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm, + .prep_add_interface = iwl_mvm_mld_prep_add_interface, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index 28a9d90ad1cd..019839604011 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -146,7 +146,7 @@ int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout : mvm->trans->trans_cfg->base_params->wd_timeout; - if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA)) return -ENOSPC; if (sta->type == STATION_TYPE_AUX) @@ -346,7 +346,7 @@ static int iwl_mvm_mld_rm_int_sta(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(int_sta->sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(int_sta->sta_id == IWL_INVALID_STA)) return -EINVAL; if (flush) @@ -521,6 +521,9 @@ void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm, unsigned int link_id, bool is_in_fw) { + lockdep_assert_wiphy(mvm->hw->wiphy); + lockdep_assert_held(&mvm->mutex); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id], is_in_fw ? ERR_PTR(-EINVAL) : NULL); RCU_INIT_POINTER(mvm->fw_id_to_link_sta[mvm_sta_link->sta_id], NULL); @@ -559,7 +562,10 @@ static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm, u32 sta_id = iwl_mvm_find_free_sta_id(mvm, ieee80211_vif_type_p2p(vif)); - if (sta_id == IWL_MVM_INVALID_STA) + lockdep_assert_wiphy(mvm->hw->wiphy); + lockdep_assert_held(&mvm->mutex); + + if (sta_id == IWL_INVALID_STA) return -ENOSPC; if (rcu_access_pointer(sta->link[link_id]) == &sta->deflink) { @@ -612,10 +618,10 @@ static void iwl_mvm_mld_set_ap_sta_id(struct ieee80211_sta *sta, struct iwl_mvm_link_sta *sta_link) { if (!sta->tdls) { - WARN_ON(vif_link->ap_sta_id != IWL_MVM_INVALID_STA); + WARN_ON(vif_link->ap_sta_id != IWL_INVALID_STA); vif_link->ap_sta_id = sta_link->sta_id; } else { - WARN_ON(vif_link->ap_sta_id == IWL_MVM_INVALID_STA); + WARN_ON(vif_link->ap_sta_id == IWL_INVALID_STA); } } @@ -631,6 +637,9 @@ static int iwl_mvm_alloc_sta_after_restart(struct iwl_mvm *mvm, int ret = -EINVAL; int sta_id; + lockdep_assert_wiphy(mvm->hw->wiphy); + lockdep_assert_held(&mvm->mutex); + /* First add an empty station since allocating a queue requires * a valid station. Since we need a link_id to allocate a station, * pick up the first valid one. @@ -686,7 +695,7 @@ int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, spin_lock_init(&mvm_sta->lock); - ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_MVM_INVALID_STA, + ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_INVALID_STA, STATION_TYPE_PEER); } else { ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta); @@ -858,9 +867,10 @@ int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id) { int ret; + lockdep_assert_wiphy(mvm->hw->wiphy); lockdep_assert_held(&mvm->mutex); - if (WARN_ON(sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON(sta_id == IWL_INVALID_STA)) return 0; ret = iwl_mvm_mld_rm_sta_from_fw(mvm, sta_id); @@ -1064,6 +1074,7 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, unsigned int link_id; int ret; + lockdep_assert_wiphy(mvm->hw->wiphy); lockdep_assert_held(&mvm->mutex); for_each_set_bit(link_id, &old_links_long, @@ -1109,7 +1120,7 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, goto err; if (vif->type == NL80211_IFTYPE_STATION) - mvm_vif_link->ap_sta_id = IWL_MVM_INVALID_STA; + mvm_vif_link->ap_sta_id = IWL_INVALID_STA; iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id, false); @@ -1182,6 +1193,9 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, link_sta_added_to_fw |= BIT(link_id); iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link); + + iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta, + link_conf->chanreq.oper.chan->band); } if (sta_mask_added) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ef07cff203b0..2ad615293c75 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -361,6 +361,9 @@ struct iwl_mvm_vif_link_info { * @IWL_MVM_ESR_BLOCKED_NON_BSS: An active non-BSS interface's link is * preventing EMLSR * @IWL_MVM_ESR_BLOCKED_ROC: remain-on-channel is preventing EMLSR + * @IWL_MVM_ESR_BLOCKED_TMP_NON_BSS: An expected active non-BSS interface's link + * is preventing EMLSR. This is a temporary blocking that is set when there + * is an indication that a non-BSS interface is to be added. * @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons * @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR * due to low RSSI. @@ -379,6 +382,7 @@ enum iwl_mvm_esr_state { IWL_MVM_ESR_BLOCKED_FW = 0x8, IWL_MVM_ESR_BLOCKED_NON_BSS = 0x10, IWL_MVM_ESR_BLOCKED_ROC = 0x20, + IWL_MVM_ESR_BLOCKED_TMP_NON_BSS = 0x40, IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000, IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000, IWL_MVM_ESR_EXIT_COEX = 0x40000, @@ -452,6 +456,8 @@ struct iwl_mvm_esr_exit { * @prevent_esr_done_wk: work that should be done when esr prevention ends. * @mlo_int_scan_wk: work for the internal MLO scan. * @unblock_esr_tpt_wk: work for unblocking EMLSR when tpt is high enough. + * @unblock_esr_tmp_non_bss_wk: work for removing the + * IWL_MVM_ESR_BLOCKED_TMP_NON_BSS blocking for EMLSR. * @roc_activity: currently running ROC activity for this vif (or * ROC_NUM_ACTIVITIES if no activity is running). * @session_prot_connection_loss: the connection was lost due to session @@ -588,6 +594,7 @@ struct iwl_mvm_vif { struct wiphy_delayed_work prevent_esr_done_wk; struct wiphy_delayed_work mlo_int_scan_wk; struct wiphy_work unblock_esr_tpt_wk; + struct wiphy_delayed_work unblock_esr_tmp_non_bss_wk; struct iwl_mvm_vif_link_info deflink; struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -773,7 +780,6 @@ struct iwl_mvm_tcm { * @head_sn: reorder window head sn * @num_stored: number of mpdus stored in the buffer * @queue: queue of this reorder buffer - * @last_amsdu: track last ASMDU SN for duplication detection * @valid: reordering is valid for this queue * @lock: protect reorder buffer internal state */ @@ -781,7 +787,6 @@ struct iwl_mvm_reorder_buffer { u16 head_sn; u16 num_stored; int queue; - u16 last_amsdu; bool valid; spinlock_t lock; } ____cacheline_aligned_in_smp; @@ -1077,6 +1082,7 @@ struct iwl_mvm { /* data related to data path */ struct iwl_rx_phy_info last_phy_info; struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_STATION_COUNT_MAX]; + /* note: fw_id_to_link_sta must be protected by wiphy and mvm mutexes */ struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX]; u8 rx_ba_sessions; @@ -1584,8 +1590,7 @@ static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm) static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm) { return fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CSUM_SUPPORT) && - !IWL_MVM_HW_CSUM_DISABLE; + IWL_UCODE_TLV_CAPA_CSUM_SUPPORT); } static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm) @@ -2100,6 +2105,7 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band); /* Links */ +void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link); int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -2327,7 +2333,7 @@ static inline int iwl_mvm_fast_resume(struct iwl_mvm *mvm) } #endif void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, - struct iwl_wowlan_config_cmd *cmd); + struct iwl_wowlan_config_cmd_v6 *cmd); int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool disable_offloading, @@ -2914,7 +2920,7 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, bool more_data); int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value); void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed); + struct ieee80211_link_sta *link_sta, u32 changed); void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_prep_tx_info *info); @@ -2982,7 +2988,8 @@ void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool iwl_mvm_have_links_same_channel(struct iwl_mvm_vif *vif1, struct iwl_mvm_vif *vif2); bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif); -int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, + struct ieee80211_bss_conf *bss_conf, s16 tx_power); int iwl_mvm_set_hw_timestamp(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index 1eb21fe861e5..15d4369678a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -10,7 +10,7 @@ #include "mvm.h" void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, - struct iwl_wowlan_config_cmd *cmd) + struct iwl_wowlan_config_cmd_v6 *cmd) { int i; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 4dd4a9d5c71f..e25d7570ffab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1505,8 +1505,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->scan_cmd_size = scan_size; /* invalidate ids to prevent accidental removal of sta_id 0 */ - mvm->aux_sta.sta_id = IWL_MVM_INVALID_STA; - mvm->snif_sta.sta_id = IWL_MVM_INVALID_STA; + mvm->aux_sta.sta_id = IWL_INVALID_STA; + mvm->snif_sta.sta_id = IWL_INVALID_STA; /* Set EBS as successful as long as not stated otherwise by the FW. */ mvm->last_ebs_successful = true; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 05715e5af6ab..de5ac000272e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -440,12 +440,6 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (!mvmsta) { - IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", - notif->sta_id); - goto out; - } - flags = le32_to_cpu(notif->flags); mvm_link_sta = rcu_dereference(mvmsta->link[link_sta->link_id]); @@ -615,11 +609,8 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, int cmd_ver; int ret; - /* Enable external EHT LTF only for GL device and if there's - * mutual support by AP and client - */ - if (CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && - sband_eht_cap && + /* Enable extra EHT LTF if there's mutual support by AP and client */ + if (sband_eht_cap && sband_eht_cap->eht_cap_elem.phy_cap_info[5] & IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF && link_sta->eht_cap.has_eht && diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 1a0b5f8d4339..9e72db9bab40 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -560,7 +560,8 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig, struct iwl_mvm_vif_link_info *link_info, struct ieee80211_bss_conf *bss_conf) { - struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(vif)->mvm; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; int thold = bss_conf->cqm_rssi_thold; int hyst = bss_conf->cqm_rssi_hyst; int last_event; @@ -625,6 +626,13 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig, if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) return; + /* We're not in EMLSR and our signal is bad, try to switch link maybe */ + if (sig < IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH && !mvmvif->esr_active) { + iwl_mvm_int_mlo_scan(mvm, vif); + return; + } + + /* We are in EMLSR, check if we need to exit */ exit_esr_thresh = iwl_mvm_get_esr_rssi_thresh(mvm, &bss_conf->chanreq.oper, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 65f8933c34b4..a2f16bfaec44 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -773,9 +773,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, return false; } - rcu_read_lock(); sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1); - rcu_read_unlock(); if (IWL_FW_CHECK(mvm, tid != baid_data->tid || @@ -814,7 +812,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { if (!amsdu || last_subframe) buffer->head_sn = nssn; - /* No need to update AMSDU last SN - we are moving the head */ + spin_unlock_bh(&buffer->lock); return false; } @@ -831,7 +829,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, if (!amsdu || last_subframe) buffer->head_sn = ieee80211_sn_inc(buffer->head_sn); - /* No need to update AMSDU last SN - we are moving the head */ spin_unlock_bh(&buffer->lock); return false; } @@ -841,9 +838,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, __skb_queue_tail(&entries[index].frames, skb); buffer->num_stored++; - if (amsdu) - buffer->last_amsdu = sn; - /* * We cannot trust NSSN for AMSDU sub-frames that are not the last. * The reason is that NSSN advances on the first sub-frame, and may diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index ddcbd80a49fb..376b9b12fa62 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -3597,7 +3597,8 @@ static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, IWL_DEBUG_SCAN(mvm, "Starting Internal MLO scan: n_channels=%zu\n", n_channels); - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) + if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) || + hweight16(vif->valid_links) == 1) return -EINVAL; size = struct_size(req, channels, n_channels); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b6c99cd6d9e5..cd74c181c260 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -47,7 +47,7 @@ int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, enum nl80211_iftype iftype) lockdep_is_held(&mvm->mutex))) return sta_id; } - return IWL_MVM_INVALID_STA; + return IWL_INVALID_STA; } /* Calculate the ampdu density and max size */ @@ -1216,7 +1216,7 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, * can be unshared and finding one (and only one) that can be * reused. * This function is also invoked as a sort of clean-up task, - * in which case @alloc_for_sta is IWL_MVM_INVALID_STA. + * in which case @alloc_for_sta is IWL_INVALID_STA. * * Returns the queue number, or -ENOSPC. */ @@ -1309,7 +1309,7 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta) rcu_read_unlock(); - if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) { + if (free_queue >= 0 && alloc_for_sta != IWL_INVALID_STA) { ret = iwl_mvm_free_inactive_queue(mvm, free_queue, queue_owner, alloc_for_sta); if (ret) @@ -1522,7 +1522,7 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) mutex_lock(&mvm->mutex); - iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); + iwl_mvm_inactivity_check(mvm, IWL_INVALID_STA); while (!list_empty(&mvm->add_stream_txqs)) { struct iwl_mvm_txq *mvmtxq; @@ -1580,7 +1580,7 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, return 0; /* run the general cleanup/unsharing of queues */ - iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); + iwl_mvm_inactivity_check(mvm, IWL_INVALID_STA); /* Make sure we have free resources for this STA */ if (vif_type == NL80211_IFTYPE_STATION && !sta->tdls && @@ -1756,7 +1756,7 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * this function */ if (!mvm->mld_api_is_used) { - if (WARN_ON(sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON(sta_id == IWL_INVALID_STA)) return -EINVAL; mvm_sta->deflink.sta_id = sta_id; @@ -1865,7 +1865,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, else sta_id = mvm_sta->deflink.sta_id; - if (sta_id == IWL_MVM_INVALID_STA) + if (sta_id == IWL_INVALID_STA) return -ENOSPC; spin_lock_init(&mvm_sta->lock); @@ -1903,10 +1903,10 @@ update_fw: if (vif->type == NL80211_IFTYPE_STATION) { if (!sta->tdls) { - WARN_ON(mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA); + WARN_ON(mvmvif->deflink.ap_sta_id != IWL_INVALID_STA); mvmvif->deflink.ap_sta_id = sta_id; } else { - WARN_ON(mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA); + WARN_ON(mvmvif->deflink.ap_sta_id == IWL_INVALID_STA); } } @@ -2095,7 +2095,7 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_sec_key_remove_ap(mvm, vif, mvm_link, 0); /* unassoc - go ahead - remove the AP STA now */ - mvm_link->ap_sta_id = IWL_MVM_INVALID_STA; + mvm_link->ap_sta_id = IWL_INVALID_STA; } /* @@ -2103,7 +2103,7 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * before the STA is removed. */ if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == sta_id)) { - mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; + mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA; cancel_delayed_work(&mvm->tdls_cs.dwork); } @@ -2170,9 +2170,9 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, u8 type) { if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || - sta->sta_id == IWL_MVM_INVALID_STA) { + sta->sta_id == IWL_INVALID_STA) { sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); - if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA)) return -ENOSPC; } @@ -2188,7 +2188,7 @@ void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) { RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); - sta->sta_id = IWL_MVM_INVALID_STA; + sta->sta_id = IWL_INVALID_STA; } static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 queue, @@ -2306,7 +2306,7 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_INVALID_STA)) return -EINVAL; iwl_mvm_disable_txq(mvm, NULL, mvm->snif_sta.sta_id, @@ -2324,7 +2324,7 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_INVALID_STA)) return -EINVAL; iwl_mvm_disable_txq(mvm, NULL, mvm->aux_sta.sta_id, @@ -2389,7 +2389,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_ADHOC) baddr = vif->bss_conf.bssid; - if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(bsta->sta_id == IWL_INVALID_STA)) return -ENOSPC; ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, @@ -2644,7 +2644,7 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, u32 status; /* This is a valid situation for GTK removal */ - if (sta_id == IWL_MVM_INVALID_STA) + if (sta_id == IWL_INVALID_STA) return 0; key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & @@ -3514,7 +3514,7 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, * station ID, then use AP's station ID. */ if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { + mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) { u8 sta_id = mvmvif->deflink.ap_sta_id; sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id], @@ -3569,7 +3569,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, int api_ver = iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA_KEY, new_api ? 2 : 1); - if (sta_id == IWL_MVM_INVALID_STA) + if (sta_id == IWL_INVALID_STA) return -EINVAL; keyidx = (key->keyidx << STA_KEY_FLG_KEYID_POS) & @@ -3728,7 +3728,7 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, if (remove_key) { /* This is a valid situation for IGTK */ - if (sta_id == IWL_MVM_INVALID_STA) + if (sta_id == IWL_INVALID_STA) return 0; igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID); @@ -3795,7 +3795,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, return sta->addr; if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { + mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) { u8 sta_id = mvmvif->deflink.ap_sta_id; sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], lockdep_is_held(&mvm->mutex)); @@ -3865,7 +3865,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); struct iwl_mvm_sta *mvm_sta; - u8 sta_id = IWL_MVM_INVALID_STA; + u8 sta_id = IWL_INVALID_STA; int ret; static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0}; @@ -3966,7 +3966,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); struct iwl_mvm_sta *mvm_sta; - u8 sta_id = IWL_MVM_INVALID_STA; + u8 sta_id = IWL_INVALID_STA; int ret, i; lockdep_assert_held(&mvm->mutex); @@ -4273,7 +4273,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, return; /* Need to block/unblock also multicast station */ - if (mvmvif->deflink.mcast_sta.sta_id != IWL_MVM_INVALID_STA) + if (mvmvif->deflink.mcast_sta.sta_id != IWL_INVALID_STA) iwl_mvm_int_sta_modify_disable_tx(mvm, mvmvif, &mvmvif->deflink.mcast_sta, disable); @@ -4282,7 +4282,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, * Only unblock the broadcast station (FW blocks it for immediate * quiet, not the driver) */ - if (!disable && mvmvif->deflink.bcast_sta.sta_id != IWL_MVM_INVALID_STA) + if (!disable && mvmvif->deflink.bcast_sta.sta_id != IWL_INVALID_STA) iwl_mvm_int_sta_modify_disable_tx(mvm, mvmvif, &mvmvif->deflink.bcast_sta, disable); @@ -4328,7 +4328,10 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, vif); bool mld = iwl_mvm_has_mld_api(mvm->fw); - u32 type = mld ? STATION_TYPE_PEER : IWL_STA_LINK; + u32 type = IWL_STA_LINK; + + if (mld) + type = STATION_TYPE_PEER; ret = iwl_mvm_allocate_int_sta(mvm, sta, 0, NL80211_IFTYPE_UNSPECIFIED, type); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index 3d25ff5cd7e8..65927ebbabb7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -196,7 +196,7 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, mvm->tdls_cs.peer.sent_timestamp = iwl_mvm_get_systime(mvm); if (state == IWL_MVM_TDLS_SW_IDLE) - mvm->tdls_cs.cur_sta_id = IWL_MVM_INVALID_STA; + mvm->tdls_cs.cur_sta_id = IWL_INVALID_STA; } void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) @@ -250,7 +250,7 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, /* get the existing peer if it's there */ if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE && - mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) { + mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) { struct ieee80211_sta *sta = rcu_dereference_protected( mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id], lockdep_is_held(&mvm->mutex)); @@ -465,7 +465,7 @@ void iwl_mvm_tdls_ch_switch_work(struct work_struct *work) iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); /* station might be gone, in that case do nothing */ - if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) + if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA) return; sta = rcu_dereference_protected( @@ -512,7 +512,7 @@ iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw, sta->addr, chandef->chan->center_freq, chandef->width); /* we only support a single peer for channel switching */ - if (mvm->tdls_cs.peer.sta_id != IWL_MVM_INVALID_STA) { + if (mvm->tdls_cs.peer.sta_id != IWL_INVALID_STA) { IWL_DEBUG_TDLS(mvm, "Existing peer. Can't start switch with %pM\n", sta->addr); @@ -566,7 +566,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr); /* we only support a single peer for channel switching */ - if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) { + if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA) { IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr); goto out; } @@ -587,7 +587,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE) wait_for_phy = true; - mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; + mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA; dev_kfree_skb(mvm->tdls_cs.peer.skb); mvm->tdls_cs.peer.skb = NULL; @@ -630,7 +630,7 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE && params->status != 0 && mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT && - mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) { + mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) { struct ieee80211_sta *cur_sta; /* make sure it's the same peer */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ca026b5256ce..c9867d26361b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1213,7 +1213,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc)) return -1; - if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_INVALID_STA)) return -1; if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->deflink.he_cap.has_he) @@ -1357,7 +1357,7 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb, mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_INVALID_STA)) return -1; memcpy(&info, skb->cb, sizeof(info)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 1d1364d03f02..dd890dcd1505 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -261,7 +261,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq) .data = { lq, }, }; - if (WARN_ON(lq->sta_id == IWL_MVM_INVALID_STA || + if (WARN_ON(lq->sta_id == IWL_INVALID_STA || iwl_mvm_has_tlc_offload(mvm))) return -EINVAL; @@ -679,10 +679,8 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm) mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bss_iface_iterator, &bss_iter_data); - if (bss_iter_data.error) { - IWL_ERR(mvm, "More than one managed interface active!\n"); + if (bss_iter_data.error) return ERR_PTR(-EINVAL); - } return bss_iter_data.vif; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 3b9943eb6934..d19b3bd0866b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1643,6 +1643,8 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, out: if (*status == IWL_D3_STATUS_ALIVE) ret = iwl_pcie_d3_handshake(trans, false); + else + trans->state = IWL_TRANS_NO_FW; return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 9fe050f0ddc1..1ef14340953c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2351,6 +2351,10 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, txq_write_ptr = txq->write_ptr; spin_unlock(&txq->lock); + /* There is nothing to do if we are flushing an empty queue */ + if (is_flush && txq_write_ptr == txq_read_ptr) + goto out; + read_ptr = iwl_txq_get_cmd_index(txq, txq_read_ptr); if (!test_bit(txq_id, trans_pcie->txqs.queue_used)) { diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index d33a994906a7..27f44a9f0bc1 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -624,7 +624,7 @@ static int p54spi_probe(struct spi_device *spi) gpio_direction_input(p54spi_gpio_irq); ret = request_irq(gpio_to_irq(p54spi_gpio_irq), - p54spi_interrupt, 0, "p54spi", + p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi", priv->spi); if (ret < 0) { dev_err(&priv->spi->dev, "request_irq() failed"); @@ -633,8 +633,6 @@ static int p54spi_probe(struct spi_device *spi) irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING); - disable_irq(gpio_to_irq(p54spi_gpio_irq)); - INIT_WORK(&priv->work, p54spi_work); init_completion(&priv->fw_comp); INIT_LIST_HEAD(&priv->tx_pending); diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index 36b234bc5be8..caf8bc231b2e 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -3,7 +3,6 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on USB || MMC || SPI depends on CFG80211 - select LIB80211 select FW_LOADER help A library for Marvell Libertas 8xxx devices. diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index afe9bcd3ad46..2e2c193716d9 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -486,6 +486,7 @@ static int lbs_add_wps_enrollee_tlv(u8 *tlv, const u8 *ie, size_t ie_len) */ static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy, + struct net_device *dev, struct cfg80211_chan_def *chandef) { struct lbs_private *priv = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/marvell/libertas/mesh.h b/drivers/net/wireless/marvell/libertas/mesh.h index 44c4cd0230a8..e37db10e82a9 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.h +++ b/drivers/net/wireless/marvell/libertas/mesh.h @@ -7,7 +7,6 @@ #include <net/iw_handler.h> -#include <net/lib80211.h> #include "host.h" #include "dev.h" diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 1cff001bdc51..b30ed321c625 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -938,8 +938,10 @@ void mwifiex_process_assoc_resp(struct mwifiex_adapter *adapter) assoc_resp.links[0].bss = priv->req_bss; assoc_resp.buf = priv->assoc_rsp_buf; assoc_resp.len = priv->assoc_rsp_size; + wiphy_lock(priv->wdev.wiphy); cfg80211_rx_assoc_resp(priv->netdev, &assoc_resp); + wiphy_unlock(priv->wdev.wiphy); priv->assoc_rsp_size = 0; } } diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index d03129d5d24e..4a96281792cc 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -875,7 +875,7 @@ struct mwifiex_ietypes_chanstats { struct mwifiex_ie_types_wildcard_ssid_params { struct mwifiex_ie_types_header header; u8 max_ssid_length; - u8 ssid[1]; + u8 ssid[]; } __packed; #define TSF_DATA_SIZE 8 diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index 516159b721d3..74747d3a379a 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -8,7 +8,7 @@ #ifndef _MWIFIEX_IOCTL_H_ #define _MWIFIEX_IOCTL_H_ -#include <net/lib80211.h> +#define NUM_WEP_KEYS 4 enum { MWIFIEX_SCAN_TYPE_UNCHANGED = 0, diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index 6d8f1d1d7ca4..5a1a0287c1d5 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -663,7 +663,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, bool enable_data = true; u16 cap_info, status_code, aid; const u8 *ie_ptr; - struct ieee80211_ht_operation *assoc_resp_ht_oper; if (!priv->attempted_bss_desc) { mwifiex_dbg(priv->adapter, ERROR, @@ -779,14 +778,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer, priv->assoc_rsp_size - sizeof(struct ieee_types_assoc_rsp)); - if (ie_ptr) { - assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr - + sizeof(struct ieee_types_header)); - priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param; - priv->ht_param_present = true; - } else { - priv->ht_param_present = false; - } + + priv->ht_param_present = ie_ptr ? true : false; mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 96d1f6039fbc..855019fe5485 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1679,7 +1679,8 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter) } ret = devm_request_irq(dev, adapter->irq_wakeup, - mwifiex_irq_wakeup_handler, IRQF_TRIGGER_LOW, + mwifiex_irq_wakeup_handler, + IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN, "wifi_wake", adapter); if (ret) { dev_err(dev, "Failed to request irq_wakeup %d (%d)\n", @@ -1687,7 +1688,6 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter) goto err_exit; } - disable_irq(adapter->irq_wakeup); if (device_init_wakeup(dev, true)) { dev_err(dev, "fail to init wakeup for mwifiex\n"); goto err_exit; diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 566adce3413c..0674dcf7a537 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -19,7 +19,6 @@ #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <net/sock.h> -#include <net/lib80211.h> #include <linux/vmalloc.h> #include <linux/firmware.h> #include <linux/ctype.h> @@ -574,7 +573,6 @@ struct mwifiex_private { u16 listen_interval; u16 atim_window; u8 adhoc_channel; - u8 adhoc_is_link_sensed; u8 adhoc_state; struct mwifiex_802_11_security sec_info; struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; @@ -683,7 +681,6 @@ struct mwifiex_private { struct mwifiex_ds_mem_rw mem_rw; struct sk_buff_head bypass_txq; struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX]; - u8 assoc_resp_ht_param; bool ht_param_present; }; @@ -802,7 +799,6 @@ struct mwifiex_auto_tdls_peer { unsigned long rssi_jiffies; u8 failure_count; u8 do_discover; - u8 do_setup; }; #define MWIFIEX_TYPE_AGGR_DATA_V2 11 diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index b5f3821a6a8f..400348abeee5 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -177,17 +177,14 @@ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, priv->is_data_rate_auto = true; priv->data_rate = 0; - priv->assoc_resp_ht_param = 0; priv->ht_param_present = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data) mwifiex_hist_data_reset(priv); - if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) priv->adhoc_state = ADHOC_IDLE; - priv->adhoc_is_link_sensed = false; - } /* * Memorize the previous SSID and BSSID so @@ -843,7 +840,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_ADHOC_BCN_LOST: mwifiex_dbg(adapter, EVENT, "event: ADHOC_BCN_LOST\n"); - priv->adhoc_is_link_sensed = false; mwifiex_clean_txrx(priv); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index d3cba6895f8c..e06a0622973e 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -351,8 +351,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, goto done; } - priv->adhoc_is_link_sensed = false; - ret = mwifiex_check_network_compatibility(priv, bss_desc); mwifiex_stop_net_dev_queue(priv->netdev, adapter); diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index 7823e67694e8..0a5f340876c3 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -1306,7 +1306,6 @@ int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb) peer->mac_addr, NL80211_TDLS_SETUP, 0, GFP_ATOMIC); - peer->do_setup = false; priv->check_tdls_tx = false; } else if (peer->failure_count < MWIFIEX_TDLS_MAX_FAIL_COUNT && @@ -1465,7 +1464,6 @@ void mwifiex_check_auto_tdls(struct timer_list *t) tdls_peer->failure_count < MWIFIEX_TDLS_MAX_FAIL_COUNT) { priv->check_tdls_tx = true; - tdls_peer->do_setup = true; mwifiex_dbg(priv->adapter, INFO, "check TDLS with peer=%pM\t" "rssi=%d\n", tdls_peer->mac_addr, diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 42c04bf858da..1f1f6280a0f2 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -494,7 +494,9 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, } } + wiphy_lock(priv->wdev.wiphy); cfg80211_rx_mlme_mgmt(priv->netdev, skb->data, pkt_len); + wiphy_unlock(priv->wdev.wiphy); } if (priv->adapter->host_mlme_enabled && diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c index ec02148a7f1f..08590aa68356 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c @@ -71,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2); struct platform_driver mt76_wmac_driver = { .probe = mt76_wmac_probe, - .remove_new = mt76_wmac_remove, + .remove = mt76_wmac_remove, .driver = { .name = "mt76_wmac", .of_match_table = of_wmac_match, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c index 12e3e4a91d27..06a0f2a141e8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c @@ -63,7 +63,7 @@ struct platform_driver mt7622_wmac_driver = { .of_match_table = mt7622_wmac_of_match, }, .probe = mt7622_wmac_probe, - .remove_new = mt7622_wmac_remove, + .remove = mt7622_wmac_remove, }; MODULE_FIRMWARE(MT7622_FIRMWARE_N9); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index d75e8dea1fbd..c6f498fc81ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1163,9 +1163,10 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta) static void mt7915_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = phy->dev; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; @@ -1709,7 +1710,7 @@ const struct ieee80211_ops mt7915_ops = { .stop_ap = mt7915_stop_ap, .sta_state = mt76_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, - .sta_rc_update = mt7915_sta_rc_update, + .link_sta_rc_update = mt7915_sta_rc_update, .set_key = mt7915_set_key, .ampdu_action = mt7915_ampdu_action, .set_rts_threshold = mt7915_set_rts_threshold, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index 90a6f61d1089..c823a7554a3a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -1303,7 +1303,7 @@ struct platform_driver mt798x_wmac_driver = { .of_match_table = mt798x_wmac_of_match, }, .probe = mt798x_wmac_probe, - .remove_new = mt798x_wmac_remove, + .remove = mt798x_wmac_remove, }; MODULE_FIRMWARE(MT7986_FIRMWARE_WA); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 39f071ece35e..2b34ae5e0cb5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1060,9 +1060,10 @@ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) static void mt7996_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_dev *dev = phy->dev; @@ -1472,7 +1473,7 @@ const struct ieee80211_ops mt7996_ops = { .sta_add = mt7996_sta_add, .sta_remove = mt7996_sta_remove, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, - .sta_rc_update = mt7996_sta_rc_update, + .link_sta_rc_update = mt7996_sta_rc_update, .set_key = mt7996_set_key, .ampdu_action = mt7996_ampdu_action, .set_rts_threshold = mt7996_set_rts_threshold, diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index eb37b228d54e..e96736cc7259 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -231,6 +231,7 @@ struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) } static int set_channel(struct wiphy *wiphy, + struct net_device *dev, struct cfg80211_chan_def *chandef) { struct wilc *wl = wiphy_priv(wiphy); @@ -1424,7 +1425,7 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev, struct wilc_vif *vif = netdev_priv(dev); int ret; - ret = set_channel(wiphy, &settings->chandef); + ret = set_channel(wiphy, dev, &settings->chandef); if (ret != 0) netdev_err(dev, "Error in setting channel\n"); @@ -1757,57 +1758,10 @@ void wlan_deinit_locks(struct wilc *wilc) cleanup_srcu_struct(&wilc->srcu); } -int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, - const struct wilc_hif_func *ops) -{ - struct wilc *wl; - int ret, i; - - wl = wilc_create_wiphy(dev); - if (!wl) - return -EINVAL; - - wlan_init_locks(wl); - - ret = wilc_wlan_cfg_init(wl); - if (ret) - goto free_wl; - - *wilc = wl; - wl->io_type = io_type; - wl->hif_func = ops; - - for (i = 0; i < NQUEUES; i++) - INIT_LIST_HEAD(&wl->txq[i].txq_head.list); - - INIT_LIST_HEAD(&wl->rxq_head.list); - INIT_LIST_HEAD(&wl->vif_list); - - wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, - wiphy_name(wl->wiphy)); - if (!wl->hif_workqueue) { - ret = -ENOMEM; - goto free_cfg; - } - - return 0; - -free_cfg: - wilc_wlan_cfg_deinit(wl); - -free_wl: - wlan_deinit_locks(wl); - wiphy_unregister(wl->wiphy); - wiphy_free(wl->wiphy); - return ret; -} -EXPORT_SYMBOL_GPL(wilc_cfg80211_init); - -struct wilc *wilc_create_wiphy(struct device *dev) +static struct wilc *wilc_create_wiphy(struct device *dev) { struct wiphy *wiphy; struct wilc *wl; - int ret; wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl)); if (!wiphy) @@ -1850,17 +1804,66 @@ struct wilc *wilc_create_wiphy(struct device *dev) BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT); wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - wiphy->features |= NL80211_FEATURE_SAE; set_wiphy_dev(wiphy, dev); wl->wiphy = wiphy; - ret = wiphy_register(wiphy); - if (ret) { - wiphy_free(wiphy); - return NULL; - } return wl; } +int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, + const struct wilc_hif_func *ops) +{ + struct wilc *wl; + int ret, i; + + wl = wilc_create_wiphy(dev); + if (!wl) + return -EINVAL; + + wlan_init_locks(wl); + + ret = wilc_wlan_cfg_init(wl); + if (ret) + goto free_wl; + + *wilc = wl; + wl->io_type = io_type; + wl->hif_func = ops; + + for (i = 0; i < NQUEUES; i++) + INIT_LIST_HEAD(&wl->txq[i].txq_head.list); + + INIT_LIST_HEAD(&wl->rxq_head.list); + INIT_LIST_HEAD(&wl->vif_list); + + wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, + wiphy_name(wl->wiphy)); + if (!wl->hif_workqueue) { + ret = -ENOMEM; + goto free_cfg; + } + + return 0; + +free_cfg: + wilc_wlan_cfg_deinit(wl); + +free_wl: + wlan_deinit_locks(wl); + wiphy_free(wl->wiphy); + return ret; +} +EXPORT_SYMBOL_GPL(wilc_cfg80211_init); + +int wilc_cfg80211_register(struct wilc *wilc) +{ + /* WPA3/SAE supported only on WILC1000 */ + if (is_wilc1000(wilc->chipid)) + wilc->wiphy->features |= NL80211_FEATURE_SAE; + + return wiphy_register(wilc->wiphy); +} +EXPORT_SYMBOL_GPL(wilc_cfg80211_register); + int wilc_init_host_int(struct net_device *net) { int ret; diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.h b/drivers/net/wireless/microchip/wilc1000/cfg80211.h index 8c65951cfaf9..2dc9c1c42d60 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.h +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.h @@ -10,7 +10,7 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, const struct wilc_hif_func *ops); -struct wilc *wilc_create_wiphy(struct device *dev); +int wilc_cfg80211_register(struct wilc *wilc); void wilc_deinit_host_int(struct net_device *net); int wilc_init_host_int(struct net_device *net); void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 9ecf3fb29b55..7e84fc0fd911 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -23,6 +23,12 @@ #define __WILC1000_FW(api) WILC1000_FW_PREFIX #api ".bin" #define WILC1000_FW(api) __WILC1000_FW(api) +#define WILC3000_API_VER 1 + +#define WILC3000_FW_PREFIX "atmel/wilc3000_wifi_firmware-" +#define __WILC3000_FW(api) WILC3000_FW_PREFIX #api ".bin" +#define WILC3000_FW(api) __WILC3000_FW(api) + static irqreturn_t isr_uh_routine(int irq, void *user_data) { struct wilc *wilc = user_data; @@ -195,20 +201,24 @@ static int wilc_wlan_get_firmware(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; - int chip_id; const struct firmware *wilc_fw; + char *firmware; int ret; - chip_id = wilc_get_chipid(wilc, false); + if (is_wilc1000(wilc->chipid)) + firmware = WILC1000_FW(WILC1000_API_VER); + else if (is_wilc3000(wilc->chipid)) + firmware = WILC3000_FW(WILC3000_API_VER); + else + return -EINVAL; - netdev_info(dev, "ChipID [%x] loading firmware [%s]\n", chip_id, - WILC1000_FW(WILC1000_API_VER)); + netdev_info(dev, "WILC%d loading firmware [%s]\n", + is_wilc1000(wilc->chipid) ? 1000 : 3000, + firmware); - ret = request_firmware(&wilc_fw, WILC1000_FW(WILC1000_API_VER), - wilc->dev); + ret = request_firmware(&wilc_fw, firmware, wilc->dev); if (ret != 0) { - netdev_err(dev, "%s - firmware not available\n", - WILC1000_FW(WILC1000_API_VER)); + netdev_err(dev, "%s - firmware not available\n", firmware); return -EINVAL; } wilc->firmware = wilc_fw; @@ -233,7 +243,7 @@ static int wilc_start_firmware(struct net_device *dev) return 0; } -static int wilc1000_firmware_download(struct net_device *dev) +static int wilc_firmware_download(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; @@ -528,7 +538,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif) if (ret) goto fail_irq_enable; - ret = wilc1000_firmware_download(dev); + ret = wilc_firmware_download(dev); if (ret) goto fail_irq_enable; @@ -608,6 +618,9 @@ static int wilc_mac_open(struct net_device *ndev) return ret; } + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype, + vif->idx); + netdev_dbg(ndev, "Mac address: %pM\n", ndev->dev_addr); ret = wilc_set_mac_address(vif, ndev->dev_addr); if (ret) { @@ -618,9 +631,6 @@ static int wilc_mac_open(struct net_device *ndev) return ret; } - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype, - vif->idx); - mgmt_regs.interface_stypes = vif->mgmt_reg_stypes; /* so we detect a change */ vif->mgmt_reg_stypes = 0; @@ -1014,3 +1024,4 @@ EXPORT_SYMBOL_GPL(wilc_netdev_ifc_init); MODULE_DESCRIPTION("Atmel WILC1000 core wireless driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER)); +MODULE_FIRMWARE(WILC3000_FW(WILC3000_API_VER)); diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index b4da05d5a498..5262c8846c13 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -182,6 +182,14 @@ static int wilc_sdio_probe(struct sdio_func *func, wilc_sdio_init(wilc, false); + ret = wilc_get_chipid(wilc); + if (ret) + goto dispose_irq; + + ret = wilc_cfg80211_register(wilc); + if (ret) + goto dispose_irq; + ret = wilc_load_mac_from_nv(wilc); if (ret) { pr_err("Can not retrieve MAC address from chip\n"); @@ -667,7 +675,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume) struct wilc_sdio *sdio_priv = wilc->bus_data; struct sdio_cmd52 cmd; int loop, ret; - u32 chipid; /** * function 0 csa enable @@ -756,18 +763,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume) return ret; } - /** - * make sure can read back chip id correctly - **/ - if (!resume) { - ret = wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid); - if (ret) { - dev_err(&func->dev, "Fail cmd read chip id...\n"); - return ret; - } - dev_err(&func->dev, "chipid (%08x)\n", chipid); - } - sdio_priv->isinit = true; return 0; } @@ -815,13 +810,19 @@ static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status) cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG; } else { cmd.function = 0; - cmd.address = WILC_SDIO_IRQ_FLAG_REG; + cmd.address = is_wilc1000(wilc->chipid) ? + WILC1000_SDIO_IRQ_FLAG_REG : + WILC3000_SDIO_IRQ_FLAG_REG; } cmd.raw = 0; cmd.read_write = 0; cmd.data = 0; wilc_sdio_cmd52(wilc, &cmd); irq_flags = cmd.data; + + if (sdio_priv->irq_gpio) + irq_flags &= is_wilc1000(wilc->chipid) ? 0x1f : 0x0f; + tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data); if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags)) @@ -843,22 +844,56 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val) if (sdio_priv->irq_gpio) reg = val & (BIT(MAX_NUM_INT) - 1); - /* select VMM table 0 */ - if (val & SEL_VMM_TBL0) - reg |= BIT(5); - /* select VMM table 1 */ - if (val & SEL_VMM_TBL1) - reg |= BIT(6); - /* enable VMM */ - if (val & EN_VMM) - reg |= BIT(7); + if (is_wilc1000(wilc->chipid)) { + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(5); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(6); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(7); + } else { + if (sdio_priv->irq_gpio && reg) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC3000_SDIO_IRQ_FLAG_REG; + cmd.data = reg; + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set 0xfe data (%d) ...\n", + __LINE__); + return ret; + } + } + + reg = 0; + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(0); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(1); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(2); + } + if (reg) { struct sdio_cmd52 cmd; cmd.read_write = 1; cmd.function = 0; cmd.raw = 0; - cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG; + cmd.address = is_wilc1000(wilc->chipid) ? + WILC1000_SDIO_IRQ_CLEAR_FLAG_REG : + WILC3000_SDIO_VMM_TBL_CTRL_REG; cmd.data = reg; ret = wilc_sdio_cmd52(wilc, &cmd); @@ -979,17 +1014,15 @@ static int wilc_sdio_suspend(struct device *dev) if (!IS_ERR(wilc->rtc_clk)) clk_disable_unprepare(wilc->rtc_clk); - host_sleep_notify(wilc); - - wilc_sdio_disable_interrupt(wilc); - - ret = wilc_sdio_reset(wilc); + ret = host_sleep_notify(wilc); if (ret) { - dev_err(&func->dev, "Fail reset sdio\n"); + clk_prepare_enable(wilc->rtc_clk); return ret; } - return 0; + wilc_sdio_disable_interrupt(wilc); + + return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); } static int wilc_sdio_resume(struct device *dev) @@ -1008,9 +1041,7 @@ static int wilc_sdio_resume(struct device *dev) wilc_sdio_init(wilc, true); wilc_sdio_enable_interrupt(wilc); - host_wakeup_notify(wilc); - - return 0; + return host_wakeup_notify(wilc); } static const struct of_device_id wilc_of_match[] = { diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 05b577b1068e..ce2a9cdd6aa7 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -245,7 +245,11 @@ static int wilc_bus_probe(struct spi_device *spi) if (ret) goto power_down; - ret = wilc_validate_chipid(wilc); + ret = wilc_get_chipid(wilc); + if (ret) + goto power_down; + + ret = wilc_cfg80211_register(wilc); if (ret) goto power_down; @@ -1229,7 +1233,7 @@ static int wilc_validate_chipid(struct wilc *wilc) dev_err(&spi->dev, "Fail cmd read chip id...\n"); return ret; } - if (!is_wilc1000(chipid)) { + if (!is_wilc1000(chipid) && !is_wilc3000(chipid)) { dev_err(&spi->dev, "Unknown chip id 0x%x\n", chipid); return -ENODEV; } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 533939e71534..9d80adc45d6b 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -12,20 +12,6 @@ #define WAKE_UP_TRIAL_RETRY 10000 -static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire) -{ - mutex_lock(&wilc->hif_cs); - if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) - chip_wakeup(wilc); -} - -static inline void release_bus(struct wilc *wilc, enum bus_release release) -{ - if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode) - chip_allow_sleep(wilc); - mutex_unlock(&wilc->hif_cs); -} - static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num, struct txq_entry_t *tqe) { @@ -555,7 +541,7 @@ static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc) return rqe; } -void chip_allow_sleep(struct wilc *wilc) +static int chip_allow_sleep_wilc1000(struct wilc *wilc) { u32 reg = 0; const struct wilc_hif_func *hif_func = wilc->hif_func; @@ -584,7 +570,7 @@ void chip_allow_sleep(struct wilc *wilc) while (--trials) { ret = hif_func->hif_read_reg(wilc, to_host_from_fw_reg, ®); if (ret) - return; + return ret; if ((reg & to_host_from_fw_bit) == 0) break; } @@ -594,28 +580,62 @@ void chip_allow_sleep(struct wilc *wilc) /* Clear bit 1 */ ret = hif_func->hif_read_reg(wilc, wakeup_reg, ®); if (ret) - return; + return ret; if (reg & wakeup_bit) { reg &= ~wakeup_bit; ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg); if (ret) - return; + return ret; } ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, ®); if (ret) - return; + return ret; if (reg & from_host_to_fw_bit) { reg &= ~from_host_to_fw_bit; ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, reg); if (ret) - return; + return ret; + } + return 0; +} + +static int chip_allow_sleep_wilc3000(struct wilc *wilc) +{ + u32 reg = 0; + int ret; + const struct wilc_hif_func *hif_func = wilc->hif_func; + + if (wilc->io_type == WILC_HIF_SDIO) { + ret = hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, ®); + if (ret) + return ret; + ret = hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, + reg & ~WILC_SDIO_WAKEUP_BIT); + if (ret) + return ret; + } else { + ret = hif_func->hif_read_reg(wilc, WILC_SPI_WAKEUP_REG, ®); + if (ret) + return ret; + ret = hif_func->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG, + reg & ~WILC_SPI_WAKEUP_BIT); + if (ret) + return ret; } + return 0; +} + +static int chip_allow_sleep(struct wilc *wilc) +{ + if (is_wilc1000(wilc->chipid)) + return chip_allow_sleep_wilc1000(wilc); + else + return chip_allow_sleep_wilc3000(wilc); } -EXPORT_SYMBOL_GPL(chip_allow_sleep); -void chip_wakeup(struct wilc *wilc) +static int chip_wakeup_wilc1000(struct wilc *wilc) { u32 ret = 0; u32 clk_status_val = 0, trials = 0; @@ -627,15 +647,15 @@ void chip_wakeup(struct wilc *wilc) if (wilc->io_type == WILC_HIF_SDIO) { wakeup_reg = WILC_SDIO_WAKEUP_REG; wakeup_bit = WILC_SDIO_WAKEUP_BIT; - clk_status_reg = WILC_SDIO_CLK_STATUS_REG; - clk_status_bit = WILC_SDIO_CLK_STATUS_BIT; + clk_status_reg = WILC1000_SDIO_CLK_STATUS_REG; + clk_status_bit = WILC1000_SDIO_CLK_STATUS_BIT; from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG; from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT; } else { wakeup_reg = WILC_SPI_WAKEUP_REG; wakeup_bit = WILC_SPI_WAKEUP_BIT; - clk_status_reg = WILC_SPI_CLK_STATUS_REG; - clk_status_bit = WILC_SPI_CLK_STATUS_BIT; + clk_status_reg = WILC1000_SPI_CLK_STATUS_REG; + clk_status_bit = WILC1000_SPI_CLK_STATUS_BIT; from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG; from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT; } @@ -644,20 +664,20 @@ void chip_wakeup(struct wilc *wilc) ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, from_host_to_fw_bit); if (ret) - return; + return ret; /* Set wake-up bit */ ret = hif_func->hif_write_reg(wilc, wakeup_reg, wakeup_bit); if (ret) - return; + return ret; while (trials < WAKE_UP_TRIAL_RETRY) { ret = hif_func->hif_read_reg(wilc, clk_status_reg, &clk_status_val); if (ret) { pr_err("Bus error %d %x\n", ret, clk_status_val); - return; + return ret; } if (clk_status_val & clk_status_bit) break; @@ -666,29 +686,135 @@ void chip_wakeup(struct wilc *wilc) } if (trials >= WAKE_UP_TRIAL_RETRY) { pr_err("Failed to wake-up the chip\n"); - return; + return -ETIMEDOUT; } /* Sometimes spi fail to read clock regs after reading * writing clockless registers */ if (wilc->io_type == WILC_HIF_SPI) wilc->hif_func->hif_reset(wilc); + + return 0; } -EXPORT_SYMBOL_GPL(chip_wakeup); -void host_wakeup_notify(struct wilc *wilc) +static int chip_wakeup_wilc3000(struct wilc *wilc) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); - wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + u32 wakeup_reg_val, clk_status_reg_val, trials = 0; + u32 wakeup_reg, wakeup_bit; + u32 clk_status_reg, clk_status_bit; + int wake_seq_trials = 5; + const struct wilc_hif_func *hif_func = wilc->hif_func; + + if (wilc->io_type == WILC_HIF_SDIO) { + wakeup_reg = WILC_SDIO_WAKEUP_REG; + wakeup_bit = WILC_SDIO_WAKEUP_BIT; + clk_status_reg = WILC3000_SDIO_CLK_STATUS_REG; + clk_status_bit = WILC3000_SDIO_CLK_STATUS_BIT; + } else { + wakeup_reg = WILC_SPI_WAKEUP_REG; + wakeup_bit = WILC_SPI_WAKEUP_BIT; + clk_status_reg = WILC3000_SPI_CLK_STATUS_REG; + clk_status_bit = WILC3000_SPI_CLK_STATUS_BIT; + } + + hif_func->hif_read_reg(wilc, wakeup_reg, &wakeup_reg_val); + do { + hif_func->hif_write_reg(wilc, wakeup_reg, wakeup_reg_val | + wakeup_bit); + /* Check the clock status */ + hif_func->hif_read_reg(wilc, clk_status_reg, + &clk_status_reg_val); + + /* In case of clocks off, wait 1ms, and check it again. + * if still off, wait for another 1ms, for a total wait of 3ms. + * If still off, redo the wake up sequence + */ + while ((clk_status_reg_val & clk_status_bit) == 0 && + (++trials % 4) != 0) { + /* Wait for the chip to stabilize*/ + usleep_range(1000, 1100); + + /* Make sure chip is awake. This is an extra step that + * can be removed later to avoid the bus access + * overhead + */ + hif_func->hif_read_reg(wilc, clk_status_reg, + &clk_status_reg_val); + } + /* in case of failure, Reset the wakeup bit to introduce a new + * edge on the next loop + */ + if ((clk_status_reg_val & clk_status_bit) == 0) { + hif_func->hif_write_reg(wilc, wakeup_reg, + wakeup_reg_val & (~wakeup_bit)); + /* added wait before wakeup sequence retry */ + usleep_range(200, 300); + } + } while ((clk_status_reg_val & clk_status_bit) == 0 && wake_seq_trials-- > 0); + if (!wake_seq_trials) + dev_err(wilc->dev, "clocks still OFF. Wake up failed\n"); + + return 0; +} + +static int chip_wakeup(struct wilc *wilc) +{ + if (is_wilc1000(wilc->chipid)) + return chip_wakeup_wilc1000(wilc); + else + return chip_wakeup_wilc3000(wilc); +} + +static inline int acquire_bus(struct wilc *wilc, enum bus_acquire acquire) +{ + int ret = 0; + + mutex_lock(&wilc->hif_cs); + if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) { + ret = chip_wakeup(wilc); + if (ret) + mutex_unlock(&wilc->hif_cs); + } + + return ret; +} + +static inline int release_bus(struct wilc *wilc, enum bus_release release) +{ + int ret = 0; + + if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode) + ret = chip_allow_sleep(wilc); + mutex_unlock(&wilc->hif_cs); + + return ret; +} + +int host_wakeup_notify(struct wilc *wilc) +{ + int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + + if (ret) + return ret; + + wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ? + WILC1000_CORTUS_INTERRUPT_2 : + WILC3000_CORTUS_INTERRUPT_2, 1); + return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); } EXPORT_SYMBOL_GPL(host_wakeup_notify); -void host_sleep_notify(struct wilc *wilc) +int host_sleep_notify(struct wilc *wilc) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); - wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + + if (ret) + return ret; + + wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ? + WILC1000_CORTUS_INTERRUPT_1 : + WILC3000_CORTUS_INTERRUPT_1, 1); + return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); } EXPORT_SYMBOL_GPL(host_sleep_notify); @@ -715,6 +841,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) int srcu_idx; u8 *txb = wilc->tx_buffer; struct wilc_vif *vif; + int rv; if (wilc->quit) goto out_update_cnt; @@ -785,7 +912,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) goto out_unlock; vmm_table[i] = 0x0; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto out_unlock; + counter = 0; func = wilc->hif_func; do { @@ -818,19 +948,45 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) if (ret) break; - ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); - if (ret) - break; + if (is_wilc1000(wilc->chipid)) { + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); + if (ret) + break; - do { - ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + do { + ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + if (ret) + break; + if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) { + entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + break; + } + } while (--timeout); + } else { + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0); if (ret) break; - if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) { - entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + + /* interrupt firmware */ + ret = func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, 1); + if (ret) break; - } - } while (--timeout); + + do { + ret = func->hif_read_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, ®); + if (ret) + break; + if (reg == 0) { + /* Get the entries */ + ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + if (ret) + break; + + entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + break; + } + } while (--timeout); + } if (timeout <= 0) { ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0); break; @@ -860,7 +1016,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) goto out_release_bus; } - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (ret) + goto out_unlock; offset = 0; i = 0; @@ -922,7 +1080,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) for (i = 0; i < NQUEUES; i++) wilc->txq[i].fw.count += ac_pkt_num_to_chip[i]; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto out_unlock; ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM); if (ret) @@ -931,7 +1091,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) ret = func->hif_block_tx_ext(wilc, 0, txb, offset); out_release_bus: - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (!ret && rv) + ret = rv; out_unlock: mutex_unlock(&wilc->txq_add_to_head_cs); @@ -1060,8 +1222,14 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) void wilc_handle_isr(struct wilc *wilc) { u32 int_status; + int ret; + + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) { + dev_err_ratelimited(wilc->dev, "Cannot acquire bus\n"); + return; + } - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); wilc->hif_func->hif_read_int(wilc, &int_status); if (int_status & DATA_INT_EXT) @@ -1070,7 +1238,9 @@ void wilc_handle_isr(struct wilc *wilc) if (!(int_status & (ALL_INT_EXT))) wilc_unknown_isr_ext(wilc); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (ret) + dev_err_ratelimited(wilc->dev, "Cannot release bus\n"); } EXPORT_SYMBOL_GPL(wilc_handle_isr); @@ -1082,6 +1252,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u8 *dma_buffer; int ret = 0; u32 reg = 0; + int rv; blksz = BIT(12); @@ -1092,7 +1263,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, offset = 0; pr_debug("%s: Downloading firmware size = %d\n", __func__, buffer_size); - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); reg &= ~BIT(10); @@ -1101,11 +1274,17 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, if (reg & BIT(10)) pr_err("%s: Failed to reset\n", __func__); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + ret = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (ret) + goto fail; + do { addr = get_unaligned_le32(&buffer[offset]); size = get_unaligned_le32(&buffer[offset + 4]); - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto fail; + offset += 8; while (((int)size) && (offset < buffer_size)) { if (size <= blksz) @@ -1123,7 +1302,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, offset += size2; size -= size2; } - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (!ret && rv) + ret = rv; if (ret) { pr_err("%s Bus error\n", __func__); @@ -1142,7 +1323,7 @@ fail: int wilc_wlan_start(struct wilc *wilc) { u32 reg = 0; - int ret; + int ret, rv; u32 chipid; if (wilc->io_type == WILC_HIF_SDIO) { @@ -1151,7 +1332,10 @@ int wilc_wlan_start(struct wilc *wilc) } else if (wilc->io_type == WILC_HIF_SPI) { reg = 1; } - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + if (ret) + return ret; + ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg); if (ret) goto release; @@ -1160,6 +1344,9 @@ int wilc_wlan_start(struct wilc *wilc) if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num) reg |= WILC_HAVE_SDIO_IRQ_GPIO; + if (is_wilc3000(wilc->chipid)) + reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC; + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg); if (ret) goto release; @@ -1182,16 +1369,18 @@ int wilc_wlan_start(struct wilc *wilc) wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); release: - release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + return ret ? ret : rv; } int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) { u32 reg = 0; - int ret; + int ret, rv; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, ®); if (ret) @@ -1227,9 +1416,9 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) ret = 0; release: /* host comm is disabled - we can't issue sleep command anymore: */ - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; + return ret ? ret : rv; } void wilc_wlan_cleanup(struct net_device *dev) @@ -1402,19 +1591,56 @@ int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, return ret; } +int wilc_get_chipid(struct wilc *wilc) +{ + u32 chipid = 0; + u32 rfrevid = 0; + + if (wilc->chipid == 0) { + wilc->hif_func->hif_read_reg(wilc, WILC3000_CHIP_ID, &chipid); + if (!is_wilc3000(chipid)) { + wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); + wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID, + &rfrevid); + + if (!is_wilc1000(chipid)) { + wilc->chipid = 0; + return -EINVAL; + } + if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ + if (rfrevid != 0x1) + chipid = WILC_1000_BASE_ID_2A_REV1; + } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ + if (rfrevid == 0x4) + chipid = WILC_1000_BASE_ID_2B_REV1; + else if (rfrevid != 0x3) + chipid = WILC_1000_BASE_ID_2B_REV2; + } + } + + wilc->chipid = chipid; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wilc_get_chipid); + static int init_chip(struct net_device *dev) { - u32 chipid; u32 reg; - int ret = 0; + int ret, rv; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; - chipid = wilc_get_chipid(wilc, true); + ret = wilc_get_chipid(wilc); + if (ret) + goto release; - if ((chipid & 0xfff) != 0xa0) { + if ((wilc->chipid & 0xfff) != 0xa0) { ret = wilc->hif_func->hif_read_reg(wilc, WILC_CORTUS_RESET_MUX_SEL, ®); @@ -1439,46 +1665,35 @@ static int init_chip(struct net_device *dev) } } -release: - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); - - return ret; -} - -u32 wilc_get_chipid(struct wilc *wilc, bool update) -{ - u32 chipid = 0; - u32 rfrevid = 0; - - if (wilc->chipid == 0 || update) { - wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); - wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID, - &rfrevid); - if (!is_wilc1000(chipid)) { - wilc->chipid = 0; - return wilc->chipid; - } - if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ - if (rfrevid != 0x1) - chipid = WILC_1000_BASE_ID_2A_REV1; - } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ - if (rfrevid == 0x4) - chipid = WILC_1000_BASE_ID_2B_REV1; - else if (rfrevid != 0x3) - chipid = WILC_1000_BASE_ID_2B_REV2; + if (is_wilc3000(wilc->chipid)) { + ret = wilc->hif_func->hif_read_reg(wilc, WILC3000_BOOTROM_STATUS, ®); + if (ret) { + netdev_err(dev, "failed to read WILC3000 BootROM status register\n"); + goto release; } - wilc->chipid = chipid; + ret = wilc->hif_func->hif_write_reg(wilc, WILC3000_CORTUS_BOOT_REGISTER_2, + WILC_CORTUS_BOOT_FROM_IRAM); + if (ret) { + netdev_err(dev, "failed to write WILC3000 Boot register\n"); + goto release; + } } - return wilc->chipid; + +release: + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + + return ret ? ret : rv; } int wilc_load_mac_from_nv(struct wilc *wl) { - int ret = -EINVAL; + int ret, rv; unsigned int i; - acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; for (i = 0; i < WILC_NVMEM_MAX_NUM_BANK; i++) { int bank_offset = get_bank_offset_from_bank_index(i); @@ -1517,14 +1732,14 @@ int wilc_load_mac_from_nv(struct wilc *wl) break; } - release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP); - return ret; + rv = release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP); + return ret ? ret : rv; } EXPORT_SYMBOL_GPL(wilc_load_mac_from_nv); int wilc_wlan_init(struct net_device *dev) { - int ret = 0; + int ret = 0, rv; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc; @@ -1533,11 +1748,26 @@ int wilc_wlan_init(struct net_device *dev) wilc->quit = 0; if (!wilc->hif_func->hif_is_init(wilc)) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + if (ret) + return ret; + ret = wilc->hif_func->hif_init(wilc, false); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (!ret) + ret = wilc_get_chipid(wilc); + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (!ret && rv) + ret = rv; if (ret) goto fail; + + if (!is_wilc1000(wilc->chipid) && !is_wilc3000(wilc->chipid)) { + netdev_err(dev, "Unsupported chipid: %x\n", wilc->chipid); + ret = -EINVAL; + goto fail; + } + + netdev_dbg(dev, "chipid (%08x)\n", wilc->chipid); } if (!wilc->vmm_table) diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h index dd2fb3c2f06a..b9e7f9222ead 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -96,8 +96,14 @@ #define WILC_SPI_WAKEUP_REG 0x1 #define WILC_SPI_WAKEUP_BIT BIT(1) -#define WILC_SPI_CLK_STATUS_REG 0x0f -#define WILC_SPI_CLK_STATUS_BIT BIT(2) +/* WILC1000 specific */ +#define WILC1000_SPI_CLK_STATUS_REG 0x0f +#define WILC1000_SPI_CLK_STATUS_BIT BIT(2) + +/* WILC3000 specific */ +#define WILC3000_SPI_CLK_STATUS_REG 0x13 +#define WILC3000_SPI_CLK_STATUS_BIT BIT(2) + #define WILC_SPI_HOST_TO_FW_REG 0x0b #define WILC_SPI_HOST_TO_FW_BIT BIT(0) @@ -123,14 +129,24 @@ #define WILC_SDIO_WAKEUP_REG 0xf0 #define WILC_SDIO_WAKEUP_BIT BIT(0) -#define WILC_SDIO_CLK_STATUS_REG 0xf1 -#define WILC_SDIO_CLK_STATUS_BIT BIT(0) +/* WILC1000 */ +#define WILC1000_SDIO_CLK_STATUS_REG 0xf1 +#define WILC1000_SDIO_CLK_STATUS_BIT BIT(0) + +#define WILC1000_SDIO_IRQ_FLAG_REG 0xf7 +#define WILC1000_SDIO_IRQ_CLEAR_FLAG_REG 0xf8 + +/* WILC3000 specific */ +#define WILC3000_SDIO_CLK_STATUS_REG 0xf0 /* clk & wakeup are on same reg */ +#define WILC3000_SDIO_CLK_STATUS_BIT BIT(4) + +#define WILC3000_SDIO_VMM_TBL_CTRL_REG 0xf1 +#define WILC3000_SDIO_IRQ_FLAG_REG 0xfe +/* Common vendor specific CCCR register */ #define WILC_SDIO_INTERRUPT_DATA_SZ_REG 0xf2 /* Read size (2 bytes) */ #define WILC_SDIO_VMM_TBL_CTRL_REG 0xf6 -#define WILC_SDIO_IRQ_FLAG_REG 0xf7 -#define WILC_SDIO_IRQ_CLEAR_FLAG_REG 0xf8 #define WILC_SDIO_HOST_TO_FW_REG 0xfa #define WILC_SDIO_HOST_TO_FW_BIT BIT(0) @@ -172,8 +188,11 @@ #define WILC_HAVE_USE_IRQ_AS_HOST_WAKE BIT(8) #define WILC_CORTUS_INTERRUPT_BASE 0x10A8 -#define WILC_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4) -#define WILC_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8) +#define WILC1000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4) +#define WILC3000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x14) + +#define WILC1000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8) +#define WILC3000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x18) /* tx control register 1 to 4 for RX */ #define WILC_REG_4_TO_1_RX 0x1e1c @@ -183,6 +202,9 @@ #define WILC_CORTUS_RESET_MUX_SEL 0x1118 #define WILC_CORTUS_BOOT_REGISTER 0xc0000 +#define WILC3000_BOOTROM_STATUS 0x207ac +#define WILC3000_CORTUS_BOOT_REGISTER_2 0x4f0000 +#define WILC3000_CHIP_ID 0x3b0000 #define WILC_CORTUS_BOOT_FROM_IRAM 0x71 @@ -195,6 +217,8 @@ #define WILC_1000_BASE_ID_2B_REV1 (WILC_1000_BASE_ID_2B + 1) #define WILC_1000_BASE_ID_2B_REV2 (WILC_1000_BASE_ID_2B + 2) +#define WILC_3000_BASE_ID 0x300000 + #define WILC_CHIP_REV_FIELD GENMASK(11, 0) /******************************************** @@ -413,6 +437,11 @@ static inline bool is_wilc1000(u32 id) return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID; } +static inline bool is_wilc3000(u32 id) +{ + return (id & (~WILC_CHIP_REV_FIELD)) == WILC_3000_BASE_ID; +} + int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u32 buffer_size); int wilc_wlan_start(struct wilc *wilc); @@ -436,13 +465,11 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev); void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size); bool wilc_wfi_mgmt_frame_rx(struct wilc_vif *vif, u8 *buff, u32 size); -void host_wakeup_notify(struct wilc *wilc); -void host_sleep_notify(struct wilc *wilc); -void chip_allow_sleep(struct wilc *wilc); -void chip_wakeup(struct wilc *wilc); +int host_wakeup_notify(struct wilc *wilc); +int host_sleep_notify(struct wilc *wilc); int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, u32 count); int wilc_wlan_init(struct net_device *dev); -u32 wilc_get_chipid(struct wilc *wilc, bool update); +int wilc_get_chipid(struct wilc *wilc); int wilc_load_mac_from_nv(struct wilc *wilc); #endif diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 9540ad6196d7..956c5763662f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -257,7 +257,7 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, cmd->beacon_interval = cpu_to_le16(s->beacon_interval); cmd->hidden_ssid = qlink_hidden_ssid_nl2q(s->hidden_ssid); cmd->inactivity_timeout = cpu_to_le16(s->inactivity_timeout); - cmd->smps_mode = s->smps_mode; + cmd->smps_mode = NL80211_SMPS_OFF; cmd->p2p_ctwindow = s->p2p_ctwindow; cmd->p2p_opp_ps = s->p2p_opp_ps; cmd->pbss = s->pbss; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index b204a24074ab..b375a4751580 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -13,7 +13,6 @@ #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <net/sock.h> -#include <net/lib80211.h> #include <net/cfg80211.h> #include <linux/vmalloc.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 3bb81bcff0ac..60c2a12e9d5e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -3607,7 +3607,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 52, 0x0C); rt2800_rfcsr_write(rt2x00dev, 54, 0xF8); if (rf->channel <= 50) { - rt2800_rfcsr_write(rt2x00dev, 55, 0x06), + rt2800_rfcsr_write(rt2x00dev, 55, 0x06); rt2800_rfcsr_write(rt2x00dev, 56, 0xD3); } else if (rf->channel >= 52) { rt2800_rfcsr_write(rt2x00dev, 55, 0x04); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index 7891c988dd5f..f95898f68d68 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -5058,10 +5058,12 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (bss_conf->enable_beacon) + if (bss_conf->enable_beacon) { rtl8xxxu_start_tx_beacon(priv); - else + schedule_delayed_work(&priv->update_beacon_work, 0); + } else { rtl8xxxu_stop_tx_beacon(priv); + } } if (changed & BSS_CHANGED_BEACON) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 039bbedb41c2..379193b24428 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -3409,17 +3409,6 @@ void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) } } -void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) -{ - struct rtl_priv *rtlpriv = btcoexist->adapter; - - rtl_dbg(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], *****************Coex DM Reset****************\n"); - - halbtc8723b1ant_init_hw_config(btcoexist, false, false); - halbtc8723b1ant_init_coex_dm(btcoexist); -} - void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 9d41e11388ad..a4506d838dc7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -197,7 +197,6 @@ void ex_btc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type); void ex_btc8723b1ant_halt_notify(struct btc_coexist *btcoexist); void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); -void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist); void ex_btc8723b1ant_display_coex_info(struct btc_coexist *btcoexist, struct seq_file *m); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index be4c0e60d44d..478cca33e5e3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -1708,19 +1708,6 @@ void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, halbtc_normal_low_power(btcoexist); } -void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - - if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { - } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { - if (btcoexist->board_info.btdm_ant_num == 1) - ex_btc8723b1ant_rf_status_notify(btcoexist, type); - } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { - } -} - void exhalbtc_halt_notify(struct btc_coexist *btcoexist) { if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -1768,31 +1755,6 @@ void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) } } -void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist) -{ - struct rtl_priv *rtlpriv = btcoexist->adapter; - - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - btcoexist->statistics.cnt_coex_dm_switch++; - - halbtc_leave_low_power(btcoexist); - - if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { - if (btcoexist->board_info.btdm_ant_num == 1) { - btcoexist->stop_coex_dm = true; - ex_btc8723b1ant_coex_dm_reset(btcoexist); - exhalbtc_set_ant_num(rtlpriv, - BT_COEX_ANT_TYPE_DETECTED, 2); - ex_btc8723b2ant_init_hwconfig(btcoexist); - ex_btc8723b2ant_init_coex_dm(btcoexist); - btcoexist->stop_coex_dm = false; - } - } - - halbtc_normal_low_power(btcoexist); -} - void exhalbtc_periodical(struct btc_coexist *btcoexist) { if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -1820,29 +1782,6 @@ void exhalbtc_periodical(struct btc_coexist *btcoexist) halbtc_normal_low_power(btcoexist); } -void exhalbtc_dbg_control(struct btc_coexist *btcoexist, - u8 code, u8 len, u8 *data) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - btcoexist->statistics.cnt_dbg_ctrl++; - - halbtc_leave_low_power(btcoexist); - - halbtc_normal_low_power(btcoexist); -} - -void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq, - u32 offset, u32 span, u32 seconds) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; -} - -void exhalbtc_stack_update_profile_info(void) -{ -} - void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi) { if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -1851,24 +1790,6 @@ void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi) btcoexist->stack_info.min_bt_rssi = bt_rssi; } -void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - - btcoexist->stack_info.hci_version = hci_version; -} - -void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist, - u16 bt_hci_version, u16 bt_patch_version) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - - btcoexist->bt_info.bt_real_fw_ver = bt_patch_version; - btcoexist->bt_info.bt_hci_ver = bt_hci_version; -} - void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type) { switch (chip_type) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index a96a995dd850..d8d88a989806 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -763,19 +763,9 @@ void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type); void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, u8 length); -void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type); void exhalbtc_halt_notify(struct btc_coexist *btcoexist); void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); -void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist); void exhalbtc_periodical(struct btc_coexist *btcoexist); -void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, - u8 *data); -void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq, - u32 offset, u32 span, u32 seconds); -void exhalbtc_stack_update_profile_info(void); -void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version); -void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist, - u16 bt_hci_version, u16 bt_patch_version); void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi); void exhalbtc_set_bt_exist(struct btc_coexist *btcoexist, bool bt_exist); void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type); diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index 82cf5fb5175f..6518e77b89f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -162,10 +162,19 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 max_attempts = 10000; u32 value32; u8 readbyte; u16 retry; + /* + * In case of USB devices, transfer speeds are limited, hence + * efuse I/O reads could be (way) slower. So, decrease (a lot) + * the read attempts in case of failures. + */ + if (rtlpriv->rtlhal.interface == INTF_USB) + max_attempts = 10; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (_offset & 0xff)); readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2); @@ -178,7 +187,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) retry = 0; value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); - while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { + while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < max_attempts)) { value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); retry++; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 1b144fbd4d26..048744166a92 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -350,7 +350,8 @@ MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 8723E 802.11n PCI wireless"); -MODULE_FIRMWARE("rtlwifi/rtl8723efw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723fw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723fw_B.bin"); module_param_named(swenc, rtl8723e_mod_params.sw_crypto, bool, 0444); module_param_named(debug_level, rtl8723e_mod_params.debug_level, int, 0644); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 0e77de1baaf8..bcfc53af4c1a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -2040,31 +2040,33 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - int params[] = {RTL8723BE_EEPROM_ID, EEPROM_VID, EEPROM_DID, - EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, - EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, - COUNTRY_CODE_WORLD_WIDE_13}; + static const int params[] = { + RTL8723BE_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13 + }; u8 *hwinfo; int i; bool is_toshiba_smid1 = false; bool is_toshiba_smid2 = false; bool is_samsung_smid = false; bool is_lenovo_smid = false; - u16 toshiba_smid1[] = { + static const u16 toshiba_smid1[] = { 0x6151, 0x6152, 0x6154, 0x6155, 0x6177, 0x6178, 0x6179, 0x6180, 0x7151, 0x7152, 0x7154, 0x7155, 0x7177, 0x7178, 0x7179, 0x7180, 0x8151, 0x8152, 0x8154, 0x8155, 0x8181, 0x8182, 0x8184, 0x8185, 0x9151, 0x9152, 0x9154, 0x9155, 0x9181, 0x9182, 0x9184, 0x9185 }; - u16 toshiba_smid2[] = { + static const u16 toshiba_smid2[] = { 0x6181, 0x6184, 0x6185, 0x7181, 0x7182, 0x7184, 0x7185, 0x8181, 0x8182, 0x8184, 0x8185, 0x9181, 0x9182, 0x9184, 0x9185 }; - u16 samsung_smid[] = { + static const u16 samsung_smid[] = { 0x6191, 0x6192, 0x6193, 0x7191, 0x7192, 0x7193, 0x8191, 0x8192, 0x8193, 0x9191, 0x9192, 0x9193 }; - u16 lenovo_smid[] = { + static const u16 lenovo_smid[] = { 0x8195, 0x9195, 0x7194, 0x8200, 0x8201, 0x8202, 0x9199, 0x9200 }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index a65503c5ae5a..b5266e560416 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -407,6 +407,9 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 8821ae 802.11ac PCI wireless"); MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin"); MODULE_FIRMWARE("rtlwifi/rtl8821aefw_29.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8821aefw_wowlan.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8812aefw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8812aefw_wowlan.bin"); module_param_named(swenc, rtl8821ae_mod_params.sw_crypto, bool, 0444); module_param_named(debug_level, rtl8821ae_mod_params.debug_level, int, 0644); diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig index 02b0d698413b..733b3e58da51 100644 --- a/drivers/net/wireless/realtek/rtw88/Kconfig +++ b/drivers/net/wireless/realtek/rtw88/Kconfig @@ -43,6 +43,17 @@ config RTW88_8723D config RTW88_8821C tristate +config RTW88_88XXA + tristate + +config RTW88_8821A + tristate + select RTW88_88XXA + +config RTW88_8812A + tristate + select RTW88_88XXA + config RTW88_8822BE tristate "Realtek 8822BE PCI wireless network adapter" depends on PCI @@ -189,6 +200,28 @@ config RTW88_8821CU 802.11ac USB wireless network adapter +config RTW88_8821AU + tristate "Realtek 8821AU/8811AU USB wireless network adapter" + depends on USB + select RTW88_CORE + select RTW88_USB + select RTW88_8821A + help + Select this option will enable support for 8821AU and 8811AU chipset + + 802.11ac USB wireless network adapter + +config RTW88_8812AU + tristate "Realtek 8812AU USB wireless network adapter" + depends on USB + select RTW88_CORE + select RTW88_USB + select RTW88_8812A + help + Select this option will enable support for 8812AU chipset + + 802.11ac USB wireless network adapter + config RTW88_DEBUG bool "Realtek rtw88 debug support" depends on RTW88_CORE diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 8f47359b4380..f0b49f5a8a5a 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -77,6 +77,21 @@ rtw88_8821cs-objs := rtw8821cs.o obj-$(CONFIG_RTW88_8821CU) += rtw88_8821cu.o rtw88_8821cu-objs := rtw8821cu.o +obj-$(CONFIG_RTW88_88XXA) += rtw88_88xxa.o +rtw88_88xxa-objs := rtw88xxa.o + +obj-$(CONFIG_RTW88_8821A) += rtw88_8821a.o +rtw88_8821a-objs := rtw8821a.o rtw8821a_table.o + +obj-$(CONFIG_RTW88_8812A) += rtw88_8812a.o +rtw88_8812a-objs := rtw8812a.o rtw8812a_table.o + +obj-$(CONFIG_RTW88_8821AU) += rtw88_8821au.o +rtw88_8821au-objs := rtw8821au.o + +obj-$(CONFIG_RTW88_8812AU) += rtw88_8812au.o +rtw88_8812au-objs := rtw8812au.o + obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o rtw88_pci-objs := pci.o diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index a99776af56c2..c929db1e53ca 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -446,7 +446,7 @@ static void rtw_coex_check_rfk(struct rtw_dev *rtwdev) } } -static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev) +void rtw_coex_query_bt_info(struct rtw_dev *rtwdev) { struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex_stat *coex_stat = &coex->stat; @@ -494,11 +494,29 @@ static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev) struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_dm *coex_dm = &coex->dm; bool bt_disabled = false; + bool bt_active = true; u16 score_board; if (chip->scbd_support) { score_board = rtw_coex_read_scbd(rtwdev); bt_disabled = !(score_board & COEX_SCBD_ONOFF); + } else { + if (coex_stat->hi_pri_tx == 0 && coex_stat->hi_pri_rx == 0 && + coex_stat->lo_pri_tx == 0 && coex_stat->lo_pri_rx == 0) + bt_active = false; + + if (coex_stat->hi_pri_tx == 0xffff && coex_stat->hi_pri_rx == 0xffff && + coex_stat->lo_pri_tx == 0xffff && coex_stat->lo_pri_rx == 0xffff) + bt_active = false; + + if (bt_active) { + coex_stat->bt_disable_cnt = 0; + bt_disabled = false; + } else { + coex_stat->bt_disable_cnt++; + if (coex_stat->bt_disable_cnt >= 10) + bt_disabled = true; + } } if (coex_stat->bt_disabled != bt_disabled) { @@ -950,12 +968,18 @@ static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control) static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state) { + if (!rtwdev->chip->ltecoex_addr) + return; + rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0xc000, state); rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0c00, state); } static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state) { + if (!rtwdev->chip->ltecoex_addr) + return; + rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x3000, state); rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state); } @@ -2747,16 +2771,19 @@ void rtw_coex_power_on_setting(struct rtw_dev *rtwdev) rtw_write8(rtwdev, 0xff1a, 0x0); rtw_coex_set_gnt_debug(rtwdev); } +EXPORT_SYMBOL(rtw_coex_power_on_setting); void rtw_coex_power_off_setting(struct rtw_dev *rtwdev) { rtw_write16(rtwdev, REG_WIFI_BT_INFO, BIT_BT_INT_EN); } +EXPORT_SYMBOL(rtw_coex_power_off_setting); void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only) { __rtw_coex_init_hw_config(rtwdev, wifi_only); } +EXPORT_SYMBOL(rtw_coex_init_hw_config); void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type) { @@ -3904,7 +3931,7 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m) u8 sys_lte; u16 score_board_WB, score_board_BW; u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc; - u32 lte_coex, bt_coex; + u32 lte_coex = 0, bt_coex = 0; int i; score_board_BW = rtw_coex_read_scbd(rtwdev); @@ -3916,8 +3943,10 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m) wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL); sys_lte = rtw_read8(rtwdev, 0x73); - lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38); - bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54); + if (rtwdev->chip->ltecoex_addr) { + lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38); + bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54); + } if (!coex_stat->wl_under_ips && (!coex_stat->wl_under_lps || coex_stat->wl_force_lps_ctrl) && diff --git a/drivers/net/wireless/realtek/rtw88/coex.h b/drivers/net/wireless/realtek/rtw88/coex.h index 57cf29da9ea4..c398be8391f7 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.h +++ b/drivers/net/wireless/realtek/rtw88/coex.h @@ -384,6 +384,7 @@ u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr); void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr, u32 mask, u32 val); void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set); +void rtw_coex_query_bt_info(struct rtw_dev *rtwdev); void rtw_coex_bt_relink_work(struct work_struct *work); void rtw_coex_bt_reenable_work(struct work_struct *work); @@ -419,4 +420,14 @@ static inline bool rtw_coex_disabled(struct rtw_dev *rtwdev) return coex_stat->bt_disabled; } +static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev) +{ + /* The RTL8821AU firmware doesn't send C2H_BT_INFO by itself + * when bluetooth headphones are disconnected, so we have to + * ask for it regularly. + */ + if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A && rtwdev->efuse.btcoex) + rtw_coex_query_bt_info(rtwdev); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index c26a6905fd15..364ec0436d0f 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -308,7 +308,7 @@ static int rtw_debugfs_get_rsvd_page(struct seq_file *m, void *v) { struct rtw_debugfs_priv *debugfs_priv = m->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; - u8 page_size = rtwdev->chip->page_size; + u16 page_size = rtwdev->chip->page_size; u32 buf_size = debugfs_priv->rsvd_page.page_num * page_size; u32 offset = debugfs_priv->rsvd_page.page_offset * page_size; u8 *buf; diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index b9b0114e253b..e6e9946fbf44 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -139,25 +139,30 @@ static u16 get_max_amsdu_len(u32 bit_rate) struct rtw_fw_iter_ra_data { struct rtw_dev *rtwdev; u8 *payload; + u8 length; }; static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta) { struct rtw_fw_iter_ra_data *ra_data = data; + struct rtw_c2h_ra_rpt *ra_rpt = (struct rtw_c2h_ra_rpt *)ra_data->payload; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; u8 mac_id, rate, sgi, bw; u8 mcs, nss; u32 bit_rate; - mac_id = GET_RA_REPORT_MACID(ra_data->payload); + mac_id = ra_rpt->mac_id; if (si->mac_id != mac_id) return; si->ra_report.txrate.flags = 0; - rate = GET_RA_REPORT_RATE(ra_data->payload); - sgi = GET_RA_REPORT_SGI(ra_data->payload); - bw = GET_RA_REPORT_BW(ra_data->payload); + rate = u8_get_bits(ra_rpt->rate_sgi, RTW_C2H_RA_RPT_RATE); + sgi = u8_get_bits(ra_rpt->rate_sgi, RTW_C2H_RA_RPT_SGI); + if (ra_data->length >= offsetofend(typeof(*ra_rpt), bw)) + bw = ra_rpt->bw; + else + bw = si->bw_mode; if (rate < DESC_RATEMCS0) { si->ra_report.txrate.legacy = rtw_desc_to_bitrate(rate); @@ -197,14 +202,18 @@ legacy: static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, u8 length) { + struct rtw_c2h_ra_rpt *ra_rpt = (struct rtw_c2h_ra_rpt *)payload; struct rtw_fw_iter_ra_data ra_data; - if (WARN(length < 7, "invalid ra report c2h length\n")) + if (WARN(length < rtwdev->chip->c2h_ra_report_size, + "invalid ra report c2h length %d\n", length)) return; - rtwdev->dm_info.tx_rate = GET_RA_REPORT_RATE(payload); + rtwdev->dm_info.tx_rate = u8_get_bits(ra_rpt->rate_sgi, + RTW_C2H_RA_RPT_RATE); ra_data.rtwdev = rtwdev; ra_data.payload = payload; + ra_data.length = length; rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data); } @@ -267,7 +276,7 @@ static void rtw_fw_scan_result(struct rtw_dev *rtwdev, u8 *payload, static void rtw_fw_adaptivity_result(struct rtw_dev *rtwdev, u8 *payload, u8 length) { - struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th; + const struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th; struct rtw_c2h_adaptivity *result = (struct rtw_c2h_adaptivity *)payload; rtw_dbg(rtwdev, RTW_DBG_ADAPTIVITY, @@ -1281,16 +1290,16 @@ static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb, rtw_tx_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb, type); pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, chip->tx_pkt_desc_sz); - rtw_tx_fill_tx_desc(&pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, &pkt_info, skb); } -static inline u8 rtw_len_to_page(unsigned int len, u8 page_size) +static inline u8 rtw_len_to_page(unsigned int len, u16 page_size) { return DIV_ROUND_UP(len, page_size); } -static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u8 page_size, - u8 page_margin, u32 page, u8 *buf, +static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u16 page_size, + u16 page_margin, u32 page, u8 *buf, struct rtw_rsvd_page *rsvd_pkt) { struct sk_buff *skb = rsvd_pkt->skb; @@ -1592,13 +1601,13 @@ static int __rtw_build_rsvd_page_from_vifs(struct rtw_dev *rtwdev) static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, u32 *size) { - struct ieee80211_hw *hw = rtwdev->hw; const struct rtw_chip_info *chip = rtwdev->chip; - struct sk_buff *iter; + struct ieee80211_hw *hw = rtwdev->hw; struct rtw_rsvd_page *rsvd_pkt; - u32 page = 0; + struct sk_buff *iter; + u16 page_size, page_margin, tx_desc_sz; u8 total_page = 0; - u8 page_size, page_margin, tx_desc_sz; + u32 page = 0; u8 *buf; int ret; @@ -2004,12 +2013,13 @@ static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_probes, { const struct rtw_chip_info *chip = rtwdev->chip; struct sk_buff *skb, *tmp; - u8 page_offset = 1, *buf, page_size = chip->page_size; u16 pg_addr = rtwdev->fifo.rsvd_h2c_info_addr, loc; - u16 buf_offset = page_size * page_offset; u8 tx_desc_sz = chip->tx_pkt_desc_sz; - u8 page_cnt, pages; + u16 page_size = chip->page_size; + u8 page_offset = 1, *buf; + u16 buf_offset = page_size * page_offset; unsigned int pkt_len; + u8 page_cnt, pages; int ret; if (rtw_fw_feature_ext_check(&rtwdev->fw, FW_FEATURE_EXT_OLD_PAGE_NUM)) diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index e999c24e4634..404de1b0c407 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -85,6 +85,19 @@ struct rtw_c2h_adaptivity { u8 option; } __packed; +struct rtw_c2h_ra_rpt { + u8 rate_sgi; + u8 mac_id; + u8 byte2; + u8 status; + u8 byte4; + u8 ra_ratio; + u8 bw; +} __packed; + +#define RTW_C2H_RA_RPT_RATE GENMASK(6, 0) +#define RTW_C2H_RA_RPT_SGI BIT(7) + struct rtw_h2c_register { u32 w0; u32 w1; @@ -364,10 +377,6 @@ struct rtw_fw_hdr_legacy { #define GET_CHAN_SWITCH_CENTRAL_CH(c2h_payload) (c2h_payload[2]) #define GET_CHAN_SWITCH_ID(c2h_payload) (c2h_payload[3]) #define GET_CHAN_SWITCH_STATUS(c2h_payload) (c2h_payload[4]) -#define GET_RA_REPORT_RATE(c2h_payload) (c2h_payload[0] & 0x7f) -#define GET_RA_REPORT_SGI(c2h_payload) ((c2h_payload[0] & 0x80) >> 7) -#define GET_RA_REPORT_BW(c2h_payload) (c2h_payload[6]) -#define GET_RA_REPORT_MACID(c2h_payload) (c2h_payload[1]) #define GET_BCN_FILTER_NOTIFY_TYPE(c2h_payload) (c2h_payload[1] & 0xf) #define GET_BCN_FILTER_NOTIFY_EVENT(c2h_payload) (c2h_payload[1] & 0x10) diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 564f5988ee82..cae9cca6dca3 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -227,8 +227,8 @@ static int rtw_sub_pwr_seq_parser(struct rtw_dev *rtwdev, u8 intf_mask, return 0; } -static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, - const struct rtw_pwr_seq_cmd **cmd_seq) +int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd * const *cmd_seq) { u8 cut_mask; u8 intf_mask; @@ -267,11 +267,12 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, return 0; } +EXPORT_SYMBOL(rtw_pwr_seq_parser); static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) { const struct rtw_chip_info *chip = rtwdev->chip; - const struct rtw_pwr_seq_cmd **pwr_seq; + const struct rtw_pwr_seq_cmd * const *pwr_seq; u32 imr = 0; u8 rpwm; bool cur_pwr; @@ -994,6 +995,7 @@ int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) return 0; } +EXPORT_SYMBOL(rtw_download_firmware); static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) { @@ -1127,7 +1129,7 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev) return 0; } -static int set_trx_fifo_info(struct rtw_dev *rtwdev) +int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_fifo_conf *fifo = &rtwdev->fifo; @@ -1136,7 +1138,7 @@ static int set_trx_fifo_info(struct rtw_dev *rtwdev) /* config rsvd page num */ fifo->rsvd_drv_pg_num = chip->rsvd_drv_pg_num; - fifo->txff_pg_num = chip->txff_size >> 7; + fifo->txff_pg_num = chip->txff_size / chip->page_size; if (rtw_chip_wcpu_11n(rtwdev)) fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num; else @@ -1179,6 +1181,7 @@ static int set_trx_fifo_info(struct rtw_dev *rtwdev) return 0; } +EXPORT_SYMBOL(rtw_set_trx_fifo_info); static int __priority_queue_cfg(struct rtw_dev *rtwdev, const struct rtw_page_table *pg_tbl, @@ -1256,7 +1259,7 @@ static int priority_queue_cfg(struct rtw_dev *rtwdev) u16 pubq_num; int ret; - ret = set_trx_fifo_info(rtwdev); + ret = rtw_set_trx_fifo_info(rtwdev); if (ret) return ret; diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h index 58c3dccc14bb..6905e2747372 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.h +++ b/drivers/net/wireless/realtek/rtw88/mac.h @@ -30,11 +30,14 @@ void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, u8 primary_ch_idx); +int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd * const *cmd_seq); int rtw_mac_power_on(struct rtw_dev *rtwdev); void rtw_mac_power_off(struct rtw_dev *rtwdev); int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); int rtw_mac_init(struct rtw_dev *rtwdev); void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); +int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev); int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size); static inline void rtw_mac_flush_all_queues(struct rtw_dev *rtwdev, bool drop) diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index b39e90fb66b4..026fbf4ad9cc 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -928,8 +928,10 @@ static int rtw_ops_set_sar_specs(struct ieee80211_hw *hw, static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, + u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct rtw_dev *rtwdev = hw->priv; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; @@ -973,7 +975,7 @@ const struct ieee80211_ops rtw_ops = { .reconfig_complete = rtw_reconfig_complete, .hw_scan = rtw_ops_hw_scan, .cancel_hw_scan = rtw_ops_cancel_hw_scan, - .sta_rc_update = rtw_ops_sta_rc_update, + .link_sta_rc_update = rtw_ops_sta_rc_update, .set_sar_specs = rtw_ops_set_sar_specs, #ifdef CONFIG_PM .suspend = rtw_ops_suspend, diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index bbdef38c7e34..e91530ed05a0 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -202,6 +202,21 @@ static void rtw_vif_watch_dog_iter(void *data, struct ieee80211_vif *vif) rtwvif->stats.rx_cnt = 0; } +static void rtw_sw_beacon_loss_check(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif, int received_beacons) +{ + int watchdog_delay = 2000000 / 1024; /* TU */ + int beacon_int, expected_beacons; + + if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER) || !rtwvif) + return; + + beacon_int = rtwvif_to_vif(rtwvif)->bss_conf.beacon_int; + expected_beacons = DIV_ROUND_UP(watchdog_delay, beacon_int); + + rtwdev->beacon_loss = received_beacons < expected_beacons / 2; +} + /* process TX/RX statistics periodically for hardware, * the information helps hardware to enhance performance */ @@ -212,6 +227,7 @@ static void rtw_watch_dog_work(struct work_struct *work) struct rtw_traffic_stats *stats = &rtwdev->stats; struct rtw_watch_dog_iter_data data = {}; bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + int received_beacons = rtwdev->dm_info.cur_pkt_count.num_bcn_pkt; u32 tx_unicast_mbps, rx_unicast_mbps; bool ps_active; @@ -258,6 +274,7 @@ static void rtw_watch_dog_work(struct work_struct *work) rtw_leave_lps(rtwdev); rtw_coex_wl_status_check(rtwdev); rtw_coex_query_bt_hid_list(rtwdev); + rtw_coex_active_query_bt_info(rtwdev); rtw_phy_dynamic_mechanism(rtwdev); @@ -270,6 +287,8 @@ static void rtw_watch_dog_work(struct work_struct *work) */ rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); + rtw_sw_beacon_loss_check(rtwdev, data.rtwvif, received_beacons); + /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter * lps, because fw does not handle the overlapped beacon interval @@ -1309,7 +1328,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, rtw_fw_send_ra_info(rtwdev, si, reset_ra_mask); } -static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) +int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_fw_state *fw; @@ -1329,6 +1348,7 @@ static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) return ret; } +EXPORT_SYMBOL(rtw_wait_firmware_completion); static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) @@ -1350,7 +1370,7 @@ static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, return LPS_DEEP_MODE_NONE; } -static int rtw_power_on(struct rtw_dev *rtwdev) +int rtw_power_on(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_fw_state *fw = &rtwdev->fw; @@ -1413,6 +1433,7 @@ err_off: err: return ret; } +EXPORT_SYMBOL(rtw_power_on); void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start) { @@ -1485,7 +1506,7 @@ int rtw_core_start(struct rtw_dev *rtwdev) { int ret; - ret = rtw_power_on(rtwdev); + ret = rtwdev->chip->ops->power_on(rtwdev); if (ret) return ret; @@ -1505,12 +1526,13 @@ int rtw_core_start(struct rtw_dev *rtwdev) return 0; } -static void rtw_power_off(struct rtw_dev *rtwdev) +void rtw_power_off(struct rtw_dev *rtwdev) { rtw_hci_stop(rtwdev); rtw_coex_power_off_setting(rtwdev); rtw_mac_power_off(rtwdev); } +EXPORT_SYMBOL(rtw_power_off); void rtw_core_stop(struct rtw_dev *rtwdev) { @@ -1535,7 +1557,7 @@ void rtw_core_stop(struct rtw_dev *rtwdev) mutex_lock(&rtwdev->mutex); - rtw_power_off(rtwdev); + rtwdev->chip->ops->power_off(rtwdev); } static void rtw_init_ht_cap(struct rtw_dev *rtwdev, @@ -1917,6 +1939,9 @@ static int rtw_dump_hw_feature(struct rtw_dev *rtwdev) u8 bw; int i; + if (!rtwdev->chip->hw_feature_report) + return 0; + id = rtw_read8(rtwdev, REG_C2HEVT); if (id != C2H_HW_FEATURE_REPORT) { rtw_err(rtwdev, "failed to read hw feature report\n"); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 945117afe143..cd09fb6f7b8b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -189,6 +189,8 @@ enum rtw_chip_type { RTW_CHIP_TYPE_8723D, RTW_CHIP_TYPE_8821C, RTW_CHIP_TYPE_8703B, + RTW_CHIP_TYPE_8821A, + RTW_CHIP_TYPE_8812A, }; enum rtw_tx_queue_type { @@ -841,6 +843,8 @@ struct rtw_regd { }; struct rtw_chip_ops { + int (*power_on)(struct rtw_dev *rtwdev); + void (*power_off)(struct rtw_dev *rtwdev); int (*mac_init)(struct rtw_dev *rtwdev); int (*dump_fw_crash)(struct rtw_dev *rtwdev); void (*shutdown)(struct rtw_dev *rtwdev); @@ -848,9 +852,8 @@ struct rtw_chip_ops { void (*phy_set_param)(struct rtw_dev *rtwdev); void (*set_channel)(struct rtw_dev *rtwdev, u8 channel, u8 bandwidth, u8 primary_chan_idx); - void (*query_rx_desc)(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status); + void (*query_phy_status)(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat); u32 (*read_rf)(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, u32 addr, u32 mask); bool (*write_rf)(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, @@ -1096,17 +1099,20 @@ enum rtw_rfe_fem { struct rtw_rfe_def { const struct rtw_table *phy_pg_tbl; const struct rtw_table *txpwr_lmt_tbl; + const struct rtw_pwr_track_tbl *pwr_track_tbl; const struct rtw_table *agc_btg_tbl; }; -#define RTW_DEF_RFE(chip, bb_pg, pwrlmt) { \ +#define RTW_DEF_RFE(chip, bb_pg, pwrlmt, track) { \ .phy_pg_tbl = &rtw ## chip ## _bb_pg_type ## bb_pg ## _tbl, \ .txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \ + .pwr_track_tbl = &rtw ## chip ## _pwr_track_type ## track ## _tbl, \ } -#define RTW_DEF_RFE_EXT(chip, bb_pg, pwrlmt, btg) { \ +#define RTW_DEF_RFE_EXT(chip, bb_pg, pwrlmt, track, btg) { \ .phy_pg_tbl = &rtw ## chip ## _bb_pg_type ## bb_pg ## _tbl, \ .txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \ + .pwr_track_tbl = &rtw ## chip ## _pwr_track_type ## track ## _tbl, \ .agc_btg_tbl = &rtw ## chip ## _agc_btg_type ## btg ## _tbl, \ } @@ -1167,7 +1173,7 @@ enum rtw_fwcd_item { /* hardware configuration for each IC */ struct rtw_chip_info { - struct rtw_chip_ops *ops; + const struct rtw_chip_ops *ops; u8 id; const char *fw_name; @@ -1184,7 +1190,7 @@ struct rtw_chip_info { u32 fw_rxff_size; u16 rsvd_drv_pg_num; u8 band; - u8 page_size; + u16 page_size; u8 csi_buf_pg_num; u8 dig_max; u8 dig_min; @@ -1199,6 +1205,9 @@ struct rtw_chip_info { const struct rtw_fwcd_segs *fwcd_segs; u8 usb_tx_agg_desc_num; + bool hw_feature_report; + u8 c2h_ra_report_size; + bool old_datarate_fb_limit; u8 default_1ss_tx_path; @@ -1209,8 +1218,8 @@ struct rtw_chip_info { /* init values */ u8 sys_func_en; - const struct rtw_pwr_seq_cmd **pwr_on_seq; - const struct rtw_pwr_seq_cmd **pwr_off_seq; + const struct rtw_pwr_seq_cmd * const *pwr_on_seq; + const struct rtw_pwr_seq_cmd * const *pwr_off_seq; const struct rtw_rqpn *rqpn_table; const struct rtw_prioq_addrs *prioq_addrs; const struct rtw_page_table *page_table; @@ -1237,12 +1246,11 @@ struct rtw_chip_info { u16 dpd_ratemask; u8 iqk_threshold; u8 lck_threshold; - const struct rtw_pwr_track_tbl *pwr_track_tbl; u8 bfer_su_max_num; u8 bfer_mu_max_num; - struct rtw_hw_reg_offset *edcca_th; + const struct rtw_hw_reg_offset *edcca_th; s8 l2h_th_ini_cs; s8 l2h_th_ini_ad; @@ -1486,6 +1494,7 @@ struct rtw_coex_stat { u8 bt_hid_slot; u8 bt_a2dp_bitpool; u8 bt_iqk_state; + u8 bt_disable_cnt; u16 wl_beacon_interval; u8 wl_noisy_level; @@ -1709,7 +1718,7 @@ struct rtw_dm_info { bool pwr_trk_init_trigger; struct ewma_thermal avg_thermal[RTW_RF_PATH_MAX]; s8 txagc_remnant_cck; - s8 txagc_remnant_ofdm; + s8 txagc_remnant_ofdm[RTW_RF_PATH_MAX]; u8 rx_cck_agc_report_type; /* backup dack results for each path and I/Q */ @@ -1832,6 +1841,20 @@ struct rtw_phy_cond { #define BRANCH_ENDIF 3 }; +struct rtw_phy_cond2 { +#ifdef __LITTLE_ENDIAN + u8 type_glna; + u8 type_gpa; + u8 type_alna; + u8 type_apa; +#else + u8 type_apa; + u8 type_alna; + u8 type_gpa; + u8 type_glna; +#endif +}; + struct rtw_fifo_conf { /* tx fifo information */ u16 rsvd_boundary; @@ -1913,6 +1936,7 @@ struct rtw_hal { u8 oem_id; u8 pkg_type; struct rtw_phy_cond phy_cond; + struct rtw_phy_cond2 phy_cond2; bool rfe_btg; u8 ps_mode; @@ -1935,6 +1959,7 @@ struct rtw_hal { u32 antenna_rx; u8 bfee_sts_cap; bool txrx_1ss; + bool cck_high_power; /* protect tx power section */ struct mutex tx_power_mutex; @@ -2190,6 +2215,7 @@ void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, bool hw_scan); int rtw_core_start(struct rtw_dev *rtwdev); +void rtw_power_off(struct rtw_dev *rtwdev); void rtw_core_stop(struct rtw_dev *rtwdev); int rtw_chip_info_setup(struct rtw_dev *rtwdev); int rtw_core_init(struct rtw_dev *rtwdev); @@ -2204,6 +2230,8 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, bool fw_exist); void rtw_fw_recovery(struct rtw_dev *rtwdev); +int rtw_wait_firmware_completion(struct rtw_dev *rtwdev); +int rtw_power_on(struct rtw_dev *rtwdev); void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start); int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, u32 fwcd_item); diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 0b9b8807af2c..0ecaefc4c83d 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -824,7 +824,7 @@ static int rtw_pci_tx_write_data(struct rtw_dev *rtwdev, pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, tx_pkt_desc_sz); pkt_info->qsel = rtw_pci_get_tx_qsel(skb, queue); - rtw_tx_fill_tx_desc(pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb); dma = dma_map_single(&rtwpci->pdev->dev, skb->data, skb->len, DMA_TO_DEVICE); if (dma_mapping_error(&rtwpci->pdev->dev, dma)) @@ -1065,7 +1065,7 @@ static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci, dma_sync_single_for_cpu(rtwdev->dev, dma, RTK_PCI_RX_BUF_SIZE, DMA_FROM_DEVICE); rx_desc = skb->data; - chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status); + rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status); /* offset from rx_desc to payload */ pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 37ef80c9091d..8ed20c89d216 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -18,7 +18,10 @@ struct phy_cfg_pair { }; union phy_table_tile { - struct rtw_phy_cond cond; + struct { + struct rtw_phy_cond cond; + struct rtw_phy_cond2 cond2; + } __packed; struct phy_cfg_pair cfg; }; @@ -123,7 +126,7 @@ static void rtw_phy_cck_pd_init(struct rtw_dev *rtwdev) void rtw_phy_set_edcca_th(struct rtw_dev *rtwdev, u8 l2h, u8 h2l) { - struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th; + const struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th; rtw_write32_mask(rtwdev, edcca_th[EDCCA_TH_L2H_IDX].hw_reg.addr, @@ -527,6 +530,13 @@ static void rtw_phy_dig(struct rtw_dev *rtwdev) */ rtw_phy_dig_recorder(dm_info, cur_igi, fa_cnt); + /* Mitigate beacon loss and connectivity issues, mainly (only?) + * in the 5 GHz band + */ + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A && rtwdev->beacon_loss && + linked && dm_info->total_fa_cnt < DIG_PERF_FA_TH_EXTRA_HIGH) + cur_igi = DIG_CVRG_MIN; + if (cur_igi != pre_igi) rtw_phy_dig_write(rtwdev, cur_igi); } @@ -1041,7 +1051,8 @@ void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg) { struct rtw_hal *hal = &rtwdev->hal; struct rtw_efuse *efuse = &rtwdev->efuse; - struct rtw_phy_cond cond = {0}; + struct rtw_phy_cond cond = {}; + struct rtw_phy_cond2 cond2 = {}; cond.cut = hal->cut_version ? hal->cut_version : 15; cond.pkg = pkg ? pkg : 15; @@ -1061,15 +1072,34 @@ void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg) break; } + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A || + rtwdev->chip->id == RTW_CHIP_TYPE_8821A) { + cond.rfe = 0; + cond.rfe |= efuse->ext_lna_2g; + cond.rfe |= efuse->ext_pa_2g << 1; + cond.rfe |= efuse->ext_lna_5g << 2; + cond.rfe |= efuse->ext_pa_5g << 3; + cond.rfe |= efuse->btcoex << 4; + + cond2.type_alna = efuse->alna_type; + cond2.type_glna = efuse->glna_type; + cond2.type_apa = efuse->apa_type; + cond2.type_gpa = efuse->gpa_type; + } + hal->phy_cond = cond; + hal->phy_cond2 = cond2; - rtw_dbg(rtwdev, RTW_DBG_PHY, "phy cond=0x%08x\n", *((u32 *)&hal->phy_cond)); + rtw_dbg(rtwdev, RTW_DBG_PHY, "phy cond=0x%08x cond2=0x%08x\n", + *((u32 *)&hal->phy_cond), *((u32 *)&hal->phy_cond2)); } -static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond) +static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond, + struct rtw_phy_cond2 cond2) { struct rtw_hal *hal = &rtwdev->hal; struct rtw_phy_cond drv_cond = hal->phy_cond; + struct rtw_phy_cond2 drv_cond2 = hal->phy_cond2; if (cond.cut && cond.cut != drv_cond.cut) return false; @@ -1080,8 +1110,29 @@ static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond) if (cond.intf && cond.intf != drv_cond.intf) return false; - if (cond.rfe != drv_cond.rfe) - return false; + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A || + rtwdev->chip->id == RTW_CHIP_TYPE_8821A) { + if (!(cond.rfe & 0x0f)) + return true; + + if ((cond.rfe & drv_cond.rfe) != cond.rfe) + return false; + + if ((cond.rfe & BIT(0)) && cond2.type_glna != drv_cond2.type_glna) + return false; + + if ((cond.rfe & BIT(1)) && cond2.type_gpa != drv_cond2.type_gpa) + return false; + + if ((cond.rfe & BIT(2)) && cond2.type_alna != drv_cond2.type_alna) + return false; + + if ((cond.rfe & BIT(3)) && cond2.type_apa != drv_cond2.type_apa) + return false; + } else { + if (cond.rfe != drv_cond.rfe) + return false; + } return true; } @@ -1090,7 +1141,8 @@ void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl) { const union phy_table_tile *p = tbl->data; const union phy_table_tile *end = p + tbl->size / 2; - struct rtw_phy_cond pos_cond = {0}; + struct rtw_phy_cond pos_cond = {}; + struct rtw_phy_cond2 pos_cond2 = {}; bool is_matched = true, is_skipped = false; BUILD_BUG_ON(sizeof(union phy_table_tile) != sizeof(struct phy_cfg_pair)); @@ -1109,11 +1161,12 @@ void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl) case BRANCH_ELIF: default: pos_cond = p->cond; + pos_cond2 = p->cond2; break; } } else if (p->cond.neg) { if (!is_skipped) { - if (check_positive(rtwdev, pos_cond)) { + if (check_positive(rtwdev, pos_cond, pos_cond2)) { is_matched = true; is_skipped = true; } else { @@ -1470,10 +1523,8 @@ static void rtw_phy_store_tx_power_by_rate(struct rtw_dev *rtwdev, rate = rates[i]; if (band == PHY_BAND_2G) hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset; - else if (band == PHY_BAND_5G) - hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset; else - continue; + hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset; } } @@ -2125,8 +2176,8 @@ void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, *limit = rtw_phy_get_tx_power_limit(rtwdev, band, bw, path, rate, ch, regd); - *remnant = (rate <= DESC_RATE11M ? dm_info->txagc_remnant_cck : - dm_info->txagc_remnant_ofdm); + *remnant = rate <= DESC_RATE11M ? dm_info->txagc_remnant_cck : + dm_info->txagc_remnant_ofdm[path]; *sar = rtw_phy_get_tx_power_sar(rtwdev, hal->sar_band, path, rate); } @@ -2340,7 +2391,8 @@ void rtw_phy_init_tx_power(struct rtw_dev *rtwdev) void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, struct rtw_swing_table *swing_table) { - const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl; + const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev); + const struct rtw_pwr_track_tbl *tbl = rfe_def->pwr_track_tbl; u8 channel = rtwdev->hal.current_channel; if (IS_CH_2G_BAND(channel)) { diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 4d9b8668e8b0..e4d506cf9c33 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -9,6 +9,7 @@ #define BIT_FEN_EN_25_1 BIT(13) #define BIT_FEN_ELDR BIT(12) #define BIT_FEN_CPUEN BIT(2) +#define BIT_FEN_USBA BIT(2) #define BIT_FEN_BB_GLB_RST BIT(1) #define BIT_FEN_BB_RSTB BIT(0) #define BIT_R_DIS_PRST BIT(6) @@ -16,6 +17,10 @@ #define REG_SYS_PW_CTRL 0x0004 #define BIT_PFM_WOWL BIT(3) #define BIT_APFM_OFFMAC BIT(9) +#define REG_APS_FSMCO 0x0004 +#define APS_FSMCO_MAC_ENABLE BIT(8) +#define APS_FSMCO_MAC_OFF BIT(9) +#define APS_FSMCO_HW_POWERDOWN BIT(15) #define REG_SYS_CLK_CTRL 0x0008 #define BIT_CPU_CLK_EN BIT(14) @@ -58,6 +63,8 @@ #define BIT_SHIFT_LDO25_VOLTAGE 4 #define BIT_LDO25_EN BIT(7) +#define REG_ACLK_MON 0x3e + #define REG_GPIO_MUXCFG 0x0040 #define BIT_FSPI_EN BIT(19) #define BIT_EN_SIC BIT(12) @@ -90,6 +97,8 @@ #define BIT_USB_SUS_DIS BIT(8) #define BIT_SDIO_PAD_E5 BIT(18) +#define REG_RF_B_CTRL 0x76 + #define REG_AFE_CTRL_4 0x0078 #define BIT_CK320M_AFE_EN BIT(4) #define BIT_EN_SYN BIT(15) @@ -134,6 +143,11 @@ #define REG_PMC_DBG_CTRL1 0xa8 #define BITS_PMC_BT_IQK_STS GENMASK(22, 21) +#define REG_HIMR0 0xb0 +#define REG_HISR0 0xb4 +#define REG_HIMR1 0xb8 +#define REG_HISR1 0xbc + #define REG_PAD_CTRL2 0x00C4 #define BIT_RSM_EN_V1 BIT(16) #define BIT_NO_PDN_CHIPOFF_V1 BIT(17) @@ -185,6 +199,15 @@ #define MAC_TRX_ENABLE (BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | \ BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | \ BIT_MACTXEN | BIT_MACRXEN) +#define REG_PBP 0x104 +#define PBP_RX_MASK 0x0f +#define PBP_TX_MASK 0xf0 +#define PBP_64 0x0 +#define PBP_128 0x1 +#define PBP_256 0x2 +#define PBP_512 0x3 +#define PBP_1024 0x4 + #define BIT_SHIFT_TXDMA_VOQ_MAP 4 #define BIT_MASK_TXDMA_VOQ_MAP 0x3 #define BIT_TXDMA_VOQ_MAP(x) \ @@ -256,6 +279,8 @@ #define REG_HMEBOX1 0x01D4 #define REG_HMEBOX2 0x01D8 #define REG_HMEBOX3 0x01DC +#define REG_LLT_INIT 0x01E0 +#define BIT_LLT_WRITE_ACCESS BIT(30) #define REG_HMEBOX0_EX 0x01F0 #define REG_HMEBOX1_EX 0x01F4 #define REG_HMEBOX2_EX 0x01F8 @@ -298,6 +323,7 @@ #define REG_AUTO_LLT 0x0224 #define BIT_AUTO_INIT_LLT BIT(16) +#define REG_DWBCN1_CTRL 0x0228 #define REG_RQPN_CTRL_1 0x0228 #define REG_RQPN_CTRL_2 0x022C #define BIT_LD_RQPN BIT(31) @@ -329,6 +355,7 @@ #define BIT_DMA_BURST_SIZE_1024 0 #define REG_RXPKTNUM 0x02B0 +#define REG_EARLY_MODE_CONTROL 0x02BC #define REG_INT_MIG 0x0304 #define REG_HCI_MIX_CFG 0x03FC @@ -336,6 +363,7 @@ #define REG_BCNQ_INFO 0x0418 #define BIT_MGQ_CPU_EMPTY BIT(24) +#define REG_TXPKT_EMPTY 0x041A #define REG_FWHW_TXQ_CTRL 0x0420 #define BIT_EN_BCNQ_DL BIT(22) #define BIT_EN_WR_FREE_TAIL BIT(20) @@ -362,10 +390,12 @@ #define REG_AMPDU_MAX_TIME_V1 0x0455 #define REG_BCNQ1_BDNY_V1 0x0456 #define REG_AMPDU_MAX_TIME 0x0456 +#define REG_AMPDU_MAX_LENGTH 0x0458 #define REG_WMAC_LBK_BF_HD 0x045D #define REG_TX_HANG_CTRL 0x045E #define BIT_EN_GNT_BT_AWAKE BIT(3) #define BIT_EN_EOF_V1 BIT(2) +#define REG_FAST_EDCA_CTRL 0x0460 #define REG_DATA_SC 0x0483 #define REG_ARFR2_V1 0x048C #define REG_ARFRH2_V1 0x0490 @@ -390,6 +420,8 @@ #define REG_PRECNT_CTRL 0x04E5 #define BIT_BTCCA_CTRL (BIT(0) | BIT(1)) #define BIT_EN_PRECNT BIT(11) +#define REG_TX_RPT_CTRL 0x04EC +#define REG_TX_RPT_TIME 0x04F0 #define REG_DUMMY_PAGE4_V1 0x04FC #define REG_EDCA_VO_PARAM 0x0500 @@ -400,6 +432,7 @@ #define BIT_MASK_CWMAX GENMASK(15, 12) #define BIT_MASK_CWMIN GENMASK(11, 8) #define BIT_MASK_AIFS GENMASK(7, 0) +#define REG_BCNTCFG 0x0510 #define REG_PIFS 0x0512 #define REG_SIFS 0x0514 #define BIT_SHIFT_SIFS_OFDM_CTX 8 @@ -526,6 +559,8 @@ #define REG_BT_COEX_V2 0x0762 #define BIT_GNT_BT_POLARITY BIT(12) #define BIT_LTE_COEX_EN BIT(7) +#define REG_GNT_BT 0x0765 +#define BIT_PTA_SW_CTL GENMASK(4, 3) #define REG_BT_COEX_ENH_INTR_CTRL 0x76E #define BIT_R_GRANTALL_WLMASK BIT(3) #define BIT_STATIS_BT_EN BIT(2) @@ -543,14 +578,43 @@ #define REG_FPGA0_RFMOD 0x0800 #define BIT_CCKEN BIT(24) #define BIT_OFDMEN BIT(25) +#define REG_CCK_RPT_FORMAT 0x0804 +#define BIT_CCK_RPT_FORMAT BIT(16) +#define REG_RXPSEL 0x0808 +#define BIT_RX_PSEL_RST (BIT(28) | BIT(29)) +#define REG_TXPSEL 0x080C #define REG_RX_GAIN_EN 0x081c +#define REG_CCASEL 0x082C +#define REG_PDMFTH 0x0830 +#define REG_BWINDICATION 0x0834 +#define REG_CCA2ND 0x0838 +#define REG_L1PKTH 0x0848 +#define REG_CLKTRK 0x0860 +#define REG_ADCCLK 0x08AC +#define REG_HSSI_READ 0x08B0 +#define REG_FPGA0_XCD_RF_PARA 0x08B4 +#define REG_RX_MCS_LIMIT 0x08BC +#define REG_ADC160 0x08C4 +#define REG_ANTSEL_SW 0x0900 +#define REG_DAC_RSTB 0x090c +#define REG_SINGLE_TONE_CONT_TX 0x0914 #define REG_RFE_CTRL_E 0x0974 #define REG_2ND_CCA_CTRL 0x0976 +#define REG_IQK_COM00 0x0978 +#define REG_IQK_COM32 0x097c +#define REG_IQK_COM64 0x0980 +#define REG_IQK_COM96 0x0984 + +#define REG_FAS 0x09a4 +#define REG_RXSB 0x0a00 +#define REG_CCK_RX 0x0a04 +#define REG_CCK_PD_TH 0x0a0a #define REG_CCK0_FAREPORT 0xa2c #define BIT_CCK0_2RX BIT(18) #define BIT_CCK0_MRC BIT(22) +#define REG_FA_CCK 0x0a5c #define REG_DIS_DPD 0x0a70 #define DIS_DPD_MASK GENMASK(9, 0) @@ -566,13 +630,109 @@ #define DIS_DPD_RATEVHT2SS_MCS1 BIT(9) #define DIS_DPD_RATEALL GENMASK(9, 0) +#define REG_CNTRST 0x0b58 + +#define REG_3WIRE_SWA 0x0c00 +#define REG_RX_IQC_AB_A 0x0c10 +#define REG_TXSCALE_A 0x0c1c +#define BB_SWING_MASK GENMASK(31, 21) +#define REG_TX_AGC_A_CCK_11_CCK_1 0xc20 +#define REG_TX_AGC_A_OFDM18_OFDM6 0xc24 +#define REG_TX_AGC_A_OFDM54_OFDM24 0xc28 +#define REG_TX_AGC_A_MCS3_MCS0 0xc2c +#define REG_TX_AGC_A_MCS7_MCS4 0xc30 +#define REG_TX_AGC_A_MCS11_MCS8 0xc34 +#define REG_TX_AGC_A_MCS15_MCS12 0xc38 +#define REG_TX_AGC_A_NSS1_INDEX3_NSS1_INDEX0 0xc3c +#define REG_TX_AGC_A_NSS1_INDEX7_NSS1_INDEX4 0xc40 +#define REG_TX_AGC_A_NSS2_INDEX1_NSS1_INDEX8 0xc44 +#define REG_TX_AGC_A_NSS2_INDEX5_NSS2_INDEX2 0xc48 +#define REG_TX_AGC_A_NSS2_INDEX9_NSS2_INDEX6 0xc4c +#define REG_RXIGI_A 0x0c50 +#define REG_TX_PWR_TRAINING_A 0x0c54 +#define REG_CK_MONHA 0x0c5c +#define REG_AFE_PWR1_A 0x0c60 +#define REG_AFE_PWR2_A 0x0c64 +#define REG_RX_WAIT_CCA_TX_CCK_RFON_A 0x0c68 +#define REG_OFDM0_XA_TX_IQ_IMBALANCE 0x0c80 +#define REG_OFDM0_A_TX_AFE 0x0c84 +#define REG_OFDM0_XB_TX_IQ_IMBALANCE 0x0c88 +#define REG_TSSI_TRK_SW 0x0c8c +#define REG_LSSI_WRITE_A 0x0c90 +#define REG_PREDISTA 0x0c90 +#define REG_TXAGCIDX 0x0c94 + +#define REG_RFE_PINMUX_A 0x0cb0 +#define REG_RFE_INV_A 0x0cb4 #define REG_RFE_CTRL8 0x0cb4 #define BIT_MASK_RFE_SEL89 GENMASK(7, 0) +#define PTA_CTRL_PIN 0x66 +#define DPDT_CTRL_PIN 0x77 +#define RFE_INV_MASK 0x3ff00000 +#define REG_RFECTL_A 0x0cb8 #define REG_RFE_INV8 0x0cbd #define BIT_MASK_RFE_INV89 GENMASK(1, 0) #define REG_RFE_INV16 0x0cbe #define BIT_RFE_BUF_EN BIT(3) +#define REG_IQK_DPD_CFG 0x0cc4 +#define REG_CFG_PMPD 0x0cc8 +#define REG_IQC_Y 0x0ccc +#define REG_IQC_X 0x0cd4 +#define REG_INTPO_SETA 0x0ce8 + +#define REG_IQKA_END 0x0d00 +#define REG_PI_READ_A 0x0d04 +#define REG_SI_READ_A 0x0d08 +#define REG_IQKB_END 0x0d40 +#define REG_PI_READ_B 0x0d44 +#define REG_SI_READ_B 0x0d48 + +#define REG_3WIRE_SWB 0x0e00 +#define REG_RX_IQC_AB_B 0x0e10 +#define REG_TXSCALE_B 0x0e1c +#define REG_TX_AGC_B_CCK_11_CCK_1 0xe20 +#define REG_TX_AGC_B_OFDM18_OFDM6 0xe24 +#define REG_TX_AGC_B_OFDM54_OFDM24 0xe28 +#define REG_TX_AGC_B_MCS3_MCS0 0xe2c +#define REG_TX_AGC_B_MCS7_MCS4 0xe30 +#define REG_TX_AGC_B_MCS11_MCS8 0xe34 +#define REG_TX_AGC_B_MCS15_MCS12 0xe38 +#define REG_TX_AGC_B_NSS1_INDEX3_NSS1_INDEX0 0xe3c +#define REG_TX_AGC_B_NSS1_INDEX7_NSS1_INDEX4 0xe40 +#define REG_TX_AGC_B_NSS2_INDEX1_NSS1_INDEX8 0xe44 +#define REG_TX_AGC_B_NSS2_INDEX5_NSS2_INDEX2 0xe48 +#define REG_TX_AGC_B_NSS2_INDEX9_NSS2_INDEX6 0xe4c +#define REG_RXIGI_B 0x0e50 +#define REG_TX_PWR_TRAINING_B 0x0e54 +#define REG_CK_MONHB 0x0e5c +#define REG_AFE_PWR1_B 0x0e60 +#define REG_AFE_PWR2_B 0x0e64 +#define REG_RX_WAIT_CCA_TX_CCK_RFON_B 0x0e68 +#define REG_TXTONEB 0x0e80 +#define REG_RXTONEB 0x0e84 +#define REG_TXPITMB 0x0e88 +#define REG_RXPITMB 0x0e8c +#define REG_LSSI_WRITE_B 0x0e90 +#define REG_PREDISTB 0x0e90 +#define REG_INIDLYB 0x0e94 +#define REG_RFE_PINMUX_B 0x0eb0 +#define REG_RFE_INV_B 0x0eb4 +#define REG_RFECTL_B 0x0eb8 +#define REG_BPBDB 0x0ec4 +#define REG_PHYTXONB 0x0ec8 +#define REG_IQKYB 0x0ecc +#define REG_IQKXB 0x0ed4 +#define REG_INTPO_SETB 0x0ee8 + +#define REG_CRC_CCK 0x0f04 +#define REG_CCA_OFDM 0x0f08 +#define REG_CRC_VHT 0x0f0c +#define REG_CRC_HT 0x0f10 +#define REG_CRC_OFDM 0x0f14 +#define REG_FA_OFDM 0x0f48 +#define REG_CCA_CCK 0x0fcc + #define REG_ANAPARSW_MAC_0 0x1010 #define BIT_CF_L_V2 GENMASK(29, 28) @@ -709,6 +869,10 @@ #define REG_IGN_GNTBT4 0x4160 +#define REG_USB_MOD 0xf008 +#define REG_USB3_RXITV 0xf050 +#define REG_USB_HRPWM 0xfe58 + #define RF_MODE 0x00 #define RF_MODOPT 0x01 #define RF_WLINT 0x01 @@ -716,7 +880,13 @@ #define RF_DTXLOK 0x08 #define RF_CFGCH 0x18 #define BIT_BAND GENMASK(18, 16) +#define RF18_BAND_MASK (BIT(16) | BIT(9) | BIT(8)) +#define RF18_CHANNEL_MASK (MASKBYTE0) +#define RF18_RFSI_MASK (BIT(18) | BIT(17)) #define RF_RCK 0x1d +#define RF_MODE_TABLE_ADDR 0x30 +#define RF_MODE_TABLE_DATA0 0x31 +#define RF_MODE_TABLE_DATA1 0x32 #define RF_LUTWA 0x33 #define RF_LUTWD1 0x3e #define RF_LUTWD0 0x3f @@ -725,10 +895,14 @@ #define RF_T_METER 0x42 #define RF_BSPAD 0x54 #define RF_GAINTX 0x56 +#define RF_TXMOD 0x58 #define RF_TXATANK 0x64 +#define RF_TXA_PREPAD 0x65 #define RF_TRXIQ 0x66 #define RF_RXIQGEN 0x8d +#define RF_RXBB2 0x8f #define RF_SYN_PFD 0xb0 +#define RF_LCK 0xb4 #define RF_XTALX2 0xb8 #define RF_SYN_CTRL 0xbb #define RF_MALSEL 0xbe diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c index 222608de33cd..a19b94d022ee 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c @@ -29,9 +29,6 @@ #define TBTT_PROHIBIT_HOLD_TIME 0x80 #define TBTT_PROHIBIT_HOLD_TIME_STOP_BCN 0x64 -/* raw pkt_stat->drv_info_sz is in unit of 8-bytes */ -#define RX_DRV_INFO_SZ_UNIT_8703B 8 - #define TRANS_SEQ_END \ 0xFFFF, \ RTW_PWR_CUT_ALL_MSK, \ @@ -481,14 +478,14 @@ static const struct rtw_pwr_seq_cmd trans_act_to_lps_8703b[] = { {TRANS_SEQ_END}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8703b[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8703b[] = { trans_pre_enable_8703b, trans_carddis_to_cardemu_8703b, trans_cardemu_to_act_8703b, NULL }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8703b[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8703b[] = { trans_act_to_lps_8703b, trans_act_to_reset_mcu_8703b, trans_act_to_cardemu_8703b, @@ -496,11 +493,6 @@ static const struct rtw_pwr_seq_cmd *card_disable_flow_8703b[] = { NULL }; -static const struct rtw_rfe_def rtw8703b_rfe_defs[] = { - [0] = { .phy_pg_tbl = &rtw8703b_bb_pg_tbl, - .txpwr_lmt_tbl = &rtw8703b_txpwr_lmt_tbl,}, -}; - static const struct rtw_page_table page_table_8703b[] = { {12, 2, 2, 0, 1}, {12, 2, 2, 0, 1}, @@ -640,7 +632,7 @@ static void rtw8703b_pwrtrack_init(struct rtw_dev *rtwdev) dm_info->pwr_trk_init_trigger = true; dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; dm_info->txagc_remnant_cck = 0; - dm_info->txagc_remnant_ofdm = 0; + dm_info->txagc_remnant_ofdm[RF_PATH_A] = 0; } static void rtw8703b_phy_set_param(struct rtw_dev *rtwdev) @@ -1032,57 +1024,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, query_phy_status_ofdm(rtwdev, phy_status, pkt_stat); } -static void rtw8703b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = 0; - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - pkt_stat->drv_info_sz *= RX_DRV_INFO_SZ_UNIT_8703B; - - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - - pkt_stat->bw = GET_RX_DESC_BW(rx_desc); - - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); - - /* Rtl8723cs driver checks for size < 14 or size > 8192 and - * simply drops the packet. Maybe this should go into - * rtw_rx_fill_rx_status()? - */ - if (pkt_stat->pkt_len == 0) { - rx_status->flag |= RX_FLAG_NO_PSDU; - rtw_dbg(rtwdev, RTW_DBG_RX, "zero length packet"); - } -} - #define ADDA_ON_VAL_8703B 0x03c00014 static @@ -1643,7 +1584,7 @@ static void rtw8703b_pwrtrack_set_ofdm_pwr(struct rtw_dev *rtwdev, s8 swing_idx, { struct rtw_dm_info *dm_info = &rtwdev->dm_info; - dm_info->txagc_remnant_ofdm = txagc_idx; + dm_info->txagc_remnant_ofdm[RF_PATH_A] = txagc_idx; /* Only path A is calibrated for rtl8703b */ rtw8703b_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_A); @@ -1872,6 +1813,12 @@ static const struct rtw_pwr_track_tbl rtw8703b_rtw_pwr_track_tbl = { .pwrtrk_xtal_p = rtw8703b_pwrtrk_xtal_p, }; +static const struct rtw_rfe_def rtw8703b_rfe_defs[] = { + [0] = { .phy_pg_tbl = &rtw8703b_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8703b_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8703b_rtw_pwr_track_tbl, }, +}; + /* Shared-Antenna Coex Table */ static const struct coex_table_para table_sant_8703b[] = { {0xffffffff, 0xffffffff}, /* case-0 */ @@ -1941,14 +1888,16 @@ static const struct coex_tdma_para tdma_sant_8703b[] = { { {0x61, 0x08, 0x03, 0x11, 0x11} }, }; -static struct rtw_chip_ops rtw8703b_ops = { +static const struct rtw_chip_ops rtw8703b_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .mac_init = rtw8723x_mac_init, .dump_fw_crash = NULL, .shutdown = NULL, .read_efuse = rtw8703b_read_efuse, .phy_set_param = rtw8703b_phy_set_param, .set_channel = rtw8703b_set_channel, - .query_rx_desc = rtw8703b_query_rx_desc, + .query_phy_status = query_phy_status, .read_rf = rtw_phy_read_rf_sipi, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8723x_set_tx_power_index, @@ -2014,6 +1963,9 @@ const struct rtw_chip_info rtw8703b_hw_spec = { .max_power_index = 0x3f, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .usb_tx_agg_desc_num = 1, /* Not sure if this chip has USB interface */ + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = true, .path_div_supported = false, .ht_supported = true, @@ -2046,7 +1998,6 @@ const struct rtw_chip_info rtw8703b_hw_spec = { .rfe_defs_size = ARRAY_SIZE(rtw8703b_rfe_defs), .iqk_threshold = 8, - .pwr_track_tbl = &rtw8703b_rtw_pwr_track_tbl, /* WOWLAN firmware exists, but not implemented yet */ .wow_fw_name = "rtw88/rtw8703b_wow_fw.bin", diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 3fba4054d45f..eeca31bf71f1 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -79,7 +79,7 @@ static void rtw8723d_pwrtrack_init(struct rtw_dev *rtwdev) dm_info->pwr_trk_init_trigger = true; dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; dm_info->txagc_remnant_cck = 0; - dm_info->txagc_remnant_ofdm = 0; + dm_info->txagc_remnant_ofdm[RF_PATH_A] = 0; } static void rtw8723d_phy_set_param(struct rtw_dev *rtwdev) @@ -227,47 +227,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, } } -static void rtw8723d_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = 0; - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - /* drv_info_sz is in unit of 8-bytes */ - pkt_stat->drv_info_sz *= 8; - - /* c2h cmd pkt's rx/phy status is not interested */ - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); -} - static bool rtw8723d_check_spur_ov_thres(struct rtw_dev *rtwdev, u8 channel, u32 thres) { @@ -1306,7 +1265,7 @@ static void rtw8723d_pwrtrack_set_ofdm_pwr(struct rtw_dev *rtwdev, s8 swing_idx, { struct rtw_dm_info *dm_info = &rtwdev->dm_info; - dm_info->txagc_remnant_ofdm = txagc_idx; + dm_info->txagc_remnant_ofdm[RF_PATH_A] = txagc_idx; rtw8723d_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_A); rtw8723d_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_B); @@ -1430,10 +1389,12 @@ static void rtw8723d_pwr_track(struct rtw_dev *rtwdev) dm_info->pwr_trk_triggered = false; } -static struct rtw_chip_ops rtw8723d_ops = { +static const struct rtw_chip_ops rtw8723d_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .phy_set_param = rtw8723d_phy_set_param, .read_efuse = rtw8723x_read_efuse, - .query_rx_desc = rtw8723d_query_rx_desc, + .query_phy_status = query_phy_status, .set_channel = rtw8723d_set_channel, .mac_init = rtw8723x_mac_init, .shutdown = rtw8723d_shutdown, @@ -1788,7 +1749,7 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8723d[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8723d[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8723d[] = { trans_carddis_to_cardemu_8723d, trans_cardemu_to_act_8723d, NULL @@ -2004,7 +1965,7 @@ static const struct rtw_pwr_seq_cmd trans_act_to_post_carddis_8723d[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8723d[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8723d[] = { trans_act_to_lps_8723d, trans_act_to_pre_carddis_8723d, trans_act_to_cardemu_8723d, @@ -2059,11 +2020,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8723d = { .n_gen1_para = ARRAY_SIZE(pcie_gen1_param_8723d), }; -static const struct rtw_rfe_def rtw8723d_rfe_defs[] = { - [0] = { .phy_pg_tbl = &rtw8723d_bb_pg_tbl, - .txpwr_lmt_tbl = &rtw8723d_txpwr_lmt_tbl,}, -}; - static const u8 rtw8723d_pwrtrk_2gb_n[] = { 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10 @@ -2127,6 +2083,12 @@ static const struct rtw_pwr_track_tbl rtw8723d_rtw_pwr_track_tbl = { .pwrtrk_xtal_n = rtw8723d_pwrtrk_xtal_n, }; +static const struct rtw_rfe_def rtw8723d_rfe_defs[] = { + [0] = { .phy_pg_tbl = &rtw8723d_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8723d_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, }, +}; + static const struct rtw_reg_domain coex_info_hw_regs_8723d[] = { {0x948, MASKDWORD, RTW_REG_DOMAIN_MAC32}, {0x67, BIT(7), RTW_REG_DOMAIN_MAC8}, @@ -2172,6 +2134,9 @@ const struct rtw_chip_info rtw8723d_hw_spec = { .page_size = TX_PAGE_SIZE, .dig_min = 0x20, .usb_tx_agg_desc_num = 1, + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = true, .ht_supported = true, .vht_supported = false, .lps_deep_mode_supported = 0, @@ -2195,7 +2160,6 @@ const struct rtw_chip_info rtw8723d_hw_spec = { .rfe_defs = rtw8723d_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8723d_rfe_defs), .rx_ldpc = false, - .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, .iqk_threshold = 8, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.c b/drivers/net/wireless/realtek/rtw88/rtw8723x.c index 0d0b6c2cb9aa..69f73cb5b4cd 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723x.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.c @@ -595,7 +595,8 @@ void __rtw8723x_pwrtrack_set_xtal(struct rtw_dev *rtwdev, u8 therm_path, u8 delta) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; - const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl; + const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev); + const struct rtw_pwr_track_tbl *tbl = rfe_def->pwr_track_tbl; const s8 *pwrtrk_xtal; s8 xtal_cap; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c new file mode 100644 index 000000000000..482edd31823d --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -0,0 +1,1102 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "main.h" +#include "coex.h" +#include "phy.h" +#include "reg.h" +#include "rtw88xxa.h" +#include "rtw8812a.h" +#include "rtw8812a_table.h" +#include "tx.h" + +static void rtw8812a_power_off(struct rtw_dev *rtwdev) +{ + rtw88xxa_power_off(rtwdev, enter_lps_flow_8812a); +} + +static s8 rtw8812a_cck_rx_pwr(u8 lna_idx, u8 vga_idx) +{ + s8 rx_pwr_all = 0; + + switch (lna_idx) { + case 7: + if (vga_idx <= 27) + rx_pwr_all = -94 + 2 * (27 - vga_idx); + else + rx_pwr_all = -94; + break; + case 6: + rx_pwr_all = -42 + 2 * (2 - vga_idx); + break; + case 5: + rx_pwr_all = -36 + 2 * (7 - vga_idx); + break; + case 4: + rx_pwr_all = -30 + 2 * (7 - vga_idx); + break; + case 3: + rx_pwr_all = -18 + 2 * (7 - vga_idx); + break; + case 2: + rx_pwr_all = 2 * (5 - vga_idx); + break; + case 1: + rx_pwr_all = 14 - 2 * vga_idx; + break; + case 0: + rx_pwr_all = 20 - 2 * vga_idx; + break; + default: + break; + } + + return rx_pwr_all; +} + +static void rtw8812a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat) +{ + rtw88xxa_query_phy_status(rtwdev, phy_status, pkt_stat, + rtw8812a_cck_rx_pwr); + + if (pkt_stat->rate >= DESC_RATE6M) + return; + + if (rtwdev->hal.cck_high_power) + return; + + if (pkt_stat->rssi >= 80) + pkt_stat->rssi = ((pkt_stat->rssi - 80) << 1) + + ((pkt_stat->rssi - 80) >> 1) + 80; + else if (pkt_stat->rssi <= 78 && pkt_stat->rssi >= 20) + pkt_stat->rssi += 3; +} + +static void rtw8812a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) +{ +} + +static void rtw8812a_do_lck(struct rtw_dev *rtwdev) +{ + u32 cont_tx, lc_cal, i; + + cont_tx = rtw_read32_mask(rtwdev, REG_SINGLE_TONE_CONT_TX, 0x70000); + + lc_cal = rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK); + + if (!cont_tx) + rtw_write8(rtwdev, REG_TXPAUSE, 0xff); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_LCK, BIT(14), 1); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x08000, 1); + + mdelay(150); + + for (i = 0; i < 5; i++) { + if (rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x08000) != 1) + break; + + mdelay(10); + } + + if (i == 5) + rtw_dbg(rtwdev, RTW_DBG_RFK, "LCK timed out\n"); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_LCK, BIT(14), 0); + + if (!cont_tx) + rtw_write8(rtwdev, REG_TXPAUSE, 0); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal); +} + +static void rtw8812a_iqk_backup_rf(struct rtw_dev *rtwdev, u32 *rfa_backup, + u32 *rfb_backup, const u32 *backup_rf_reg, + u32 rf_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Save RF Parameters */ + for (i = 0; i < rf_num; i++) { + rfa_backup[i] = rtw_read_rf(rtwdev, RF_PATH_A, + backup_rf_reg[i], MASKDWORD); + rfb_backup[i] = rtw_read_rf(rtwdev, RF_PATH_B, + backup_rf_reg[i], MASKDWORD); + } +} + +static void rtw8812a_iqk_restore_rf(struct rtw_dev *rtwdev, + enum rtw_rf_path path, + const u32 *backup_rf_reg, + u32 *RF_backup, u32 rf_reg_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + for (i = 0; i < rf_reg_num; i++) + rtw_write_rf(rtwdev, path, backup_rf_reg[i], + RFREG_MASK, RF_backup[i]); + + rtw_write_rf(rtwdev, path, RF_LUTWE, RFREG_MASK, 0); +} + +static void rtw8812a_iqk_restore_afe(struct rtw_dev *rtwdev, u32 *afe_backup, + const u32 *backup_afe_reg, u32 afe_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Reload AFE Parameters */ + for (i = 0; i < afe_num; i++) + rtw_write32(rtwdev, backup_afe_reg[i], afe_backup[i]); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x0); + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x0); + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x0); + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000); + rtw_write32_mask(rtwdev, REG_LSSI_WRITE_A, BIT(7), 1); + rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(18), 1); + rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(29), 1); + rtw_write32_mask(rtwdev, REG_CFG_PMPD, BIT(29), 1); + + rtw_write32(rtwdev, REG_TXTONEB, 0x0); + rtw_write32(rtwdev, REG_RXTONEB, 0x0); + rtw_write32(rtwdev, REG_TXPITMB, 0x0); + rtw_write32(rtwdev, REG_RXPITMB, 0x3c000000); + rtw_write32_mask(rtwdev, REG_LSSI_WRITE_B, BIT(7), 1); + rtw_write32_mask(rtwdev, REG_BPBDB, BIT(18), 1); + rtw_write32_mask(rtwdev, REG_BPBDB, BIT(29), 1); + rtw_write32_mask(rtwdev, REG_PHYTXONB, BIT(29), 1); +} + +static void rtw8812a_iqk_rx_fill(struct rtw_dev *rtwdev, enum rtw_rf_path path, + unsigned int rx_x, unsigned int rx_y) +{ + switch (path) { + case RF_PATH_A: + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + if (rx_x >> 1 >= 0x112 || + (rx_y >> 1 >= 0x12 && rx_y >> 1 <= 0x3ee)) { + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x000003ff, 0x100); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x03ff0000, 0); + } else { + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x000003ff, rx_x >> 1); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x03ff0000, rx_y >> 1); + } + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x = %x;;rx_y = %x ====>fill to IQC\n", + rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff); + rtw_dbg(rtwdev, RTW_DBG_RFK, "0xc10 = %x ====>fill to IQC\n", + rtw_read32(rtwdev, REG_RX_IQC_AB_A)); + break; + case RF_PATH_B: + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + if (rx_x >> 1 >= 0x112 || + (rx_y >> 1 >= 0x12 && rx_y >> 1 <= 0x3ee)) { + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B, + 0x000003ff, 0x100); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B, + 0x03ff0000, 0); + } else { + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B, + 0x000003ff, rx_x >> 1); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B, + 0x03ff0000, rx_y >> 1); + } + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x = %x;;rx_y = %x ====>fill to IQC\n", + rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff); + rtw_dbg(rtwdev, RTW_DBG_RFK, "0xe10 = %x====>fill to IQC\n", + rtw_read32(rtwdev, REG_RX_IQC_AB_B)); + break; + default: + break; + } +} + +static void rtw8812a_iqk_tx_fill(struct rtw_dev *rtwdev, enum rtw_rf_path path, + unsigned int tx_x, unsigned int tx_y) +{ + switch (path) { + case RF_PATH_A: + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_PREDISTA, BIT(7), 0x1); + rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(18), 0x1); + rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(29), 0x1); + rtw_write32_mask(rtwdev, REG_CFG_PMPD, BIT(29), 0x1); + rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, tx_y); + rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, tx_x); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x = %x;;tx_y = %x =====> fill to IQC\n", + tx_x & 0x000007ff, tx_y & 0x000007ff); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "0xcd4 = %x;;0xccc = %x ====>fill to IQC\n", + rtw_read32_mask(rtwdev, REG_IQC_X, 0x000007ff), + rtw_read32_mask(rtwdev, REG_IQC_Y, 0x000007ff)); + break; + case RF_PATH_B: + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_PREDISTB, BIT(7), 0x1); + rtw_write32_mask(rtwdev, REG_BPBDB, BIT(18), 0x1); + rtw_write32_mask(rtwdev, REG_BPBDB, BIT(29), 0x1); + rtw_write32_mask(rtwdev, REG_PHYTXONB, BIT(29), 0x1); + rtw_write32_mask(rtwdev, REG_IQKYB, 0x000007ff, tx_y); + rtw_write32_mask(rtwdev, REG_IQKXB, 0x000007ff, tx_x); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x = %x;;tx_y = %x =====> fill to IQC\n", + tx_x & 0x000007ff, tx_y & 0x000007ff); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "0xed4 = %x;;0xecc = %x ====>fill to IQC\n", + rtw_read32_mask(rtwdev, REG_IQKXB, 0x000007ff), + rtw_read32_mask(rtwdev, REG_IQKYB, 0x000007ff)); + break; + default: + break; + } +} + +static void rtw8812a_iqk(struct rtw_dev *rtwdev) +{ + int tx_x0_temp[10], tx_y0_temp[10], tx_x1_temp[10], tx_y1_temp[10]; + int rx_x0_temp[10], rx_y0_temp[10], rx_x1_temp[10], rx_y1_temp[10]; + bool iqk0_ready = false, tx0_finish = false, rx0_finish = false; + bool iqk1_ready = false, tx1_finish = false, rx1_finish = false; + u8 tx0_avg = 0, tx1_avg = 0, rx0_avg = 0, rx1_avg = 0; + int tx_x0 = 0, tx_y0 = 0, tx_x1 = 0, tx_y1 = 0; + int rx_x0 = 0, rx_y0 = 0, rx_x1 = 0, rx_y1 = 0; + struct rtw_efuse *efuse = &rtwdev->efuse; + bool tx0_fail = true, rx0_fail = true; + bool tx1_fail = true, rx1_fail = true; + u8 cal0_retry, cal1_retry; + u8 delay_count; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* ========path-A AFE all on======== */ + /* Port 0 DAC/ADC on */ + rtw_write32(rtwdev, REG_AFE_PWR1_A, 0x77777777); + rtw_write32(rtwdev, REG_AFE_PWR2_A, 0x77777777); + + /* Port 1 DAC/ADC on */ + rtw_write32(rtwdev, REG_AFE_PWR1_B, 0x77777777); + rtw_write32(rtwdev, REG_AFE_PWR2_B, 0x77777777); + + rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_A, 0x19791979); + rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_B, 0x19791979); + + /* hardware 3-wire off */ + rtw_write32_mask(rtwdev, REG_3WIRE_SWA, 0xf, 0x4); + rtw_write32_mask(rtwdev, REG_3WIRE_SWB, 0xf, 0x4); + + /* DAC/ADC sampling rate (160 MHz) */ + rtw_write32_mask(rtwdev, REG_CK_MONHA, GENMASK(26, 24), 0x7); + rtw_write32_mask(rtwdev, REG_CK_MONHB, GENMASK(26, 24), 0x7); + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + /* ====== path A TX IQK RF setting ====== */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80002); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x20000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x3fffd); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xfe83f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d5); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001); + + /* ====== path B TX IQK RF setting ====== */ + rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x80002); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x20000); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x3fffd); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xfe83f); + rtw_write_rf(rtwdev, RF_PATH_B, RF_TXA_PREPAD, RFREG_MASK, 0x931d5); + rtw_write_rf(rtwdev, RF_PATH_B, RF_RXBB2, RFREG_MASK, 0x8a001); + + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1); + rtw_write32_mask(rtwdev, REG_INIDLYB, BIT(0), 0x1); + rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000); /* TX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000); /* RX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM96, 0x00462910); /* [0]:AGC_en, [15]:idac_K_Mask */ + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + if (efuse->ext_pa_5g) { + if (efuse->rfe_option == 1) { + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403e3); + rtw_write32(rtwdev, REG_TXPITMB, 0x821403e3); + } else { + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403f7); + rtw_write32(rtwdev, REG_TXPITMB, 0x821403f7); + } + } else { + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403f1); + rtw_write32(rtwdev, REG_TXPITMB, 0x821403f1); + } + + if (rtwdev->hal.current_band_type == RTW_BAND_5G) { + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x68163e96); + rtw_write32(rtwdev, REG_RXPITMB, 0x68163e96); + } else { + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28163e96); + rtw_write32(rtwdev, REG_RXPITMB, 0x28163e96); + + if (efuse->rfe_option == 3) { + if (efuse->ext_pa_2g) + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403e3); + else + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403f7); + } + } + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10); + rtw_write32(rtwdev, REG_INTPO_SETA, 0x00000000); + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_TXTONEB, 0x18008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_RXTONEB, 0x38008c10); + rtw_write32(rtwdev, REG_INTPO_SETB, 0x00000000); + + cal0_retry = 0; + cal1_retry = 0; + while (1) { + /* one shot */ + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00100000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00000000); + + for (delay_count = 0; delay_count < 20; delay_count++) { + if (!tx0_finish) + iqk0_ready = rtw_read32_mask(rtwdev, + REG_IQKA_END, + BIT(10)); + if (!tx1_finish) + iqk1_ready = rtw_read32_mask(rtwdev, + REG_IQKB_END, + BIT(10)); + if (iqk0_ready && iqk1_ready) + break; + + mdelay(1); + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "TX delay_count = %d\n", + delay_count); + + if (delay_count < 20) { /* If 20ms No Result, then cal_retry++ */ + /* ============TXIQK Check============== */ + tx0_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(12)); + tx1_fail = rtw_read32_mask(rtwdev, REG_IQKB_END, BIT(12)); + + if (!(tx0_fail || tx0_finish)) { + rtw_write32(rtwdev, REG_RFECTL_A, 0x02000000); + tx_x0_temp[tx0_avg] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x04000000); + tx_y0_temp[tx0_avg] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x0[%d] = %x ;; tx_y0[%d] = %x\n", + tx0_avg, tx_x0_temp[tx0_avg], + tx0_avg, tx_y0_temp[tx0_avg]); + + tx_x0_temp[tx0_avg] <<= 21; + tx_y0_temp[tx0_avg] <<= 21; + + tx0_avg++; + } else { + cal0_retry++; + if (cal0_retry == 10) + break; + } + + if (!(tx1_fail || tx1_finish)) { + rtw_write32(rtwdev, REG_RFECTL_B, 0x02000000); + tx_x1_temp[tx1_avg] = rtw_read32_mask(rtwdev, + REG_IQKB_END, + 0x07ff0000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x04000000); + tx_y1_temp[tx1_avg] = rtw_read32_mask(rtwdev, + REG_IQKB_END, + 0x07ff0000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x1[%d] = %x ;; tx_y1[%d] = %x\n", + tx1_avg, tx_x1_temp[tx1_avg], + tx1_avg, tx_y1_temp[tx1_avg]); + + tx_x1_temp[tx1_avg] <<= 21; + tx_y1_temp[tx1_avg] <<= 21; + + tx1_avg++; + } else { + cal1_retry++; + if (cal1_retry == 10) + break; + } + } else { + cal0_retry++; + cal1_retry++; + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "delay 20ms TX IQK Not Ready!!!!!\n"); + + if (cal0_retry == 10) + break; + } + + if (tx0_avg >= 2) + tx0_finish = rtw88xxa_iqk_finish(tx0_avg, 4, + tx_x0_temp, tx_y0_temp, &tx_x0, &tx_y0, + false, false); + + if (tx1_avg >= 2) + tx1_finish = rtw88xxa_iqk_finish(tx1_avg, 4, + tx_x1_temp, tx_y1_temp, &tx_x1, &tx_y1, + false, false); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx0_average = %d, tx1_average = %d\n", + tx0_avg, tx1_avg); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx0_finish = %d, tx1_finish = %d\n", + tx0_finish, tx1_finish); + + if (tx0_finish && tx1_finish) + break; + + if ((cal0_retry + tx0_avg) >= 10 || + (cal1_retry + tx1_avg) >= 10) + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "TXA_cal_retry = %d\n", cal0_retry); + rtw_dbg(rtwdev, RTW_DBG_RFK, "TXB_cal_retry = %d\n", cal1_retry); + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + /* Load LOK */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXMOD, 0x7fe00, + rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, 0xffc00)); + rtw_write_rf(rtwdev, RF_PATH_B, RF_TXMOD, 0x7fe00, + rtw_read_rf(rtwdev, RF_PATH_B, RF_DTXLOK, 0xffc00)); + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + if (tx0_finish) { + /* ====== path A RX IQK RF setting====== */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x30000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x3f7ff); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xfe7bf); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x88001); + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d1); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000); + } + if (tx1_finish) { + /* ====== path B RX IQK RF setting====== */ + rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x30000); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x3f7ff); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xfe7bf); + rtw_write_rf(rtwdev, RF_PATH_B, RF_RXBB2, RFREG_MASK, 0x88001); + rtw_write_rf(rtwdev, RF_PATH_B, RF_TXA_PREPAD, RFREG_MASK, 0x931d1); + rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x00000); + } + + rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x0); + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + + if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE) + rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a911); + else + rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a890); + + if (efuse->rfe_option == 1) { + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777717); + rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777717); + rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077); + } else { + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777717); + rtw_write32(rtwdev, REG_RFE_INV_A, 0x02000077); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777717); + rtw_write32(rtwdev, REG_RFE_INV_B, 0x02000077); + } + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + if (tx0_finish) { + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x38008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x18008c10); + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x82140119); + } + if (tx1_finish) { + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_TXTONEB, 0x38008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_RXTONEB, 0x18008c10); + rtw_write32(rtwdev, REG_TXPITMB, 0x82140119); + } + + cal0_retry = 0; + cal1_retry = 0; + while (1) { + /* one shot */ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + if (tx0_finish) { + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000, + tx_x0 & 0x000007ff); + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF, + tx_y0 & 0x000007ff); + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + if (efuse->rfe_option == 1) + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28161500); + else + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28160cc0); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00300000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + mdelay(5); + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + } + + if (tx1_finish) { + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000, + tx_x1 & 0x000007ff); + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF, + tx_y1 & 0x000007ff); + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + if (efuse->rfe_option == 1) + rtw_write32(rtwdev, REG_RXPITMB, 0x28161500); + else + rtw_write32(rtwdev, REG_RXPITMB, 0x28160ca0); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00300000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00100000); + mdelay(5); + rtw_write32(rtwdev, REG_RXPITMB, 0x3c000000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00000000); + } + + for (delay_count = 0; delay_count < 20; delay_count++) { + if (!rx0_finish && tx0_finish) + iqk0_ready = rtw_read32_mask(rtwdev, + REG_IQKA_END, + BIT(10)); + if (!rx1_finish && tx1_finish) + iqk1_ready = rtw_read32_mask(rtwdev, + REG_IQKB_END, + BIT(10)); + if (iqk0_ready && iqk1_ready) + break; + + mdelay(1); + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "RX delay_count = %d\n", + delay_count); + + if (delay_count < 20) { /* If 20ms No Result, then cal_retry++ */ + /* ============RXIQK Check============== */ + rx0_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(11)); + rx1_fail = rtw_read32_mask(rtwdev, REG_IQKB_END, BIT(11)); + + if (!(rx0_fail || rx0_finish) && tx0_finish) { + rtw_write32(rtwdev, REG_RFECTL_A, 0x06000000); + rx_x0_temp[rx0_avg] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x08000000); + rx_y0_temp[rx0_avg] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x0[%d] = %x ;; rx_y0[%d] = %x\n", + rx0_avg, rx_x0_temp[rx0_avg], + rx0_avg, rx_y0_temp[rx0_avg]); + + rx_x0_temp[rx0_avg] <<= 21; + rx_y0_temp[rx0_avg] <<= 21; + + rx0_avg++; + } else { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "1. RXA_cal_retry = %d\n", cal0_retry); + + cal0_retry++; + if (cal0_retry == 10) + break; + } + + if (!(rx1_fail || rx1_finish) && tx1_finish) { + rtw_write32(rtwdev, REG_RFECTL_B, 0x06000000); + rx_x1_temp[rx1_avg] = rtw_read32_mask(rtwdev, + REG_IQKB_END, + 0x07ff0000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x08000000); + rx_y1_temp[rx1_avg] = rtw_read32_mask(rtwdev, + REG_IQKB_END, + 0x07ff0000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x1[%d] = %x ;; rx_y1[%d] = %x\n", + rx1_avg, rx_x1_temp[rx1_avg], + rx1_avg, rx_y1_temp[rx1_avg]); + + rx_x1_temp[rx1_avg] <<= 21; + rx_y1_temp[rx1_avg] <<= 21; + + rx1_avg++; + } else { + cal1_retry++; + if (cal1_retry == 10) + break; + } + } else { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "2. RXA_cal_retry = %d\n", cal0_retry); + + cal0_retry++; + cal1_retry++; + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "delay 20ms RX IQK Not Ready!!!!!\n"); + + if (cal0_retry == 10) + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "3. RXA_cal_retry = %d\n", + cal0_retry); + + if (rx0_avg >= 2) + rx0_finish = rtw88xxa_iqk_finish(rx0_avg, 4, + rx_x0_temp, rx_y0_temp, + &rx_x0, &rx_y0, + true, false); + + if (rx1_avg >= 2) + rx1_finish = rtw88xxa_iqk_finish(rx1_avg, 4, + rx_x1_temp, rx_y1_temp, + &rx_x1, &rx_y1, + true, false); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx0_average = %d, rx1_average = %d\n", + rx0_avg, rx1_avg); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx0_finish = %d, rx1_finish = %d\n", + rx0_finish, rx1_finish); + + if ((rx0_finish || !tx0_finish) && (rx1_finish || !tx1_finish)) + break; + + if ((cal0_retry + rx0_avg) >= 10 || + (cal1_retry + rx1_avg) >= 10 || + rx0_avg == 3 || rx1_avg == 3) + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "RXA_cal_retry = %d\n", cal0_retry); + rtw_dbg(rtwdev, RTW_DBG_RFK, "RXB_cal_retry = %d\n", cal1_retry); + + /* FillIQK Result */ + rtw_dbg(rtwdev, RTW_DBG_RFK, "========Path_A =======\n"); + + if (tx0_finish) + rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_A, tx_x0, tx_y0); + else + rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_A, 0x200, 0x0); + + if (rx0_finish) + rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_A, rx_x0, rx_y0); + else + rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_A, 0x200, 0x0); + + rtw_dbg(rtwdev, RTW_DBG_RFK, "========Path_B =======\n"); + + if (tx1_finish) + rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_B, tx_x1, tx_y1); + else + rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_B, 0x200, 0x0); + + if (rx1_finish) + rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_B, rx_x1, rx_y1); + else + rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_B, 0x200, 0x0); +} + +#define MACBB_REG_NUM_8812A 9 +#define AFE_REG_NUM_8812A 12 +#define RF_REG_NUM_8812A 3 + +static void rtw8812a_do_iqk(struct rtw_dev *rtwdev) +{ + static const u32 backup_macbb_reg[MACBB_REG_NUM_8812A] = { + 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0xe00, 0x838, 0x82c + }; + static const u32 backup_afe_reg[AFE_REG_NUM_8812A] = { + 0xc5c, 0xc60, 0xc64, 0xc68, 0xcb0, 0xcb4, + 0xe5c, 0xe60, 0xe64, 0xe68, 0xeb0, 0xeb4 + }; + static const u32 backup_rf_reg[RF_REG_NUM_8812A] = { + 0x65, 0x8f, 0x0 + }; + u32 macbb_backup[MACBB_REG_NUM_8812A] = {}; + u32 afe_backup[AFE_REG_NUM_8812A] = {}; + u32 rfa_backup[RF_REG_NUM_8812A] = {}; + u32 rfb_backup[RF_REG_NUM_8812A] = {}; + u32 reg_cb8, reg_eb8; + + rtw88xxa_iqk_backup_mac_bb(rtwdev, macbb_backup, + backup_macbb_reg, MACBB_REG_NUM_8812A); + + rtw_write32_set(rtwdev, REG_CCASEL, BIT(31)); + reg_cb8 = rtw_read32(rtwdev, REG_RFECTL_A); + reg_eb8 = rtw_read32(rtwdev, REG_RFECTL_B); + rtw_write32_clr(rtwdev, REG_CCASEL, BIT(31)); + + rtw88xxa_iqk_backup_afe(rtwdev, afe_backup, + backup_afe_reg, AFE_REG_NUM_8812A); + rtw8812a_iqk_backup_rf(rtwdev, rfa_backup, rfb_backup, + backup_rf_reg, RF_REG_NUM_8812A); + + rtw88xxa_iqk_configure_mac(rtwdev); + + rtw8812a_iqk(rtwdev); + + rtw8812a_iqk_restore_rf(rtwdev, RF_PATH_A, backup_rf_reg, + rfa_backup, RF_REG_NUM_8812A); + rtw8812a_iqk_restore_rf(rtwdev, RF_PATH_B, backup_rf_reg, + rfb_backup, RF_REG_NUM_8812A); + + rtw8812a_iqk_restore_afe(rtwdev, afe_backup, + backup_afe_reg, AFE_REG_NUM_8812A); + + rtw_write32_set(rtwdev, REG_CCASEL, BIT(31)); + rtw_write32(rtwdev, REG_RFECTL_A, reg_cb8); + rtw_write32(rtwdev, REG_RFECTL_B, reg_eb8); + rtw_write32_clr(rtwdev, REG_CCASEL, BIT(31)); + + rtw88xxa_iqk_restore_mac_bb(rtwdev, macbb_backup, + backup_macbb_reg, MACBB_REG_NUM_8812A); +} + +static void rtw8812a_phy_calibration(struct rtw_dev *rtwdev) +{ + u8 channel = rtwdev->hal.current_channel; + + rtw8812a_do_iqk(rtwdev); + + /* The official driver wants to do this after connecting + * but before first writing a new igi (phydm_get_new_igi). + * Here seems close enough. + */ + if (channel >= 36 && channel <= 64) + rtw_load_table(rtwdev, &rtw8812a_agc_diff_lb_tbl); + else if (channel >= 100) + rtw_load_table(rtwdev, &rtw8812a_agc_diff_hb_tbl); +} + +static void rtw8812a_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + if (!dm_info->pwr_trk_triggered) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, + GENMASK(17, 16), 0x03); + dm_info->pwr_trk_triggered = true; + return; + } + + rtw88xxa_phy_pwrtrack(rtwdev, rtw8812a_do_lck, rtw8812a_do_iqk); + dm_info->pwr_trk_triggered = false; +} + +static void rtw8812a_fill_txdesc_checksum(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + u8 *txdesc) +{ + fill_txdesc_checksum_common(txdesc, 16); +} + +static void rtw8812a_coex_cfg_init(struct rtw_dev *rtwdev) +{ +} + +static void rtw8812a_coex_cfg_gnt_fix(struct rtw_dev *rtwdev) +{ +} + +static void rtw8821a_coex_cfg_rfe_type(struct rtw_dev *rtwdev) +{ +} + +static void rtw8821a_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr) +{ +} + +static void rtw8821a_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) +{ +} + +static const struct rtw_chip_ops rtw8812a_ops = { + .power_on = rtw88xxa_power_on, + .power_off = rtw8812a_power_off, + .phy_set_param = NULL, + .read_efuse = rtw88xxa_read_efuse, + .query_phy_status = rtw8812a_query_phy_status, + .set_channel = rtw88xxa_set_channel, + .mac_init = NULL, + .read_rf = rtw88xxa_phy_read_rf, + .write_rf = rtw_phy_write_rf_reg_sipi, + .set_antenna = NULL, + .set_tx_power_index = rtw88xxa_set_tx_power_index, + .cfg_ldo25 = rtw8812a_cfg_ldo25, + .efuse_grant = rtw88xxa_efuse_grant, + .false_alarm_statistics = rtw88xxa_false_alarm_statistics, + .phy_calibration = rtw8812a_phy_calibration, + .cck_pd_set = rtw88xxa_phy_cck_pd_set, + .pwr_track = rtw8812a_pwr_track, + .config_bfee = NULL, + .set_gid_table = NULL, + .cfg_csi_rate = NULL, + .fill_txdesc_checksum = rtw8812a_fill_txdesc_checksum, + .coex_set_init = rtw8812a_coex_cfg_init, + .coex_set_ant_switch = NULL, + .coex_set_gnt_fix = rtw8812a_coex_cfg_gnt_fix, + .coex_set_gnt_debug = NULL, + .coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type, + .coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power, + .coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain, +}; + +static const struct rtw_page_table page_table_8812a[] = { + /* hq_num, nq_num, lq_num, exq_num, gapq_num */ + {0, 0, 0, 0, 0}, /* SDIO */ + {0, 0, 0, 0, 0}, /* PCI */ + {16, 0, 0, 0, 1}, /* 2 bulk out endpoints */ + {16, 0, 16, 0, 1}, /* 3 bulk out endpoints */ + {16, 0, 16, 0, 1}, /* 4 bulk out endpoints */ +}; + +static const struct rtw_rqpn rqpn_table_8812a[] = { + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH, + RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, +}; + +static const struct rtw_prioq_addrs prioq_addrs_8812a = { + .prio[RTW_DMA_MAPPING_EXTRA] = { + .rsvd = REG_RQPN_NPQ + 2, .avail = REG_RQPN_NPQ + 3, + }, + .prio[RTW_DMA_MAPPING_LOW] = { + .rsvd = REG_RQPN + 1, .avail = REG_FIFOPAGE_CTRL_2 + 1, + }, + .prio[RTW_DMA_MAPPING_NORMAL] = { + .rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1, + }, + .prio[RTW_DMA_MAPPING_HIGH] = { + .rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2, + }, + .wsize = false, +}; + +static const struct rtw_hw_reg rtw8812a_dig[] = { + [0] = { .addr = REG_RXIGI_A, .mask = 0x7f }, + [1] = { .addr = REG_RXIGI_B, .mask = 0x7f }, +}; + +static const struct rtw_rfe_def rtw8812a_rfe_defs[] = { + [0] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8812a_rtw_pwr_track_tbl, }, + [1] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8812a_rtw_pwr_track_tbl, }, + [3] = { .phy_pg_tbl = &rtw8812a_bb_pg_rfe3_tbl, + .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8812a_rtw_pwr_track_rfe3_tbl, }, +}; + +static const u8 wl_rssi_step_8812a[] = {101, 45, 101, 40}; +static const u8 bt_rssi_step_8812a[] = {101, 101, 101, 101}; + +static const struct coex_rf_para rf_para_tx_8812a[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {8, 17, true, 4}, + {7, 18, true, 4}, + {6, 19, true, 4}, + {5, 20, true, 4} +}; + +static const struct coex_rf_para rf_para_rx_8812a[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {3, 24, true, 5}, + {2, 26, true, 5}, + {1, 27, true, 5}, + {0, 28, true, 5} +}; + +static_assert(ARRAY_SIZE(rf_para_tx_8812a) == ARRAY_SIZE(rf_para_rx_8812a)); + +const struct rtw_chip_info rtw8812a_hw_spec = { + .ops = &rtw8812a_ops, + .id = RTW_CHIP_TYPE_8812A, + .fw_name = "rtw88/rtw8812a_fw.bin", + .wlan_cpu = RTW_WCPU_11N, + .tx_pkt_desc_sz = 40, + .tx_buf_desc_sz = 16, + .rx_pkt_desc_sz = 24, + .rx_buf_desc_sz = 8, + .phy_efuse_size = 512, + .log_efuse_size = 512, + .ptct_efuse_size = 96 + 1, /* TODO or just 18? */ + .txff_size = 131072, + .rxff_size = 16128, + .rsvd_drv_pg_num = 9, + .txgi_factor = 1, + .is_pwr_by_rate_dec = true, + .max_power_index = 0x3f, + .csi_buf_pg_num = 0, + .band = RTW_BAND_2G | RTW_BAND_5G, + .page_size = 512, + .dig_min = 0x20, + .ht_supported = true, + .vht_supported = true, + .lps_deep_mode_supported = 0, + .sys_func_en = 0xFD, + .pwr_on_seq = card_enable_flow_8812a, + .pwr_off_seq = card_disable_flow_8812a, + .page_table = page_table_8812a, + .rqpn_table = rqpn_table_8812a, + .prioq_addrs = &prioq_addrs_8812a, + .intf_table = NULL, + .dig = rtw8812a_dig, + .rf_sipi_addr = {REG_LSSI_WRITE_A, REG_LSSI_WRITE_B}, + .ltecoex_addr = NULL, + .mac_tbl = &rtw8812a_mac_tbl, + .agc_tbl = &rtw8812a_agc_tbl, + .bb_tbl = &rtw8812a_bb_tbl, + .rf_tbl = {&rtw8812a_rf_a_tbl, &rtw8812a_rf_b_tbl}, + .rfe_defs = rtw8812a_rfe_defs, + .rfe_defs_size = ARRAY_SIZE(rtw8812a_rfe_defs), + .rx_ldpc = false, + .hw_feature_report = false, + .c2h_ra_report_size = 4, + .old_datarate_fb_limit = true, + .usb_tx_agg_desc_num = 1, + .iqk_threshold = 8, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, + + .coex_para_ver = 0, /* no coex code in 8812au driver */ + .bt_desired_ver = 0, + .scbd_support = false, + .new_scbd10_def = false, + .ble_hid_profile_support = false, + .wl_mimo_ps_support = false, + .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, + .bt_rssi_type = COEX_BTRSSI_RATIO, + .ant_isolation = 15, + .rssi_tolerance = 2, + .wl_rssi_step = wl_rssi_step_8812a, + .bt_rssi_step = bt_rssi_step_8812a, + .table_sant_num = 0, + .table_sant = NULL, + .table_nsant_num = 0, + .table_nsant = NULL, + .tdma_sant_num = 0, + .tdma_sant = NULL, + .tdma_nsant_num = 0, + .tdma_nsant = NULL, + .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8812a), + .wl_rf_para_tx = rf_para_tx_8812a, + .wl_rf_para_rx = rf_para_rx_8812a, + .bt_afh_span_bw20 = 0x20, + .bt_afh_span_bw40 = 0x30, + .afh_5g_num = 0, + .afh_5g = NULL, + .coex_info_hw_regs_num = 0, + .coex_info_hw_regs = NULL, +}; +EXPORT_SYMBOL(rtw8812a_hw_spec); + +MODULE_FIRMWARE("rtw88/rtw8812a_fw.bin"); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8812a driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.h b/drivers/net/wireless/realtek/rtw88/rtw8812a.h new file mode 100644 index 000000000000..82dab59e341d --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW8812A_H__ +#define __RTW8812A_H__ + +extern const struct rtw_chip_info rtw8812a_hw_spec; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c new file mode 100644 index 000000000000..048efbbd49ed --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c @@ -0,0 +1,2812 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "main.h" +#include "phy.h" +#include "rtw8812a_table.h" + +static const u32 rtw8812a_mac[] = { + 0x010, 0x0000000C, + 0x80000200, 0x00000000, 0x40000000, 0x00000000, + 0x011, 0x00000066, + 0xA0000000, 0x00000000, + 0x011, 0x0000005A, + 0xB0000000, 0x00000000, + 0x025, 0x0000000F, + 0x072, 0x00000000, + 0x420, 0x00000080, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000002, + 0x435, 0x00000003, + 0x436, 0x00000005, + 0x437, 0x00000007, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43A, 0x00000000, + 0x43B, 0x00000001, + 0x43C, 0x00000002, + 0x43D, 0x00000003, + 0x43E, 0x00000005, + 0x43F, 0x00000007, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000010, + 0x445, 0x00000000, + 0x446, 0x00000000, + 0x447, 0x00000000, + 0x448, 0x00000000, + 0x449, 0x000000F0, + 0x44A, 0x0000000F, + 0x44B, 0x0000003E, + 0x44C, 0x00000010, + 0x44D, 0x00000000, + 0x44E, 0x00000000, + 0x44F, 0x00000000, + 0x450, 0x00000000, + 0x451, 0x000000F0, + 0x452, 0x0000000F, + 0x453, 0x00000000, + 0x45B, 0x00000080, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55C, 0x00000050, + 0x55D, 0x000000FF, + 0x604, 0x00000009, + 0x605, 0x00000030, + 0x607, 0x00000003, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x638, 0x00000050, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000080, + 0x642, 0x00000040, + 0x643, 0x00000000, + 0x652, 0x000000C8, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + 0x718, 0x00000040, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_mac, rtw_phy_cfg_mac); + +static const u32 rtw8812a_agc[] = { + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFC000001, + 0x81C, 0xFB020001, + 0x81C, 0xFA040001, + 0x81C, 0xF9060001, + 0x81C, 0xF8080001, + 0x81C, 0xF70A0001, + 0x81C, 0xF60C0001, + 0x81C, 0xF50E0001, + 0x81C, 0xF4100001, + 0x81C, 0xF3120001, + 0x81C, 0xF2140001, + 0x81C, 0xF1160001, + 0x81C, 0xF0180001, + 0x81C, 0xEF1A0001, + 0x81C, 0xEE1C0001, + 0x81C, 0xED1E0001, + 0x81C, 0xEC200001, + 0x81C, 0xEB220001, + 0x81C, 0xEA240001, + 0x81C, 0xCD260001, + 0x81C, 0xCC280001, + 0x81C, 0xCB2A0001, + 0x81C, 0xCA2C0001, + 0x81C, 0xC92E0001, + 0x81C, 0xC8300001, + 0x81C, 0xA6320001, + 0x81C, 0xA5340001, + 0x81C, 0xA4360001, + 0x81C, 0xA3380001, + 0x81C, 0xA23A0001, + 0x81C, 0x883C0001, + 0x81C, 0x873E0001, + 0x81C, 0x86400001, + 0x81C, 0x85420001, + 0x81C, 0x84440001, + 0x81C, 0x83460001, + 0x81C, 0x82480001, + 0x81C, 0x814A0001, + 0x81C, 0x484C0001, + 0x81C, 0x474E0001, + 0x81C, 0x46500001, + 0x81C, 0x45520001, + 0x81C, 0x44540001, + 0x81C, 0x43560001, + 0x81C, 0x42580001, + 0x81C, 0x415A0001, + 0x81C, 0x255C0001, + 0x81C, 0x245E0001, + 0x81C, 0x23600001, + 0x81C, 0x22620001, + 0x81C, 0x21640001, + 0x81C, 0x21660001, + 0x81C, 0x21680001, + 0x81C, 0x216A0001, + 0x81C, 0x216C0001, + 0x81C, 0x216E0001, + 0x81C, 0x21700001, + 0x81C, 0x21720001, + 0x81C, 0x21740001, + 0x81C, 0x21760001, + 0x81C, 0x21780001, + 0x81C, 0x217A0001, + 0x81C, 0x217C0001, + 0x81C, 0x217E0001, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x81C, 0xF9000001, + 0x81C, 0xF8020001, + 0x81C, 0xF7040001, + 0x81C, 0xF6060001, + 0x81C, 0xF5080001, + 0x81C, 0xF40A0001, + 0x81C, 0xF30C0001, + 0x81C, 0xF20E0001, + 0x81C, 0xF1100001, + 0x81C, 0xF0120001, + 0x81C, 0xEF140001, + 0x81C, 0xEE160001, + 0x81C, 0xED180001, + 0x81C, 0xEC1A0001, + 0x81C, 0xEB1C0001, + 0x81C, 0xEA1E0001, + 0x81C, 0xCD200001, + 0x81C, 0xCC220001, + 0x81C, 0xCB240001, + 0x81C, 0xCA260001, + 0x81C, 0xC9280001, + 0x81C, 0xC82A0001, + 0x81C, 0xC72C0001, + 0x81C, 0xC62E0001, + 0x81C, 0xA5300001, + 0x81C, 0xA4320001, + 0x81C, 0xA3340001, + 0x81C, 0xA2360001, + 0x81C, 0x88380001, + 0x81C, 0x873A0001, + 0x81C, 0x863C0001, + 0x81C, 0x853E0001, + 0x81C, 0x84400001, + 0x81C, 0x83420001, + 0x81C, 0x82440001, + 0x81C, 0x81460001, + 0x81C, 0x48480001, + 0x81C, 0x474A0001, + 0x81C, 0x464C0001, + 0x81C, 0x454E0001, + 0x81C, 0x44500001, + 0x81C, 0x43520001, + 0x81C, 0x42540001, + 0x81C, 0x41560001, + 0x81C, 0x25580001, + 0x81C, 0x245A0001, + 0x81C, 0x235C0001, + 0x81C, 0x225E0001, + 0x81C, 0x21600001, + 0x81C, 0x21620001, + 0x81C, 0x21640001, + 0x81C, 0x21660001, + 0x81C, 0x21680001, + 0x81C, 0x216A0001, + 0x81C, 0x236C0001, + 0x81C, 0x226E0001, + 0x81C, 0x21700001, + 0x81C, 0x21720001, + 0x81C, 0x21740001, + 0x81C, 0x21760001, + 0x81C, 0x21780001, + 0x81C, 0x217A0001, + 0x81C, 0x217C0001, + 0x81C, 0x217E0001, + 0xA0000000, 0x00000000, + 0x81C, 0xFF000001, + 0x81C, 0xFF020001, + 0x81C, 0xFF040001, + 0x81C, 0xFF060001, + 0x81C, 0xFF080001, + 0x81C, 0xFE0A0001, + 0x81C, 0xFD0C0001, + 0x81C, 0xFC0E0001, + 0x81C, 0xFB100001, + 0x81C, 0xFA120001, + 0x81C, 0xF9140001, + 0x81C, 0xF8160001, + 0x81C, 0xF7180001, + 0x81C, 0xF61A0001, + 0x81C, 0xF51C0001, + 0x81C, 0xF41E0001, + 0x81C, 0xF3200001, + 0x81C, 0xF2220001, + 0x81C, 0xF1240001, + 0x81C, 0xF0260001, + 0x81C, 0xEF280001, + 0x81C, 0xEE2A0001, + 0x81C, 0xED2C0001, + 0x81C, 0xEC2E0001, + 0x81C, 0xEB300001, + 0x81C, 0xEA320001, + 0x81C, 0xE9340001, + 0x81C, 0xE8360001, + 0x81C, 0xE7380001, + 0x81C, 0xE63A0001, + 0x81C, 0xE53C0001, + 0x81C, 0xC73E0001, + 0x81C, 0xC6400001, + 0x81C, 0xC5420001, + 0x81C, 0xC4440001, + 0x81C, 0xC3460001, + 0x81C, 0xC2480001, + 0x81C, 0xC14A0001, + 0x81C, 0xA74C0001, + 0x81C, 0xA64E0001, + 0x81C, 0xA5500001, + 0x81C, 0xA4520001, + 0x81C, 0xA3540001, + 0x81C, 0xA2560001, + 0x81C, 0xA1580001, + 0x81C, 0x675A0001, + 0x81C, 0x665C0001, + 0x81C, 0x655E0001, + 0x81C, 0x64600001, + 0x81C, 0x63620001, + 0x81C, 0x48640001, + 0x81C, 0x47660001, + 0x81C, 0x46680001, + 0x81C, 0x456A0001, + 0x81C, 0x446C0001, + 0x81C, 0x436E0001, + 0x81C, 0x42700001, + 0x81C, 0x41720001, + 0x81C, 0x41740001, + 0x81C, 0x41760001, + 0x81C, 0x41780001, + 0x81C, 0x417A0001, + 0x81C, 0x417C0001, + 0x81C, 0x417E0001, + 0xB0000000, 0x00000000, + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFC800001, + 0x81C, 0xFB820001, + 0x81C, 0xFA840001, + 0x81C, 0xF9860001, + 0x81C, 0xF8880001, + 0x81C, 0xF78A0001, + 0x81C, 0xF68C0001, + 0x81C, 0xF58E0001, + 0x81C, 0xF4900001, + 0x81C, 0xF3920001, + 0x81C, 0xF2940001, + 0x81C, 0xF1960001, + 0x81C, 0xF0980001, + 0x81C, 0xEF9A0001, + 0x81C, 0xEE9C0001, + 0x81C, 0xED9E0001, + 0x81C, 0xECA00001, + 0x81C, 0xEBA20001, + 0x81C, 0xEAA40001, + 0x81C, 0xE9A60001, + 0x81C, 0xE8A80001, + 0x81C, 0xE7AA0001, + 0x81C, 0xE6AC0001, + 0x81C, 0xE5AE0001, + 0x81C, 0xE4B00001, + 0x81C, 0xE3B20001, + 0x81C, 0xA8B40001, + 0x81C, 0xA7B60001, + 0x81C, 0xA6B80001, + 0x81C, 0xA5BA0001, + 0x81C, 0xA4BC0001, + 0x81C, 0xA3BE0001, + 0x81C, 0xA2C00001, + 0x81C, 0xA1C20001, + 0x81C, 0x68C40001, + 0x81C, 0x67C60001, + 0x81C, 0x66C80001, + 0x81C, 0x65CA0001, + 0x81C, 0x64CC0001, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0x81C, 0x01E80001, + 0x81C, 0x01EA0001, + 0x81C, 0x01EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xA0000000, 0x00000000, + 0x81C, 0xFF800001, + 0x81C, 0xFF820001, + 0x81C, 0xFF840001, + 0x81C, 0xFE860001, + 0x81C, 0xFD880001, + 0x81C, 0xFC8A0001, + 0x81C, 0xFB8C0001, + 0x81C, 0xFA8E0001, + 0x81C, 0xF9900001, + 0x81C, 0xF8920001, + 0x81C, 0xF7940001, + 0x81C, 0xF6960001, + 0x81C, 0xF5980001, + 0x81C, 0xF49A0001, + 0x81C, 0xF39C0001, + 0x81C, 0xF29E0001, + 0x81C, 0xF1A00001, + 0x81C, 0xF0A20001, + 0x81C, 0xEFA40001, + 0x81C, 0xEEA60001, + 0x81C, 0xEDA80001, + 0x81C, 0xECAA0001, + 0x81C, 0xEBAC0001, + 0x81C, 0xEAAE0001, + 0x81C, 0xE9B00001, + 0x81C, 0xE8B20001, + 0x81C, 0xE7B40001, + 0x81C, 0xE6B60001, + 0x81C, 0xE5B80001, + 0x81C, 0xE4BA0001, + 0x81C, 0xE3BC0001, + 0x81C, 0xA8BE0001, + 0x81C, 0xA7C00001, + 0x81C, 0xA6C20001, + 0x81C, 0xA5C40001, + 0x81C, 0xA4C60001, + 0x81C, 0xA3C80001, + 0x81C, 0xA2CA0001, + 0x81C, 0xA1CC0001, + 0x81C, 0x68CE0001, + 0x81C, 0x67D00001, + 0x81C, 0x66D20001, + 0x81C, 0x65D40001, + 0x81C, 0x64D60001, + 0x81C, 0x47D80001, + 0x81C, 0x46DA0001, + 0x81C, 0x45DC0001, + 0x81C, 0x44DE0001, + 0x81C, 0x43E00001, + 0x81C, 0x42E20001, + 0x81C, 0x08E40001, + 0x81C, 0x07E60001, + 0x81C, 0x06E80001, + 0x81C, 0x05EA0001, + 0x81C, 0x04EC0001, + 0x81C, 0x03EE0001, + 0x81C, 0x02F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xB0000000, 0x00000000, + 0xC50, 0x00000022, + 0xC50, 0x00000020, + 0xE50, 0x00000022, + 0xE50, 0x00000020, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_agc, rtw_phy_cfg_agc); + +static const u32 rtw8812a_agc_diff_lb[] = { + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0xA0000000, 0x00000000, + 0x81C, 0x47D80001, + 0x81C, 0x46DA0001, + 0x81C, 0x45DC0001, + 0x81C, 0x44DE0001, + 0x81C, 0x43E00001, + 0x81C, 0x42E20001, + 0x81C, 0x08E40001, + 0x81C, 0x07E60001, + 0x81C, 0x06E80001, + 0x81C, 0x05EA0001, + 0x81C, 0x04EC0001, + 0x81C, 0x03EE0001, + 0x81C, 0x02F00001, + 0xB0000000, 0x00000000, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_agc_diff_lb, rtw_phy_cfg_agc); + +static const u32 rtw8812a_agc_diff_hb[] = { + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0x45CE0001, + 0x81C, 0x44D00001, + 0x81C, 0x43D20001, + 0x81C, 0x42D40001, + 0x81C, 0x08D60001, + 0x81C, 0x07D80001, + 0x81C, 0x06DA0001, + 0x81C, 0x05DC0001, + 0x81C, 0x04DE0001, + 0x81C, 0x03E00001, + 0x81C, 0x02E20001, + 0x81C, 0x01E40001, + 0x81C, 0x01E60001, + 0xA0000000, 0x00000000, + 0x81C, 0x45D80001, + 0x81C, 0x44DA0001, + 0x81C, 0x43DC0001, + 0x81C, 0x42DE0001, + 0x81C, 0x08E00001, + 0x81C, 0x07E20001, + 0x81C, 0x06E40001, + 0x81C, 0x05E60001, + 0x81C, 0x04E80001, + 0x81C, 0x03EA0001, + 0x81C, 0x02EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0xB0000000, 0x00000000, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_agc_diff_hb, rtw_phy_cfg_agc); + +static const u32 rtw8812a_bb[] = { + 0x800, 0x8020D010, + 0x804, 0x080112E0, + 0x808, 0x0E028233, + 0x80C, 0x12131113, + 0x810, 0x20101263, + 0x814, 0x020C3D10, + 0x818, 0x03A00385, + 0x820, 0x00000000, + 0x824, 0x00030FE0, + 0x828, 0x00000000, + 0x82C, 0x002083DD, + 0x830, 0x2EAAEEB8, + 0x834, 0x0037A706, + 0x838, 0x06C89B44, + 0x83C, 0x0000095B, + 0x840, 0xC0000001, + 0x844, 0x40003CDE, + 0x848, 0x6210FF8B, + 0x84C, 0x6CFDFFB8, + 0x850, 0x28874706, + 0x854, 0x0001520C, + 0x858, 0x8060E000, + 0x85C, 0x74210168, + 0x860, 0x6929C321, + 0x864, 0x79727432, + 0x868, 0x8CA7A314, + 0x86C, 0x338C2878, + 0x870, 0x03333333, + 0x874, 0x31602C2E, + 0x878, 0x00003152, + 0x87C, 0x000FC000, + 0x8A0, 0x00000013, + 0x8A4, 0x7F7F7F7F, + 0x8A8, 0xA202033E, + 0x8AC, 0x0FF0FA0A, + 0x8B0, 0x00000600, + 0x8B4, 0x000FC080, + 0x8B8, 0x6C10D7FF, + 0x8BC, 0x4CA520A3, + 0x8C0, 0x27F00020, + 0x8C4, 0x00000000, + 0x8C8, 0x00012D69, + 0x8CC, 0x08248492, + 0x8D0, 0x0000B800, + 0x8DC, 0x00000000, + 0x8D4, 0x940008A0, + 0x8D8, 0x290B5612, + 0x8F8, 0x400002C0, + 0x8FC, 0x00000000, + 0x900, 0x00000701, + 0x90C, 0x00000000, + 0x910, 0x0000FC00, + 0x914, 0x00000404, + 0x918, 0x1C1028C0, + 0x91C, 0x64B11A1C, + 0x920, 0xE0767233, + 0x924, 0x055AA500, + 0x928, 0x00000004, + 0x92C, 0xFFFE0000, + 0x930, 0xFFFFFFFE, + 0x934, 0x001FFFFF, + 0x960, 0x00000000, + 0x964, 0x00000000, + 0x968, 0x00000000, + 0x96C, 0x00000000, + 0x970, 0x801FFFFF, + 0x978, 0x00000000, + 0x97C, 0x00000000, + 0x980, 0x00000000, + 0x984, 0x00000000, + 0x988, 0x00000000, + 0x990, 0x27100000, + 0x994, 0xFFFF0100, + 0x998, 0xFFFFFF5C, + 0x99C, 0xFFFFFFFF, + 0x9A0, 0x000000FF, + 0x9A4, 0x00080080, + 0x9A8, 0x00000000, + 0x9AC, 0x00000000, + 0x9B0, 0x81081008, + 0x9B4, 0x00000000, + 0x9B8, 0x01081008, + 0x9BC, 0x01081008, + 0x9D0, 0x00000000, + 0x9D4, 0x00000000, + 0x9D8, 0x00000000, + 0x9DC, 0x00000000, + 0x9E4, 0x00000003, + 0x9E8, 0x000002D5, + 0xA00, 0x00D047C8, + 0xA04, 0x01FF000C, + 0xA08, 0x8C838300, + 0xA0C, 0x2E7F000F, + 0xA10, 0x9500BB78, + 0xA14, 0x11144028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1217, + 0xA28, 0x00000305, + 0xA2C, 0x00900000, + 0xA70, 0x101FFF00, + 0xA74, 0x00000008, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x218075B2, + 0xA84, 0x001F8C80, + 0xB00, 0x03100000, + 0xB04, 0x0000B000, + 0xB08, 0xAE0201EB, + 0xB0C, 0x01003207, + 0xB10, 0x00009807, + 0xB14, 0x01000000, + 0xB18, 0x00000002, + 0xB1C, 0x00000002, + 0xB20, 0x0000001F, + 0xB24, 0x03020100, + 0xB28, 0x07060504, + 0xB2C, 0x0B0A0908, + 0xB30, 0x0F0E0D0C, + 0xB34, 0x13121110, + 0xB38, 0x17161514, + 0xB3C, 0x0000003A, + 0xB40, 0x00000000, + 0xB44, 0x00000000, + 0xB48, 0x13000032, + 0xB4C, 0x48080000, + 0xB50, 0x00000000, + 0xB54, 0x00000000, + 0xB58, 0x00000000, + 0xB5C, 0x00000000, + 0xC00, 0x00000007, + 0xC04, 0x00042020, + 0xC08, 0x80410231, + 0xC0C, 0x00000000, + 0xC10, 0x00000100, + 0xC14, 0x01000000, + 0xC1C, 0x40000003, + 0xC20, 0x12121212, + 0xC24, 0x12121212, + 0xC28, 0x12121212, + 0xC2C, 0x12121212, + 0xC30, 0x12121212, + 0xC34, 0x12121212, + 0xC38, 0x12121212, + 0xC3C, 0x12121212, + 0xC40, 0x12121212, + 0xC44, 0x12121212, + 0xC48, 0x12121212, + 0xC4C, 0x12121212, + 0xC50, 0x00000020, + 0xC54, 0x0008121C, + 0xC58, 0x30000C1C, + 0xC5C, 0x00000058, + 0xC60, 0x34344443, + 0xC64, 0x07003333, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000002, 0x00000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000004, 0x00000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000001, 0x00000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0xA0000000, 0x00000000, + 0xC68, 0x59799979, + 0xB0000000, 0x00000000, + 0xC6C, 0x59795979, + 0xC70, 0x19795979, + 0xC74, 0x19795979, + 0xC78, 0x19791979, + 0xC7C, 0x19791979, + 0xC80, 0x19791979, + 0xC84, 0x19791979, + 0xC94, 0x0100005C, + 0xC98, 0x00000000, + 0xC9C, 0x00000000, + 0xCA0, 0x00000029, + 0xCA4, 0x08040201, + 0xCA8, 0x80402010, + 0xCB0, 0x77547777, + 0xCB4, 0x00000077, + 0xCB8, 0x00508242, + 0xE00, 0x00000007, + 0xE04, 0x00042020, + 0xE08, 0x80410231, + 0xE0C, 0x00000000, + 0xE10, 0x00000100, + 0xE14, 0x01000000, + 0xE1C, 0x40000003, + 0xE20, 0x12121212, + 0xE24, 0x12121212, + 0xE28, 0x12121212, + 0xE2C, 0x12121212, + 0xE30, 0x12121212, + 0xE34, 0x12121212, + 0xE38, 0x12121212, + 0xE3C, 0x12121212, + 0xE40, 0x12121212, + 0xE44, 0x12121212, + 0xE48, 0x12121212, + 0xE4C, 0x12121212, + 0xE50, 0x00000020, + 0xE54, 0x0008121C, + 0xE58, 0x30000C1C, + 0xE5C, 0x00000058, + 0xE60, 0x34344443, + 0xE64, 0x07003333, + 0xE68, 0x59791979, + 0xE6C, 0x59795979, + 0xE70, 0x19795979, + 0xE74, 0x19795979, + 0xE78, 0x19791979, + 0xE7C, 0x19791979, + 0xE80, 0x19791979, + 0xE84, 0x19791979, + 0xE94, 0x0100005C, + 0xE98, 0x00000000, + 0xE9C, 0x00000000, + 0xEA0, 0x00000029, + 0xEA4, 0x08040201, + 0xEA8, 0x80402010, + 0xEB0, 0x77547777, + 0xEB4, 0x00000077, + 0xEB8, 0x00508242, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_bb, rtw_phy_cfg_bb); + +static const struct rtw_phy_pg_cfg_pair rtw8812a_bb_pg[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x42424444, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x30323638, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x28303236, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x38404242, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283034, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x28303236, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x42422426, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30343840, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x42424444, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x30323638, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x28303236, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x38404242, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283034, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x28303236, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x42422426, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30343840, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x42424444, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x30323640, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x28303236, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x38404242, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x26283034, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x28303236, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x42422426, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x30343840, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x42424444, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x30323640, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x28303236, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x38404242, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x26283034, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x28303236, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x42422426, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x30343840, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, +}; + +RTW_DECL_TABLE_BB_PG(rtw8812a_bb_pg); + +static const struct rtw_phy_pg_cfg_pair rtw8812a_bb_pg_rfe3[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x34343434, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x32323232, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303232, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x32323232, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x28303232, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x32323232, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x32323232, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x28303232, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x32322426, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x32323232, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x24262830, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x34343434, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x32323232, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303232, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x32323232, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x28303232, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x32323232, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x32323232, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x28303232, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x32322426, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x32323232, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x32323232, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x28303232, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32323232, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x32323232, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32323232, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x32322222, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303232, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x22222426, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x32323232, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x28303232, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32323232, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x32323232, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32323232, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x32322222, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303232, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x22222426, }, +}; + +RTW_DECL_TABLE_BB_PG(rtw8812a_bb_pg_rfe3); + +static const u32 rtw8812a_rf_a[] = { + 0x000, 0x00010000, + 0x018, 0x0001712A, + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x01E, 0x00080000, + 0x089, 0x00000080, + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x086, 0x00014B3A, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x086, 0x00014B3A, + 0xA0000000, 0x00000000, + 0x086, 0x00014B38, + 0xB0000000, 0x00000000, + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x08B, 0x00080180, + 0xA0000000, 0x00000000, + 0x08B, 0x00087180, + 0xB0000000, 0x00000000, + 0x0B1, 0x0001FC1A, + 0x0B3, 0x000F0810, + 0x0B4, 0x0001A78D, + 0x0BA, 0x00086180, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0xA0000000, 0x00000000, + 0x03B, 0x00038A58, + 0x03B, 0x00037A58, + 0x03B, 0x0002A590, + 0x03B, 0x00027A50, + 0x03B, 0x00018248, + 0x03B, 0x00010240, + 0x03B, 0x00008240, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000100, + 0x80000002, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A4EE, + 0x034, 0x00009076, + 0x034, 0x00008073, + 0x034, 0x00007070, + 0x034, 0x0000606D, + 0x034, 0x0000506A, + 0x034, 0x00004049, + 0x034, 0x00003046, + 0x034, 0x00002028, + 0x034, 0x00001025, + 0x034, 0x00000022, + 0xA0000000, 0x00000000, + 0x034, 0x0000ADF4, + 0x034, 0x00009DF1, + 0x034, 0x00008DEE, + 0x034, 0x00007DEB, + 0x034, 0x00006DE8, + 0x034, 0x00005DE5, + 0x034, 0x00004DE2, + 0x034, 0x00003CE6, + 0x034, 0x000024E7, + 0x034, 0x000014E4, + 0x034, 0x000004E1, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000192, + 0x035, 0x00008192, + 0x035, 0x00010192, + 0x036, 0x00000024, + 0x036, 0x00008024, + 0x036, 0x00010024, + 0x036, 0x00018024, + 0x0EF, 0x00000000, + 0x051, 0x00000C21, + 0x052, 0x000006D9, + 0x053, 0x000FC649, + 0x054, 0x0000017E, + 0x0EF, 0x00000002, + 0x008, 0x00008400, + 0x018, 0x0001712A, + 0x0EF, 0x00001000, + 0x03A, 0x00000080, + 0x03B, 0x0003A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0003202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0002B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00023070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0001B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00012085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0000A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00002080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x0007A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0007202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0006B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00063070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0005B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00052085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0004A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00042080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x000BA02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x000B202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x000AB064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x000A3070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0009B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00092085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0008A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00082080, + 0x03C, 0x00010000, + 0x0EF, 0x00001100, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x0004604D, + 0x034, 0x0004504A, + 0x034, 0x00044047, + 0x034, 0x00043044, + 0x034, 0x00042007, + 0x034, 0x00041004, + 0x034, 0x00040001, + 0xA0000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045DE6, + 0x034, 0x00044DE3, + 0x034, 0x000438C8, + 0x034, 0x000428C5, + 0x034, 0x000418C2, + 0x034, 0x000408C0, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0B4, + 0x034, 0x000290B1, + 0x034, 0x00028072, + 0x034, 0x0002706F, + 0x034, 0x0002604F, + 0x034, 0x0002504C, + 0x034, 0x00024049, + 0x034, 0x00023046, + 0x034, 0x00022009, + 0x034, 0x00021006, + 0x034, 0x00020003, + 0xA0000000, 0x00000000, + 0x034, 0x0002ADF5, + 0x034, 0x00029DF2, + 0x034, 0x00028DEF, + 0x034, 0x00027DEC, + 0x034, 0x00026DE9, + 0x034, 0x00025DE6, + 0x034, 0x00024DE3, + 0x034, 0x000238C8, + 0x034, 0x000228C5, + 0x034, 0x000218C2, + 0x034, 0x000208C0, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x0000604D, + 0x034, 0x0000504A, + 0x034, 0x00004047, + 0x034, 0x00003044, + 0x034, 0x00002007, + 0x034, 0x00001004, + 0x034, 0x00000001, + 0xA0000000, 0x00000000, + 0x034, 0x0000AFF7, + 0x034, 0x00009DF7, + 0x034, 0x00008DF4, + 0x034, 0x00007DF1, + 0x034, 0x00006DEE, + 0x034, 0x00005DEB, + 0x034, 0x00004DE8, + 0x034, 0x000038CC, + 0x034, 0x000028C9, + 0x034, 0x000018C6, + 0x034, 0x000008C3, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0xA0000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x00000188, + 0x035, 0x00008147, + 0x035, 0x00010147, + 0x035, 0x000201D7, + 0x035, 0x000281D7, + 0x035, 0x000301D7, + 0x035, 0x000401D8, + 0x035, 0x000481D8, + 0x035, 0x000501D8, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0xA0000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00084EB4, + 0x036, 0x0008CC35, + 0x036, 0x00094C35, + 0x036, 0x0009CC35, + 0x036, 0x000A4C35, + 0x036, 0x000ACC35, + 0x036, 0x000B4C35, + 0x036, 0x000BCC35, + 0x036, 0x000C4C34, + 0x036, 0x000CCC35, + 0x036, 0x000D4C35, + 0x036, 0x000DCC35, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0xA0000000, 0x00000000, + 0x03C, 0x000002A8, + 0x03C, 0x000005A2, + 0x03C, 0x00000880, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0x0DF, 0x00000080, + 0x01F, 0x00000064, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D1, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D2, + 0xA0000000, 0x00000000, + 0x061, 0x000E5D53, + 0x062, 0x00038FCD, + 0x063, 0x000114EB, + 0x064, 0x000196AC, + 0x065, 0x000911D7, + 0xB0000000, 0x00000000, + 0x008, 0x00008400, + 0x01C, 0x000739D2, + 0x0B4, 0x0001E78D, + 0x018, 0x0001F12A, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x0B4, 0x0001A78D, + 0x018, 0x0001712A, +}; + +RTW_DECL_TABLE_RF_RADIO(rtw8812a_rf_a, A); + +static const u32 rtw8812a_rf_b[] = { + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x089, 0x00000080, + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x086, 0x00014B3A, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x086, 0x00014B3A, + 0xA0000000, 0x00000000, + 0x086, 0x00014B38, + 0xB0000000, 0x00000000, + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x08B, 0x00080180, + 0xA0000000, 0x00000000, + 0x08B, 0x00087180, + 0xB0000000, 0x00000000, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0xA0000000, 0x00000000, + 0x03B, 0x00038A58, + 0x03B, 0x00037A58, + 0x03B, 0x0002A590, + 0x03B, 0x00027A50, + 0x03B, 0x00018248, + 0x03B, 0x00010240, + 0x03B, 0x00008240, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000100, + 0x80000002, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A4EE, + 0x034, 0x00009076, + 0x034, 0x00008073, + 0x034, 0x00007070, + 0x034, 0x0000606D, + 0x034, 0x0000506A, + 0x034, 0x00004049, + 0x034, 0x00003046, + 0x034, 0x00002028, + 0x034, 0x00001025, + 0x034, 0x00000022, + 0xA0000000, 0x00000000, + 0x034, 0x0000ADF4, + 0x034, 0x00009DF1, + 0x034, 0x00008DEE, + 0x034, 0x00007DEB, + 0x034, 0x00006DE8, + 0x034, 0x00005DE5, + 0x034, 0x00004DE2, + 0x034, 0x00003CE6, + 0x034, 0x000024E7, + 0x034, 0x000014E4, + 0x034, 0x000004E1, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000192, + 0x035, 0x00008192, + 0x035, 0x00010192, + 0x036, 0x00000024, + 0x036, 0x00008024, + 0x036, 0x00010024, + 0x036, 0x00018024, + 0x0EF, 0x00000000, + 0x051, 0x00000C21, + 0x052, 0x000006D9, + 0x053, 0x000FC649, + 0x054, 0x0000017E, + 0x0EF, 0x00000002, + 0x008, 0x00008400, + 0x018, 0x0001712A, + 0x0EF, 0x00001000, + 0x03A, 0x00000080, + 0x03B, 0x0003A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0003202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0002B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00023070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0001B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00012085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0000A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00002080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x0007A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0007202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0006B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00063070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0005B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00052085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0004A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00042080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x000BA02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x000B202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x000AB064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x000A3070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0009B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00092085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0008A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00082080, + 0x03C, 0x00010000, + 0x0EF, 0x00001100, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0B1, + 0x034, 0x000490AE, + 0x034, 0x0004806F, + 0x034, 0x0004706C, + 0x034, 0x0004604C, + 0x034, 0x00045049, + 0x034, 0x00044046, + 0x034, 0x00043043, + 0x034, 0x00042006, + 0x034, 0x00041003, + 0x034, 0x00040000, + 0xA0000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045DE6, + 0x034, 0x00044DE3, + 0x034, 0x000438C8, + 0x034, 0x000428C5, + 0x034, 0x000418C2, + 0x034, 0x000408C0, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0B3, + 0x034, 0x000290B0, + 0x034, 0x00028071, + 0x034, 0x0002706E, + 0x034, 0x0002604E, + 0x034, 0x0002504B, + 0x034, 0x00024048, + 0x034, 0x00023045, + 0x034, 0x00022008, + 0x034, 0x00021005, + 0x034, 0x00020002, + 0xA0000000, 0x00000000, + 0x034, 0x0002ADF5, + 0x034, 0x00029DF2, + 0x034, 0x00028DEF, + 0x034, 0x00027DEC, + 0x034, 0x00026DE9, + 0x034, 0x00025DE6, + 0x034, 0x00024DE3, + 0x034, 0x000238C8, + 0x034, 0x000228C5, + 0x034, 0x000218C2, + 0x034, 0x000208C0, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0B3, + 0x034, 0x000090B0, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x0000604D, + 0x034, 0x0000504A, + 0x034, 0x00004047, + 0x034, 0x00003044, + 0x034, 0x00002007, + 0x034, 0x00001004, + 0x034, 0x00000001, + 0xA0000000, 0x00000000, + 0x034, 0x0000AFF7, + 0x034, 0x00009DF7, + 0x034, 0x00008DF4, + 0x034, 0x00007DF1, + 0x034, 0x00006DEE, + 0x034, 0x00005DEB, + 0x034, 0x00004DE8, + 0x034, 0x000038CC, + 0x034, 0x000028C9, + 0x034, 0x000018C6, + 0x034, 0x000008C3, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x00000188, + 0x035, 0x00008147, + 0x035, 0x00010147, + 0x035, 0x000201D7, + 0x035, 0x000281D7, + 0x035, 0x000301D7, + 0x035, 0x000401D8, + 0x035, 0x000481D8, + 0x035, 0x000501D8, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0xA0000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00084EB4, + 0x036, 0x0008CC35, + 0x036, 0x00094C35, + 0x036, 0x0009CC35, + 0x036, 0x000A4C35, + 0x036, 0x000ACC35, + 0x036, 0x000B4C35, + 0x036, 0x000BCC35, + 0x036, 0x000C4C34, + 0x036, 0x000CCC35, + 0x036, 0x000D4C35, + 0x036, 0x000DCC35, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0xA0000000, 0x00000000, + 0x03C, 0x000002A8, + 0x03C, 0x000005A2, + 0x03C, 0x00000880, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0x0DF, 0x00000080, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D2, + 0x90000002, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0xA0000000, 0x00000000, + 0x061, 0x000E5D53, + 0x062, 0x00038FCD, + 0x063, 0x000114EB, + 0x064, 0x000196AC, + 0x065, 0x000911D7, + 0xB0000000, 0x00000000, + 0x008, 0x00008400, +}; + +RTW_DECL_TABLE_RF_RADIO(rtw8812a_rf_b, B); + +static const struct rtw_txpwr_lmt_cfg_pair rtw8812a_txpwr_lmt[] = { + { 0, 0, 0, 0, 1, 36, }, + { 2, 0, 0, 0, 1, 32, }, + { 1, 0, 0, 0, 1, 32, }, + { 0, 0, 0, 0, 2, 36, }, + { 2, 0, 0, 0, 2, 32, }, + { 1, 0, 0, 0, 2, 32, }, + { 0, 0, 0, 0, 3, 36, }, + { 2, 0, 0, 0, 3, 32, }, + { 1, 0, 0, 0, 3, 32, }, + { 0, 0, 0, 0, 4, 36, }, + { 2, 0, 0, 0, 4, 32, }, + { 1, 0, 0, 0, 4, 32, }, + { 0, 0, 0, 0, 5, 36, }, + { 2, 0, 0, 0, 5, 32, }, + { 1, 0, 0, 0, 5, 32, }, + { 0, 0, 0, 0, 6, 36, }, + { 2, 0, 0, 0, 6, 32, }, + { 1, 0, 0, 0, 6, 32, }, + { 0, 0, 0, 0, 7, 36, }, + { 2, 0, 0, 0, 7, 32, }, + { 1, 0, 0, 0, 7, 32, }, + { 0, 0, 0, 0, 8, 36, }, + { 2, 0, 0, 0, 8, 32, }, + { 1, 0, 0, 0, 8, 32, }, + { 0, 0, 0, 0, 9, 36, }, + { 2, 0, 0, 0, 9, 32, }, + { 1, 0, 0, 0, 9, 32, }, + { 0, 0, 0, 0, 10, 36, }, + { 2, 0, 0, 0, 10, 32, }, + { 1, 0, 0, 0, 10, 32, }, + { 0, 0, 0, 0, 11, 36, }, + { 2, 0, 0, 0, 11, 32, }, + { 1, 0, 0, 0, 11, 32, }, + { 0, 0, 0, 0, 12, 63, }, + { 2, 0, 0, 0, 12, 32, }, + { 1, 0, 0, 0, 12, 32, }, + { 0, 0, 0, 0, 13, 63, }, + { 2, 0, 0, 0, 13, 32, }, + { 1, 0, 0, 0, 13, 32, }, + { 0, 0, 0, 0, 14, 63, }, + { 2, 0, 0, 0, 14, 63, }, + { 1, 0, 0, 0, 14, 32, }, + { 0, 0, 0, 1, 1, 34, }, + { 2, 0, 0, 1, 1, 32, }, + { 1, 0, 0, 1, 1, 32, }, + { 0, 0, 0, 1, 2, 36, }, + { 2, 0, 0, 1, 2, 32, }, + { 1, 0, 0, 1, 2, 32, }, + { 0, 0, 0, 1, 3, 36, }, + { 2, 0, 0, 1, 3, 32, }, + { 1, 0, 0, 1, 3, 32, }, + { 0, 0, 0, 1, 4, 36, }, + { 2, 0, 0, 1, 4, 32, }, + { 1, 0, 0, 1, 4, 32, }, + { 0, 0, 0, 1, 5, 36, }, + { 2, 0, 0, 1, 5, 32, }, + { 1, 0, 0, 1, 5, 32, }, + { 0, 0, 0, 1, 6, 36, }, + { 2, 0, 0, 1, 6, 32, }, + { 1, 0, 0, 1, 6, 32, }, + { 0, 0, 0, 1, 7, 36, }, + { 2, 0, 0, 1, 7, 32, }, + { 1, 0, 0, 1, 7, 32, }, + { 0, 0, 0, 1, 8, 36, }, + { 2, 0, 0, 1, 8, 32, }, + { 1, 0, 0, 1, 8, 32, }, + { 0, 0, 0, 1, 9, 36, }, + { 2, 0, 0, 1, 9, 32, }, + { 1, 0, 0, 1, 9, 32, }, + { 0, 0, 0, 1, 10, 36, }, + { 2, 0, 0, 1, 10, 32, }, + { 1, 0, 0, 1, 10, 32, }, + { 0, 0, 0, 1, 11, 32, }, + { 2, 0, 0, 1, 11, 32, }, + { 1, 0, 0, 1, 11, 32, }, + { 0, 0, 0, 1, 12, 63, }, + { 2, 0, 0, 1, 12, 32, }, + { 1, 0, 0, 1, 12, 32, }, + { 0, 0, 0, 1, 13, 63, }, + { 2, 0, 0, 1, 13, 32, }, + { 1, 0, 0, 1, 13, 32, }, + { 0, 0, 0, 1, 14, 63, }, + { 2, 0, 0, 1, 14, 63, }, + { 1, 0, 0, 1, 14, 63, }, + { 0, 0, 0, 2, 1, 34, }, + { 2, 0, 0, 2, 1, 32, }, + { 1, 0, 0, 2, 1, 32, }, + { 0, 0, 0, 2, 2, 36, }, + { 2, 0, 0, 2, 2, 32, }, + { 1, 0, 0, 2, 2, 32, }, + { 0, 0, 0, 2, 3, 36, }, + { 2, 0, 0, 2, 3, 32, }, + { 1, 0, 0, 2, 3, 32, }, + { 0, 0, 0, 2, 4, 36, }, + { 2, 0, 0, 2, 4, 32, }, + { 1, 0, 0, 2, 4, 32, }, + { 0, 0, 0, 2, 5, 36, }, + { 2, 0, 0, 2, 5, 32, }, + { 1, 0, 0, 2, 5, 32, }, + { 0, 0, 0, 2, 6, 36, }, + { 2, 0, 0, 2, 6, 32, }, + { 1, 0, 0, 2, 6, 32, }, + { 0, 0, 0, 2, 7, 36, }, + { 2, 0, 0, 2, 7, 32, }, + { 1, 0, 0, 2, 7, 32, }, + { 0, 0, 0, 2, 8, 36, }, + { 2, 0, 0, 2, 8, 32, }, + { 1, 0, 0, 2, 8, 32, }, + { 0, 0, 0, 2, 9, 36, }, + { 2, 0, 0, 2, 9, 32, }, + { 1, 0, 0, 2, 9, 32, }, + { 0, 0, 0, 2, 10, 36, }, + { 2, 0, 0, 2, 10, 32, }, + { 1, 0, 0, 2, 10, 32, }, + { 0, 0, 0, 2, 11, 32, }, + { 2, 0, 0, 2, 11, 32, }, + { 1, 0, 0, 2, 11, 32, }, + { 0, 0, 0, 2, 12, 63, }, + { 2, 0, 0, 2, 12, 32, }, + { 1, 0, 0, 2, 12, 32, }, + { 0, 0, 0, 2, 13, 63, }, + { 2, 0, 0, 2, 13, 32, }, + { 1, 0, 0, 2, 13, 32, }, + { 0, 0, 0, 2, 14, 63, }, + { 2, 0, 0, 2, 14, 63, }, + { 1, 0, 0, 2, 14, 63, }, + { 0, 0, 0, 3, 1, 32, }, + { 2, 0, 0, 3, 1, 32, }, + { 1, 0, 0, 3, 1, 32, }, + { 0, 0, 0, 3, 2, 34, }, + { 2, 0, 0, 3, 2, 32, }, + { 1, 0, 0, 3, 2, 32, }, + { 0, 0, 0, 3, 3, 34, }, + { 2, 0, 0, 3, 3, 32, }, + { 1, 0, 0, 3, 3, 32, }, + { 0, 0, 0, 3, 4, 34, }, + { 2, 0, 0, 3, 4, 32, }, + { 1, 0, 0, 3, 4, 32, }, + { 0, 0, 0, 3, 5, 34, }, + { 2, 0, 0, 3, 5, 32, }, + { 1, 0, 0, 3, 5, 32, }, + { 0, 0, 0, 3, 6, 34, }, + { 2, 0, 0, 3, 6, 32, }, + { 1, 0, 0, 3, 6, 32, }, + { 0, 0, 0, 3, 7, 34, }, + { 2, 0, 0, 3, 7, 32, }, + { 1, 0, 0, 3, 7, 32, }, + { 0, 0, 0, 3, 8, 34, }, + { 2, 0, 0, 3, 8, 32, }, + { 1, 0, 0, 3, 8, 32, }, + { 0, 0, 0, 3, 9, 34, }, + { 2, 0, 0, 3, 9, 32, }, + { 1, 0, 0, 3, 9, 32, }, + { 0, 0, 0, 3, 10, 34, }, + { 2, 0, 0, 3, 10, 32, }, + { 1, 0, 0, 3, 10, 32, }, + { 0, 0, 0, 3, 11, 30, }, + { 2, 0, 0, 3, 11, 32, }, + { 1, 0, 0, 3, 11, 32, }, + { 0, 0, 0, 3, 12, 63, }, + { 2, 0, 0, 3, 12, 32, }, + { 1, 0, 0, 3, 12, 32, }, + { 0, 0, 0, 3, 13, 63, }, + { 2, 0, 0, 3, 13, 32, }, + { 1, 0, 0, 3, 13, 32, }, + { 0, 0, 0, 3, 14, 63, }, + { 2, 0, 0, 3, 14, 63, }, + { 1, 0, 0, 3, 14, 63, }, + { 0, 0, 1, 2, 1, 63, }, + { 2, 0, 1, 2, 1, 63, }, + { 1, 0, 1, 2, 1, 63, }, + { 0, 0, 1, 2, 2, 63, }, + { 2, 0, 1, 2, 2, 63, }, + { 1, 0, 1, 2, 2, 63, }, + { 0, 0, 1, 2, 3, 32, }, + { 2, 0, 1, 2, 3, 32, }, + { 1, 0, 1, 2, 3, 32, }, + { 0, 0, 1, 2, 4, 36, }, + { 2, 0, 1, 2, 4, 32, }, + { 1, 0, 1, 2, 4, 32, }, + { 0, 0, 1, 2, 5, 36, }, + { 2, 0, 1, 2, 5, 32, }, + { 1, 0, 1, 2, 5, 32, }, + { 0, 0, 1, 2, 6, 36, }, + { 2, 0, 1, 2, 6, 32, }, + { 1, 0, 1, 2, 6, 32, }, + { 0, 0, 1, 2, 7, 36, }, + { 2, 0, 1, 2, 7, 32, }, + { 1, 0, 1, 2, 7, 32, }, + { 0, 0, 1, 2, 8, 36, }, + { 2, 0, 1, 2, 8, 32, }, + { 1, 0, 1, 2, 8, 32, }, + { 0, 0, 1, 2, 9, 36, }, + { 2, 0, 1, 2, 9, 32, }, + { 1, 0, 1, 2, 9, 32, }, + { 0, 0, 1, 2, 10, 36, }, + { 2, 0, 1, 2, 10, 32, }, + { 1, 0, 1, 2, 10, 32, }, + { 0, 0, 1, 2, 11, 32, }, + { 2, 0, 1, 2, 11, 32, }, + { 1, 0, 1, 2, 11, 32, }, + { 0, 0, 1, 2, 12, 63, }, + { 2, 0, 1, 2, 12, 32, }, + { 1, 0, 1, 2, 12, 32, }, + { 0, 0, 1, 2, 13, 63, }, + { 2, 0, 1, 2, 13, 32, }, + { 1, 0, 1, 2, 13, 32, }, + { 0, 0, 1, 2, 14, 63, }, + { 2, 0, 1, 2, 14, 63, }, + { 1, 0, 1, 2, 14, 63, }, + { 0, 0, 1, 3, 1, 63, }, + { 2, 0, 1, 3, 1, 63, }, + { 1, 0, 1, 3, 1, 63, }, + { 0, 0, 1, 3, 2, 63, }, + { 2, 0, 1, 3, 2, 63, }, + { 1, 0, 1, 3, 2, 63, }, + { 0, 0, 1, 3, 3, 30, }, + { 2, 0, 1, 3, 3, 30, }, + { 1, 0, 1, 3, 3, 30, }, + { 0, 0, 1, 3, 4, 34, }, + { 2, 0, 1, 3, 4, 30, }, + { 1, 0, 1, 3, 4, 30, }, + { 0, 0, 1, 3, 5, 34, }, + { 2, 0, 1, 3, 5, 30, }, + { 1, 0, 1, 3, 5, 30, }, + { 0, 0, 1, 3, 6, 34, }, + { 2, 0, 1, 3, 6, 30, }, + { 1, 0, 1, 3, 6, 30, }, + { 0, 0, 1, 3, 7, 34, }, + { 2, 0, 1, 3, 7, 30, }, + { 1, 0, 1, 3, 7, 30, }, + { 0, 0, 1, 3, 8, 34, }, + { 2, 0, 1, 3, 8, 30, }, + { 1, 0, 1, 3, 8, 30, }, + { 0, 0, 1, 3, 9, 34, }, + { 2, 0, 1, 3, 9, 30, }, + { 1, 0, 1, 3, 9, 30, }, + { 0, 0, 1, 3, 10, 34, }, + { 2, 0, 1, 3, 10, 30, }, + { 1, 0, 1, 3, 10, 30, }, + { 0, 0, 1, 3, 11, 30, }, + { 2, 0, 1, 3, 11, 30, }, + { 1, 0, 1, 3, 11, 30, }, + { 0, 0, 1, 3, 12, 63, }, + { 2, 0, 1, 3, 12, 32, }, + { 1, 0, 1, 3, 12, 32, }, + { 0, 0, 1, 3, 13, 63, }, + { 2, 0, 1, 3, 13, 32, }, + { 1, 0, 1, 3, 13, 32, }, + { 0, 0, 1, 3, 14, 63, }, + { 2, 0, 1, 3, 14, 63, }, + { 1, 0, 1, 3, 14, 63, }, + { 0, 1, 0, 1, 36, 30, }, + { 2, 1, 0, 1, 36, 32, }, + { 1, 1, 0, 1, 36, 32, }, + { 0, 1, 0, 1, 40, 30, }, + { 2, 1, 0, 1, 40, 32, }, + { 1, 1, 0, 1, 40, 32, }, + { 0, 1, 0, 1, 44, 30, }, + { 2, 1, 0, 1, 44, 32, }, + { 1, 1, 0, 1, 44, 32, }, + { 0, 1, 0, 1, 48, 30, }, + { 2, 1, 0, 1, 48, 32, }, + { 1, 1, 0, 1, 48, 32, }, + { 0, 1, 0, 1, 52, 36, }, + { 2, 1, 0, 1, 52, 32, }, + { 1, 1, 0, 1, 52, 32, }, + { 0, 1, 0, 1, 56, 34, }, + { 2, 1, 0, 1, 56, 32, }, + { 1, 1, 0, 1, 56, 32, }, + { 0, 1, 0, 1, 60, 32, }, + { 2, 1, 0, 1, 60, 32, }, + { 1, 1, 0, 1, 60, 32, }, + { 0, 1, 0, 1, 64, 28, }, + { 2, 1, 0, 1, 64, 32, }, + { 1, 1, 0, 1, 64, 32, }, + { 0, 1, 0, 1, 100, 30, }, + { 2, 1, 0, 1, 100, 32, }, + { 1, 1, 0, 1, 100, 32, }, + { 0, 1, 0, 1, 104, 30, }, + { 2, 1, 0, 1, 104, 32, }, + { 1, 1, 0, 1, 104, 32, }, + { 0, 1, 0, 1, 108, 32, }, + { 2, 1, 0, 1, 108, 32, }, + { 1, 1, 0, 1, 108, 32, }, + { 0, 1, 0, 1, 112, 34, }, + { 2, 1, 0, 1, 112, 32, }, + { 1, 1, 0, 1, 112, 32, }, + { 0, 1, 0, 1, 116, 34, }, + { 2, 1, 0, 1, 116, 32, }, + { 1, 1, 0, 1, 116, 32, }, + { 0, 1, 0, 1, 120, 36, }, + { 2, 1, 0, 1, 120, 32, }, + { 1, 1, 0, 1, 120, 32, }, + { 0, 1, 0, 1, 124, 34, }, + { 2, 1, 0, 1, 124, 32, }, + { 1, 1, 0, 1, 124, 32, }, + { 0, 1, 0, 1, 128, 32, }, + { 2, 1, 0, 1, 128, 32, }, + { 1, 1, 0, 1, 128, 32, }, + { 0, 1, 0, 1, 132, 30, }, + { 2, 1, 0, 1, 132, 32, }, + { 1, 1, 0, 1, 132, 32, }, + { 0, 1, 0, 1, 136, 30, }, + { 2, 1, 0, 1, 136, 32, }, + { 1, 1, 0, 1, 136, 32, }, + { 0, 1, 0, 1, 140, 28, }, + { 2, 1, 0, 1, 140, 32, }, + { 1, 1, 0, 1, 140, 32, }, + { 0, 1, 0, 1, 149, 36, }, + { 2, 1, 0, 1, 149, 32, }, + { 1, 1, 0, 1, 149, 63, }, + { 0, 1, 0, 1, 153, 36, }, + { 2, 1, 0, 1, 153, 32, }, + { 1, 1, 0, 1, 153, 63, }, + { 0, 1, 0, 1, 157, 36, }, + { 2, 1, 0, 1, 157, 32, }, + { 1, 1, 0, 1, 157, 63, }, + { 0, 1, 0, 1, 161, 36, }, + { 2, 1, 0, 1, 161, 32, }, + { 1, 1, 0, 1, 161, 63, }, + { 0, 1, 0, 1, 165, 36, }, + { 2, 1, 0, 1, 165, 32, }, + { 1, 1, 0, 1, 165, 63, }, + { 0, 1, 0, 2, 36, 30, }, + { 2, 1, 0, 2, 36, 32, }, + { 1, 1, 0, 2, 36, 32, }, + { 0, 1, 0, 2, 40, 30, }, + { 2, 1, 0, 2, 40, 32, }, + { 1, 1, 0, 2, 40, 32, }, + { 0, 1, 0, 2, 44, 30, }, + { 2, 1, 0, 2, 44, 32, }, + { 1, 1, 0, 2, 44, 32, }, + { 0, 1, 0, 2, 48, 30, }, + { 2, 1, 0, 2, 48, 32, }, + { 1, 1, 0, 2, 48, 32, }, + { 0, 1, 0, 2, 52, 36, }, + { 2, 1, 0, 2, 52, 32, }, + { 1, 1, 0, 2, 52, 32, }, + { 0, 1, 0, 2, 56, 34, }, + { 2, 1, 0, 2, 56, 32, }, + { 1, 1, 0, 2, 56, 32, }, + { 0, 1, 0, 2, 60, 32, }, + { 2, 1, 0, 2, 60, 32, }, + { 1, 1, 0, 2, 60, 32, }, + { 0, 1, 0, 2, 64, 28, }, + { 2, 1, 0, 2, 64, 32, }, + { 1, 1, 0, 2, 64, 32, }, + { 0, 1, 0, 2, 100, 30, }, + { 2, 1, 0, 2, 100, 32, }, + { 1, 1, 0, 2, 100, 32, }, + { 0, 1, 0, 2, 104, 30, }, + { 2, 1, 0, 2, 104, 32, }, + { 1, 1, 0, 2, 104, 32, }, + { 0, 1, 0, 2, 108, 32, }, + { 2, 1, 0, 2, 108, 32, }, + { 1, 1, 0, 2, 108, 32, }, + { 0, 1, 0, 2, 112, 34, }, + { 2, 1, 0, 2, 112, 32, }, + { 1, 1, 0, 2, 112, 32, }, + { 0, 1, 0, 2, 116, 34, }, + { 2, 1, 0, 2, 116, 32, }, + { 1, 1, 0, 2, 116, 32, }, + { 0, 1, 0, 2, 120, 36, }, + { 2, 1, 0, 2, 120, 32, }, + { 1, 1, 0, 2, 120, 32, }, + { 0, 1, 0, 2, 124, 34, }, + { 2, 1, 0, 2, 124, 32, }, + { 1, 1, 0, 2, 124, 32, }, + { 0, 1, 0, 2, 128, 32, }, + { 2, 1, 0, 2, 128, 32, }, + { 1, 1, 0, 2, 128, 32, }, + { 0, 1, 0, 2, 132, 30, }, + { 2, 1, 0, 2, 132, 32, }, + { 1, 1, 0, 2, 132, 32, }, + { 0, 1, 0, 2, 136, 30, }, + { 2, 1, 0, 2, 136, 32, }, + { 1, 1, 0, 2, 136, 32, }, + { 0, 1, 0, 2, 140, 28, }, + { 2, 1, 0, 2, 140, 32, }, + { 1, 1, 0, 2, 140, 32, }, + { 0, 1, 0, 2, 149, 36, }, + { 2, 1, 0, 2, 149, 32, }, + { 1, 1, 0, 2, 149, 63, }, + { 0, 1, 0, 2, 153, 36, }, + { 2, 1, 0, 2, 153, 32, }, + { 1, 1, 0, 2, 153, 63, }, + { 0, 1, 0, 2, 157, 36, }, + { 2, 1, 0, 2, 157, 32, }, + { 1, 1, 0, 2, 157, 63, }, + { 0, 1, 0, 2, 161, 36, }, + { 2, 1, 0, 2, 161, 32, }, + { 1, 1, 0, 2, 161, 63, }, + { 0, 1, 0, 2, 165, 36, }, + { 2, 1, 0, 2, 165, 32, }, + { 1, 1, 0, 2, 165, 63, }, + { 0, 1, 0, 3, 36, 28, }, + { 2, 1, 0, 3, 36, 30, }, + { 1, 1, 0, 3, 36, 30, }, + { 0, 1, 0, 3, 40, 28, }, + { 2, 1, 0, 3, 40, 30, }, + { 1, 1, 0, 3, 40, 30, }, + { 0, 1, 0, 3, 44, 28, }, + { 2, 1, 0, 3, 44, 30, }, + { 1, 1, 0, 3, 44, 30, }, + { 0, 1, 0, 3, 48, 28, }, + { 2, 1, 0, 3, 48, 30, }, + { 1, 1, 0, 3, 48, 30, }, + { 0, 1, 0, 3, 52, 34, }, + { 2, 1, 0, 3, 52, 30, }, + { 1, 1, 0, 3, 52, 30, }, + { 0, 1, 0, 3, 56, 32, }, + { 2, 1, 0, 3, 56, 30, }, + { 1, 1, 0, 3, 56, 30, }, + { 0, 1, 0, 3, 60, 30, }, + { 2, 1, 0, 3, 60, 30, }, + { 1, 1, 0, 3, 60, 30, }, + { 0, 1, 0, 3, 64, 26, }, + { 2, 1, 0, 3, 64, 30, }, + { 1, 1, 0, 3, 64, 30, }, + { 0, 1, 0, 3, 100, 28, }, + { 2, 1, 0, 3, 100, 30, }, + { 1, 1, 0, 3, 100, 30, }, + { 0, 1, 0, 3, 104, 28, }, + { 2, 1, 0, 3, 104, 30, }, + { 1, 1, 0, 3, 104, 30, }, + { 0, 1, 0, 3, 108, 30, }, + { 2, 1, 0, 3, 108, 30, }, + { 1, 1, 0, 3, 108, 30, }, + { 0, 1, 0, 3, 112, 32, }, + { 2, 1, 0, 3, 112, 30, }, + { 1, 1, 0, 3, 112, 30, }, + { 0, 1, 0, 3, 116, 32, }, + { 2, 1, 0, 3, 116, 30, }, + { 1, 1, 0, 3, 116, 30, }, + { 0, 1, 0, 3, 120, 34, }, + { 2, 1, 0, 3, 120, 30, }, + { 1, 1, 0, 3, 120, 30, }, + { 0, 1, 0, 3, 124, 32, }, + { 2, 1, 0, 3, 124, 30, }, + { 1, 1, 0, 3, 124, 30, }, + { 0, 1, 0, 3, 128, 30, }, + { 2, 1, 0, 3, 128, 30, }, + { 1, 1, 0, 3, 128, 30, }, + { 0, 1, 0, 3, 132, 28, }, + { 2, 1, 0, 3, 132, 30, }, + { 1, 1, 0, 3, 132, 30, }, + { 0, 1, 0, 3, 136, 28, }, + { 2, 1, 0, 3, 136, 30, }, + { 1, 1, 0, 3, 136, 30, }, + { 0, 1, 0, 3, 140, 26, }, + { 2, 1, 0, 3, 140, 30, }, + { 1, 1, 0, 3, 140, 30, }, + { 0, 1, 0, 3, 149, 34, }, + { 2, 1, 0, 3, 149, 30, }, + { 1, 1, 0, 3, 149, 63, }, + { 0, 1, 0, 3, 153, 34, }, + { 2, 1, 0, 3, 153, 30, }, + { 1, 1, 0, 3, 153, 63, }, + { 0, 1, 0, 3, 157, 34, }, + { 2, 1, 0, 3, 157, 30, }, + { 1, 1, 0, 3, 157, 63, }, + { 0, 1, 0, 3, 161, 34, }, + { 2, 1, 0, 3, 161, 30, }, + { 1, 1, 0, 3, 161, 63, }, + { 0, 1, 0, 3, 165, 34, }, + { 2, 1, 0, 3, 165, 30, }, + { 1, 1, 0, 3, 165, 63, }, + { 0, 1, 1, 2, 38, 30, }, + { 2, 1, 1, 2, 38, 32, }, + { 1, 1, 1, 2, 38, 32, }, + { 0, 1, 1, 2, 46, 30, }, + { 2, 1, 1, 2, 46, 32, }, + { 1, 1, 1, 2, 46, 32, }, + { 0, 1, 1, 2, 54, 32, }, + { 2, 1, 1, 2, 54, 32, }, + { 1, 1, 1, 2, 54, 32, }, + { 0, 1, 1, 2, 62, 32, }, + { 2, 1, 1, 2, 62, 32, }, + { 1, 1, 1, 2, 62, 32, }, + { 0, 1, 1, 2, 102, 28, }, + { 2, 1, 1, 2, 102, 32, }, + { 1, 1, 1, 2, 102, 32, }, + { 0, 1, 1, 2, 110, 32, }, + { 2, 1, 1, 2, 110, 32, }, + { 1, 1, 1, 2, 110, 32, }, + { 0, 1, 1, 2, 118, 36, }, + { 2, 1, 1, 2, 118, 32, }, + { 1, 1, 1, 2, 118, 32, }, + { 0, 1, 1, 2, 126, 34, }, + { 2, 1, 1, 2, 126, 32, }, + { 1, 1, 1, 2, 126, 32, }, + { 0, 1, 1, 2, 134, 32, }, + { 2, 1, 1, 2, 134, 32, }, + { 1, 1, 1, 2, 134, 32, }, + { 0, 1, 1, 2, 151, 36, }, + { 2, 1, 1, 2, 151, 32, }, + { 1, 1, 1, 2, 151, 63, }, + { 0, 1, 1, 2, 159, 36, }, + { 2, 1, 1, 2, 159, 32, }, + { 1, 1, 1, 2, 159, 63, }, + { 0, 1, 1, 3, 38, 28, }, + { 2, 1, 1, 3, 38, 30, }, + { 1, 1, 1, 3, 38, 30, }, + { 0, 1, 1, 3, 46, 28, }, + { 2, 1, 1, 3, 46, 30, }, + { 1, 1, 1, 3, 46, 30, }, + { 0, 1, 1, 3, 54, 30, }, + { 2, 1, 1, 3, 54, 30, }, + { 1, 1, 1, 3, 54, 30, }, + { 0, 1, 1, 3, 62, 30, }, + { 2, 1, 1, 3, 62, 30, }, + { 1, 1, 1, 3, 62, 30, }, + { 0, 1, 1, 3, 102, 26, }, + { 2, 1, 1, 3, 102, 30, }, + { 1, 1, 1, 3, 102, 30, }, + { 0, 1, 1, 3, 110, 30, }, + { 2, 1, 1, 3, 110, 30, }, + { 1, 1, 1, 3, 110, 30, }, + { 0, 1, 1, 3, 118, 34, }, + { 2, 1, 1, 3, 118, 30, }, + { 1, 1, 1, 3, 118, 30, }, + { 0, 1, 1, 3, 126, 32, }, + { 2, 1, 1, 3, 126, 30, }, + { 1, 1, 1, 3, 126, 30, }, + { 0, 1, 1, 3, 134, 30, }, + { 2, 1, 1, 3, 134, 30, }, + { 1, 1, 1, 3, 134, 30, }, + { 0, 1, 1, 3, 151, 34, }, + { 2, 1, 1, 3, 151, 30, }, + { 1, 1, 1, 3, 151, 63, }, + { 0, 1, 1, 3, 159, 34, }, + { 2, 1, 1, 3, 159, 30, }, + { 1, 1, 1, 3, 159, 63, }, + { 0, 1, 2, 4, 42, 30, }, + { 2, 1, 2, 4, 42, 32, }, + { 1, 1, 2, 4, 42, 32, }, + { 0, 1, 2, 4, 58, 28, }, + { 2, 1, 2, 4, 58, 32, }, + { 1, 1, 2, 4, 58, 32, }, + { 0, 1, 2, 4, 106, 30, }, + { 2, 1, 2, 4, 106, 32, }, + { 1, 1, 2, 4, 106, 32, }, + { 0, 1, 2, 4, 122, 34, }, + { 2, 1, 2, 4, 122, 32, }, + { 1, 1, 2, 4, 122, 32, }, + { 0, 1, 2, 4, 155, 36, }, + { 2, 1, 2, 4, 155, 32, }, + { 1, 1, 2, 4, 155, 63, }, + { 0, 1, 2, 5, 42, 28, }, + { 2, 1, 2, 5, 42, 30, }, + { 1, 1, 2, 5, 42, 30, }, + { 0, 1, 2, 5, 58, 26, }, + { 2, 1, 2, 5, 58, 30, }, + { 1, 1, 2, 5, 58, 30, }, + { 0, 1, 2, 5, 106, 28, }, + { 2, 1, 2, 5, 106, 30, }, + { 1, 1, 2, 5, 106, 30, }, + { 0, 1, 2, 5, 122, 32, }, + { 2, 1, 2, 5, 122, 30, }, + { 1, 1, 2, 5, 122, 30, }, + { 0, 1, 2, 5, 155, 34, }, + { 2, 1, 2, 5, 155, 30, }, + { 1, 1, 2, 5, 155, 63, }, +}; + +RTW_DECL_TABLE_TXPWR_LMT(rtw8812a_txpwr_lmt); + +static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8812a[] = { + {0x0012, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0014, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x80, 0}, + {0x0015, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x01, 0}, + {0x0023, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x10, 0}, + {0x0046, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0043, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), 0}, + {0x0003, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), BIT(2)}, + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x0024, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0028, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), BIT(3)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8812a[] = { + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), 0}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(7), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(0), 0}, + {0x0024, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0028, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_act_to_lps_8812a[] = { + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0xFF}, + {0x0522, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x7F}, + {0x05F8, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05F9, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05FA, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05FB, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x0c00, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0x0e00, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0100, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x03}, + {0x0101, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0553, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), BIT(5)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8812a[] = { + {0x0c00, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0x0e00, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0007, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x2A}, + {0x0008, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x02, 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8812a[] = { + {0x0003, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), 0}, + {0x0080, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x05}, + {0x0042, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xF0, 0xcc}, + {0x0042, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xF0, 0xEC}, + {0x0043, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x07}, + {0x0045, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0046, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0xff}, + {0x0047, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x0014, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x80, BIT(7)}, + {0x0015, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x01, BIT(0)}, + {0x0012, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x01, 0}, + {0x0023, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x10, BIT(4)}, + {0x0008, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x02, 0}, + {0x0007, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x20}, + {0x001f, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0076, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), BIT(3)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +const struct rtw_pwr_seq_cmd * const card_enable_flow_8812a[] = { + trans_carddis_to_cardemu_8812a, + trans_cardemu_to_act_8812a, + NULL +}; + +const struct rtw_pwr_seq_cmd * const enter_lps_flow_8812a[] = { + trans_act_to_lps_8812a, + NULL +}; + +const struct rtw_pwr_seq_cmd * const card_disable_flow_8812a[] = { + trans_act_to_cardemu_8812a, + trans_cardemu_to_carddis_8812a, + NULL +}; + +static const u8 rtw8812a_pwrtrk_5gb_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 14, 14, 14, 14, 14}, + {0, 1, 1, 2, 2, 3, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 14, 14, 14, 14, 14}, + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 11, 12, 12, 13, + 13, 14, 14, 15, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8812a_pwrtrk_5gb_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +static const u8 rtw8812a_pwrtrk_5ga_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 15, 15, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 15, 15, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 15, 15, 15, 15, 15}, +}; + +static const u8 rtw8812a_pwrtrk_5ga_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 12, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +static const u8 rtw8812a_pwrtrk_2gb_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_2gb_p[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const u8 rtw8812a_pwrtrk_2ga_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10 +}; + +static const u8 rtw8812a_pwrtrk_2ga_p[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const u8 rtw8812a_pwrtrk_2g_cck_b_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_2g_cck_b_p[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const u8 rtw8812a_pwrtrk_2g_cck_a_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10 +}; + +static const u8 rtw8812a_pwrtrk_2g_cck_a_p[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[0] = rtw8812a_pwrtrk_5gb_n[0], + .pwrtrk_5gb_n[1] = rtw8812a_pwrtrk_5gb_n[1], + .pwrtrk_5gb_n[2] = rtw8812a_pwrtrk_5gb_n[2], + .pwrtrk_5gb_p[0] = rtw8812a_pwrtrk_5gb_p[0], + .pwrtrk_5gb_p[1] = rtw8812a_pwrtrk_5gb_p[1], + .pwrtrk_5gb_p[2] = rtw8812a_pwrtrk_5gb_p[2], + .pwrtrk_5ga_n[0] = rtw8812a_pwrtrk_5ga_n[0], + .pwrtrk_5ga_n[1] = rtw8812a_pwrtrk_5ga_n[1], + .pwrtrk_5ga_n[2] = rtw8812a_pwrtrk_5ga_n[2], + .pwrtrk_5ga_p[0] = rtw8812a_pwrtrk_5ga_p[0], + .pwrtrk_5ga_p[1] = rtw8812a_pwrtrk_5ga_p[1], + .pwrtrk_5ga_p[2] = rtw8812a_pwrtrk_5ga_p[2], + .pwrtrk_2gb_n = rtw8812a_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8812a_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8812a_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8812a_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8812a_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8812a_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8812a_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8812a_pwrtrk_2g_cck_a_p, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_5gb_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, + 13, 14, 15, 16, 16, 17, 17, 18, 18}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, + 12, 14, 13, 13, 14, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 14, 15, 15, 16, 16}, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_5gb_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_5ga_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 13, 14, 15, 16, 16, 17, 17, 18, 18}, + {0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 15, 16, 16, 17, 17}, + {0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, + 13, 14, 14, 15, 15, 16, 17, 18, 18}, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_5ga_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2gb_n[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, + 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2gb_p[] = { + 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 8, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2ga_n[] = { + 0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2ga_p[] = { + 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_b_n[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, + 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_b_p[] = { + 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 8, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_a_n[] = { + 0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_a_p[] = { + 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11 +}; + +const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_rfe3_tbl = { + .pwrtrk_5gb_n[0] = rtw8812a_pwrtrk_rfe3_5gb_n[0], + .pwrtrk_5gb_n[1] = rtw8812a_pwrtrk_rfe3_5gb_n[1], + .pwrtrk_5gb_n[2] = rtw8812a_pwrtrk_rfe3_5gb_n[2], + .pwrtrk_5gb_p[0] = rtw8812a_pwrtrk_rfe3_5gb_p[0], + .pwrtrk_5gb_p[1] = rtw8812a_pwrtrk_rfe3_5gb_p[1], + .pwrtrk_5gb_p[2] = rtw8812a_pwrtrk_rfe3_5gb_p[2], + .pwrtrk_5ga_n[0] = rtw8812a_pwrtrk_rfe3_5ga_n[0], + .pwrtrk_5ga_n[1] = rtw8812a_pwrtrk_rfe3_5ga_n[1], + .pwrtrk_5ga_n[2] = rtw8812a_pwrtrk_rfe3_5ga_n[2], + .pwrtrk_5ga_p[0] = rtw8812a_pwrtrk_rfe3_5ga_p[0], + .pwrtrk_5ga_p[1] = rtw8812a_pwrtrk_rfe3_5ga_p[1], + .pwrtrk_5ga_p[2] = rtw8812a_pwrtrk_rfe3_5ga_p[2], + .pwrtrk_2gb_n = rtw8812a_pwrtrk_rfe3_2gb_n, + .pwrtrk_2gb_p = rtw8812a_pwrtrk_rfe3_2gb_p, + .pwrtrk_2ga_n = rtw8812a_pwrtrk_rfe3_2ga_n, + .pwrtrk_2ga_p = rtw8812a_pwrtrk_rfe3_2ga_p, + .pwrtrk_2g_cckb_n = rtw8812a_pwrtrk_rfe3_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8812a_pwrtrk_rfe3_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8812a_pwrtrk_rfe3_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8812a_pwrtrk_rfe3_2g_cck_a_p, +}; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h new file mode 100644 index 000000000000..f7ab5e4cf059 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW8812A_TABLE_H__ +#define __RTW8812A_TABLE_H__ + +extern const struct rtw_table rtw8812a_mac_tbl; +extern const struct rtw_table rtw8812a_agc_tbl; +extern const struct rtw_table rtw8812a_agc_diff_lb_tbl; +extern const struct rtw_table rtw8812a_agc_diff_hb_tbl; +extern const struct rtw_table rtw8812a_bb_tbl; +extern const struct rtw_table rtw8812a_bb_pg_tbl; +extern const struct rtw_table rtw8812a_bb_pg_rfe3_tbl; +extern const struct rtw_table rtw8812a_rf_a_tbl; +extern const struct rtw_table rtw8812a_rf_b_tbl; +extern const struct rtw_table rtw8812a_txpwr_lmt_tbl; + +extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8812a[]; +extern const struct rtw_pwr_seq_cmd * const enter_lps_flow_8812a[]; +extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8812a[]; + +extern const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_tbl; +extern const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_rfe3_tbl; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812au.c b/drivers/net/wireless/realtek/rtw88/rtw8812au.c new file mode 100644 index 000000000000..4da69590a423 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812au.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include <linux/module.h> +#include <linux/usb.h> +#include "main.h" +#include "rtw8812a.h" +#include "usb.h" + +static const struct usb_device_id rtw_8812au_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x2604, 0x0012, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8812au_id_table); + +static struct usb_driver rtw_8812au_driver = { + .name = "rtw_8812au", + .id_table = rtw_8812au_id_table, + .probe = rtw_usb_probe, + .disconnect = rtw_usb_disconnect, +}; +module_usb_driver(rtw_8812au_driver); + +MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8812au driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c new file mode 100644 index 000000000000..db242c9ad68f --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -0,0 +1,1197 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "main.h" +#include "coex.h" +#include "phy.h" +#include "reg.h" +#include "rtw88xxa.h" +#include "rtw8821a.h" +#include "rtw8821a_table.h" +#include "tx.h" + +static void rtw8821a_power_off(struct rtw_dev *rtwdev) +{ + rtw88xxa_power_off(rtwdev, enter_lps_flow_8821a); +} + +static s8 rtw8821a_cck_rx_pwr(u8 lna_idx, u8 vga_idx) +{ + static const s8 lna_gain_table[] = {15, -1, -17, 0, -30, -38}; + s8 rx_pwr_all = 0; + s8 lna_gain; + + switch (lna_idx) { + case 5: + case 4: + case 2: + case 1: + case 0: + lna_gain = lna_gain_table[lna_idx]; + rx_pwr_all = lna_gain - 2 * vga_idx; + break; + default: + break; + } + + return rx_pwr_all; +} + +static void rtw8821a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat) +{ + rtw88xxa_query_phy_status(rtwdev, phy_status, pkt_stat, + rtw8821a_cck_rx_pwr); +} + +static void rtw8821a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) +{ +} + +#define CAL_NUM_8821A 3 +#define MACBB_REG_NUM_8821A 8 +#define AFE_REG_NUM_8821A 4 +#define RF_REG_NUM_8821A 3 + +static void rtw8821a_iqk_backup_rf(struct rtw_dev *rtwdev, u32 *rfa_backup, + const u32 *backup_rf_reg, u32 rf_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Save RF Parameters */ + for (i = 0; i < rf_num; i++) + rfa_backup[i] = rtw_read_rf(rtwdev, RF_PATH_A, + backup_rf_reg[i], MASKDWORD); +} + +static void rtw8821a_iqk_restore_rf(struct rtw_dev *rtwdev, + const u32 *backup_rf_reg, + u32 *RF_backup, u32 rf_reg_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + for (i = 0; i < rf_reg_num; i++) + rtw_write_rf(rtwdev, RF_PATH_A, backup_rf_reg[i], + RFREG_MASK, RF_backup[i]); +} + +static void rtw8821a_iqk_restore_afe(struct rtw_dev *rtwdev, u32 *afe_backup, + const u32 *backup_afe_reg, u32 afe_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Reload AFE Parameters */ + for (i = 0; i < afe_num; i++) + rtw_write32(rtwdev, backup_afe_reg[i], afe_backup[i]); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x0); + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x0); + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x0); + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000); + rtw_write32(rtwdev, REG_LSSI_WRITE_A, 0x00000080); + rtw_write32(rtwdev, REG_TXAGCIDX, 0x00000000); + rtw_write32(rtwdev, REG_IQK_DPD_CFG, 0x20040000); + rtw_write32(rtwdev, REG_CFG_PMPD, 0x20000000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x0); +} + +static void rtw8821a_iqk_rx_fill(struct rtw_dev *rtwdev, + unsigned int rx_x, unsigned int rx_y) +{ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x000003ff, rx_x >> 1); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x03ff0000, (rx_y >> 1) & 0x3ff); +} + +static void rtw8821a_iqk_tx_fill(struct rtw_dev *rtwdev, + unsigned int tx_x, unsigned int tx_y) +{ + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + rtw_write32(rtwdev, REG_LSSI_WRITE_A, 0x00000080); + rtw_write32(rtwdev, REG_IQK_DPD_CFG, 0x20040000); + rtw_write32(rtwdev, REG_CFG_PMPD, 0x20000000); + rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, tx_y); + rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, tx_x); +} + +static void rtw8821a_iqk_tx_vdf_true(struct rtw_dev *rtwdev, u32 cal, + bool *tx0iqkok, + int tx_x0[CAL_NUM_8821A], + int tx_y0[CAL_NUM_8821A]) +{ + u32 cal_retry, delay_count, iqk_ready, tx_fail; + int tx_dt[3], vdf_y[3], vdf_x[3]; + int k; + + for (k = 0; k < 3; k++) { + switch (k) { + case 0: + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, + 0x18008c38); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c38); + rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x0); + break; + case 1: + rtw_write32_mask(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, + BIT(28), 0x0); + rtw_write32_mask(rtwdev, REG_OFDM0_A_TX_AFE, + BIT(28), 0x0); + rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x0); + break; + case 2: + rtw_dbg(rtwdev, RTW_DBG_RFK, + "vdf_y[1] = %x vdf_y[0] = %x\n", + vdf_y[1] >> 21 & 0x00007ff, + vdf_y[0] >> 21 & 0x00007ff); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "vdf_x[1] = %x vdf_x[0] = %x\n", + vdf_x[1] >> 21 & 0x00007ff, + vdf_x[0] >> 21 & 0x00007ff); + + tx_dt[cal] = (vdf_y[1] >> 20) - (vdf_y[0] >> 20); + tx_dt[cal] = (16 * tx_dt[cal]) * 10000 / 15708; + tx_dt[cal] = (tx_dt[cal] >> 1) + (tx_dt[cal] & BIT(0)); + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, + 0x18008c20); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c20); + rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_INTPO_SETA, 0x3fff0000, + tx_dt[cal] & 0x00003fff); + break; + } + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + + for (cal_retry = 0; cal_retry < 10; cal_retry++) { + /* one shot */ + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + + for (delay_count = 0; delay_count < 20; delay_count++) { + iqk_ready = rtw_read32_mask(rtwdev, + REG_IQKA_END, + BIT(10)); + + /* Originally: if (~iqk_ready || delay_count > 20) + * that looks like a typo so make it more explicit + */ + iqk_ready = true; + + if (iqk_ready) + break; + + mdelay(1); + } + + if (delay_count < 20) { + /* ============TXIQK Check============== */ + tx_fail = rtw_read32_mask(rtwdev, + REG_IQKA_END, + BIT(12)); + + /* Originally: if (~tx_fail) { + * It looks like a typo, so make it more explicit. + */ + tx_fail = false; + + if (!tx_fail) { + rtw_write32(rtwdev, REG_RFECTL_A, + 0x02000000); + vdf_x[k] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + vdf_x[k] <<= 21; + + rtw_write32(rtwdev, REG_RFECTL_A, + 0x04000000); + vdf_y[k] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + vdf_y[k] <<= 21; + + *tx0iqkok = true; + break; + } + + rtw_write32_mask(rtwdev, REG_IQC_Y, + 0x000007ff, 0x0); + rtw_write32_mask(rtwdev, REG_IQC_X, + 0x000007ff, 0x200); + } + + *tx0iqkok = false; + } + } + + if (k == 3) { + tx_x0[cal] = vdf_x[k - 1]; + tx_y0[cal] = vdf_y[k - 1]; + } +} + +static void rtw8821a_iqk_tx_vdf_false(struct rtw_dev *rtwdev, u32 cal, + bool *tx0iqkok, + int tx_x0[CAL_NUM_8821A], + int tx_y0[CAL_NUM_8821A]) +{ + u32 cal_retry, delay_count, iqk_ready, tx_fail; + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + + for (cal_retry = 0; cal_retry < 10; cal_retry++) { + /* one shot */ + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + + for (delay_count = 0; delay_count < 20; delay_count++) { + iqk_ready = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(10)); + + /* Originally: if (~iqk_ready || delay_count > 20) + * that looks like a typo so make it more explicit + */ + iqk_ready = true; + + if (iqk_ready) + break; + + mdelay(1); + } + + if (delay_count < 20) { + /* ============TXIQK Check============== */ + tx_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(12)); + + /* Originally: if (~tx_fail) { + * It looks like a typo, so make it more explicit. + */ + tx_fail = false; + + if (!tx_fail) { + rtw_write32(rtwdev, REG_RFECTL_A, 0x02000000); + tx_x0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END, + 0x07ff0000); + tx_x0[cal] <<= 21; + + rtw_write32(rtwdev, REG_RFECTL_A, 0x04000000); + tx_y0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END, + 0x07ff0000); + tx_y0[cal] <<= 21; + + *tx0iqkok = true; + break; + } + + rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, 0x0); + rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, 0x200); + } + + *tx0iqkok = false; + } +} + +static void rtw8821a_iqk_rx(struct rtw_dev *rtwdev, u32 cal, bool *rx0iqkok, + int rx_x0[CAL_NUM_8821A], + int rx_y0[CAL_NUM_8821A]) +{ + u32 cal_retry, delay_count, iqk_ready, rx_fail; + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + + for (cal_retry = 0; cal_retry < 10; cal_retry++) { + /* one shot */ + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + + for (delay_count = 0; delay_count < 20; delay_count++) { + iqk_ready = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(10)); + + /* Originally: if (~iqk_ready || delay_count > 20) + * that looks like a typo so make it more explicit + */ + iqk_ready = true; + + if (iqk_ready) + break; + + mdelay(1); + } + + if (delay_count < 20) { + /* ============RXIQK Check============== */ + rx_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(11)); + if (!rx_fail) { + rtw_write32(rtwdev, REG_RFECTL_A, 0x06000000); + rx_x0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END, + 0x07ff0000); + rx_x0[cal] <<= 21; + + rtw_write32(rtwdev, REG_RFECTL_A, 0x08000000); + rx_y0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END, + 0x07ff0000); + rx_y0[cal] <<= 21; + + *rx0iqkok = true; + break; + } + + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x000003ff, 0x200 >> 1); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x03ff0000, 0x0 >> 1); + } + + *rx0iqkok = false; + } +} + +static void rtw8821a_iqk(struct rtw_dev *rtwdev) +{ + int tx_average = 0, rx_average = 0, rx_iqk_loop = 0; + const struct rtw_efuse *efuse = &rtwdev->efuse; + int tx_x = 0, tx_y = 0, rx_x = 0, rx_y = 0; + const struct rtw_hal *hal = &rtwdev->hal; + bool tx0iqkok = false, rx0iqkok = false; + int rx_x_temp = 0, rx_y_temp = 0; + int rx_x0[2][CAL_NUM_8821A]; + int rx_y0[2][CAL_NUM_8821A]; + int tx_x0[CAL_NUM_8821A]; + int tx_y0[CAL_NUM_8821A]; + bool rx_finish1 = false; + bool rx_finish2 = false; + bool vdf_enable; + u32 cal; + int i; + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "band_width = %d, ext_pa = %d, ext_pa_5g = %d\n", + hal->current_band_width, efuse->ext_pa_2g, efuse->ext_pa_5g); + + vdf_enable = hal->current_band_width == RTW_CHANNEL_WIDTH_80; + + for (cal = 0; cal < CAL_NUM_8821A; cal++) { + /* path-A LOK */ + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* ========path-A AFE all on======== */ + /* Port 0 DAC/ADC on */ + rtw_write32(rtwdev, REG_AFE_PWR1_A, 0x77777777); + rtw_write32(rtwdev, REG_AFE_PWR2_A, 0x77777777); + + rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_A, 0x19791979); + + /* hardware 3-wire off */ + rtw_write32_mask(rtwdev, REG_3WIRE_SWA, 0xf, 0x4); + + /* LOK setting */ + + /* 1. DAC/ADC sampling rate (160 MHz) */ + rtw_write32_mask(rtwdev, REG_CK_MONHA, GENMASK(26, 24), 0x7); + + /* 2. LoK RF setting (at BW = 20M) */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80002); + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x00c00, 0x3); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x20000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x0003f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xf3fc3); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, + 0x931d5); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001); + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1); + /* TX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000); + /* RX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000); + /* [0]:AGC_en, [15]:idac_K_Mask */ + rtw_write32(rtwdev, REG_IQK_COM96, 0x00462910); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + if (efuse->ext_pa_5g) + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403f7); + else + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403f4); + + if (hal->current_band_type == RTW_BAND_5G) + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x68163e96); + else + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28163e96); + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXMOD, 0x7fe00, + rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, 0xffc00)); + + if (hal->current_band_width == RTW_CHANNEL_WIDTH_40) + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, + RF18_BW_MASK, 0x1); + else if (hal->current_band_width == RTW_CHANNEL_WIDTH_80) + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, + RF18_BW_MASK, 0x0); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + /* 3. TX RF setting */ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x20000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x0003f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xf3fc3); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d5); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000); + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1); + /* TX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000); + /* RX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000); + /* [0]:AGC_en, [15]:idac_K_Mask */ + rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a910); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + if (efuse->ext_pa_5g) + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403f7); + else + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403e3); + + if (hal->current_band_type == RTW_BAND_5G) + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x40163e96); + else + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x00163e96); + + if (vdf_enable) + rtw8821a_iqk_tx_vdf_true(rtwdev, cal, &tx0iqkok, + tx_x0, tx_y0); + else + rtw8821a_iqk_tx_vdf_false(rtwdev, cal, &tx0iqkok, + tx_x0, tx_y0); + + if (!tx0iqkok) + break; /* TXK fail, Don't do RXK */ + + /* ====== RX IQK ====== */ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + /* 1. RX RF setting */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x30000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x0002f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xfffbb); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x88001); + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d8); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000); + + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000, + (tx_x0[cal] >> 21) & 0x000007ff); + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF, + (tx_y0[cal] >> 21) & 0x000007ff); + rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x0); + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a911); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x38008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x18008c10); + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x02140119); + + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE) + rx_iqk_loop = 2; /* for 2% fail; */ + else + rx_iqk_loop = 1; + + for (i = 0; i < rx_iqk_loop; i++) { + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE && i == 0) + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28161100); /* Good */ + else + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28160d00); + + rtw8821a_iqk_rx(rtwdev, cal, &rx0iqkok, + rx_x0[i], rx_y0[i]); + } + + if (tx0iqkok) + tx_average++; + if (rx0iqkok) + rx_average++; + } + + /* FillIQK Result */ + + if (tx_average == 0) + return; + + for (i = 0; i < tx_average; i++) + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x0[%d] = %x ;; tx_y0[%d] = %x\n", + i, (tx_x0[i] >> 21) & 0x000007ff, + i, (tx_y0[i] >> 21) & 0x000007ff); + + if (rtw88xxa_iqk_finish(tx_average, 3, tx_x0, tx_y0, + &tx_x, &tx_y, true, true)) + rtw8821a_iqk_tx_fill(rtwdev, tx_x, tx_y); + else + rtw8821a_iqk_tx_fill(rtwdev, 0x200, 0x0); + + if (rx_average == 0) + return; + + for (i = 0; i < rx_average; i++) { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x0[0][%d] = %x ;; rx_y0[0][%d] = %x\n", + i, (rx_x0[0][i] >> 21) & 0x000007ff, + i, (rx_y0[0][i] >> 21) & 0x000007ff); + + if (rx_iqk_loop == 2) + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x0[1][%d] = %x ;; rx_y0[1][%d] = %x\n", + i, (rx_x0[1][i] >> 21) & 0x000007ff, + i, (rx_y0[1][i] >> 21) & 0x000007ff); + } + + rx_finish1 = rtw88xxa_iqk_finish(rx_average, 4, rx_x0[0], rx_y0[0], + &rx_x_temp, &rx_y_temp, true, true); + + if (rx_finish1) { + rx_x = rx_x_temp; + rx_y = rx_y_temp; + } + + if (rx_iqk_loop == 2) { + rx_finish2 = rtw88xxa_iqk_finish(rx_average, 4, + rx_x0[1], rx_y0[1], + &rx_x, &rx_y, true, true); + + if (rx_finish1 && rx_finish2) { + rx_x = (rx_x + rx_x_temp) / 2; + rx_y = (rx_y + rx_y_temp) / 2; + } + } + + if (rx_finish1 || rx_finish2) + rtw8821a_iqk_rx_fill(rtwdev, rx_x, rx_y); + else + rtw8821a_iqk_rx_fill(rtwdev, 0x200, 0x0); +} + +static void rtw8821a_do_iqk(struct rtw_dev *rtwdev) +{ + static const u32 backup_macbb_reg[MACBB_REG_NUM_8821A] = { + 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0x838, 0x82c + }; + static const u32 backup_afe_reg[AFE_REG_NUM_8821A] = { + 0xc5c, 0xc60, 0xc64, 0xc68 + }; + static const u32 backup_rf_reg[RF_REG_NUM_8821A] = { + 0x65, 0x8f, 0x0 + }; + u32 macbb_backup[MACBB_REG_NUM_8821A]; + u32 afe_backup[AFE_REG_NUM_8821A]; + u32 rfa_backup[RF_REG_NUM_8821A]; + + rtw88xxa_iqk_backup_mac_bb(rtwdev, macbb_backup, + backup_macbb_reg, MACBB_REG_NUM_8821A); + rtw88xxa_iqk_backup_afe(rtwdev, afe_backup, + backup_afe_reg, AFE_REG_NUM_8821A); + rtw8821a_iqk_backup_rf(rtwdev, rfa_backup, + backup_rf_reg, RF_REG_NUM_8821A); + + rtw88xxa_iqk_configure_mac(rtwdev); + + rtw8821a_iqk(rtwdev); + + rtw8821a_iqk_restore_rf(rtwdev, backup_rf_reg, + rfa_backup, RF_REG_NUM_8821A); + rtw8821a_iqk_restore_afe(rtwdev, afe_backup, + backup_afe_reg, AFE_REG_NUM_8821A); + rtw88xxa_iqk_restore_mac_bb(rtwdev, macbb_backup, + backup_macbb_reg, MACBB_REG_NUM_8821A); +} + +static void rtw8821a_phy_calibration(struct rtw_dev *rtwdev) +{ + rtw8821a_do_iqk(rtwdev); +} + +static void rtw8821a_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + if (!dm_info->pwr_trk_triggered) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, + GENMASK(17, 16), 0x03); + dm_info->pwr_trk_triggered = true; + return; + } + + rtw88xxa_phy_pwrtrack(rtwdev, NULL, rtw8821a_do_iqk); + dm_info->pwr_trk_triggered = false; +} + +static void rtw8821a_fill_txdesc_checksum(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + u8 *txdesc) +{ + fill_txdesc_checksum_common(txdesc, 16); +} + +static void rtw8821a_coex_cfg_init(struct rtw_dev *rtwdev) +{ + u8 val8; + + /* BT report packet sample rate */ + rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0x5); + + val8 = BIT_STATIS_BT_EN; + if (rtwdev->efuse.share_ant) + val8 |= BIT_R_GRANTALL_WLMASK; + rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, val8); + + /* enable BT counter statistics */ + rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x3); + + /* enable PTA */ + rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN); +} + +static void rtw8821a_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, + u8 pos_type) +{ + bool share_ant = rtwdev->efuse.share_ant; + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + u32 phase = coex_dm->cur_ant_pos_type; + + if (!rtwdev->efuse.btcoex) + return; + + switch (phase) { + case COEX_SET_ANT_POWERON: + case COEX_SET_ANT_INIT: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, + share_ant ? PTA_CTRL_PIN : DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1); + break; + case COEX_SET_ANT_WONLY: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_clr(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1); + break; + case COEX_SET_ANT_2G: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_clr(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, + share_ant ? PTA_CTRL_PIN : DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1); + break; + case COEX_SET_ANT_5G: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, + share_ant ? 0x2 : 0x1); + break; + case COEX_SET_ANT_WOFF: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, + share_ant ? 0x2 : 0x1); + break; + default: + rtw_warn(rtwdev, "%s: not handling phase %d\n", + __func__, phase); + break; + } +} + +static void rtw8821a_coex_cfg_gnt_fix(struct rtw_dev *rtwdev) +{ +} + +static void rtw8821a_coex_cfg_gnt_debug(struct rtw_dev *rtwdev) +{ +} + +static void rtw8821a_coex_cfg_rfe_type(struct rtw_dev *rtwdev) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_rfe *coex_rfe = &coex->rfe; + + coex_rfe->ant_switch_exist = true; +} + +static void rtw8821a_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + struct rtw_efuse *efuse = &rtwdev->efuse; + bool share_ant = efuse->share_ant; + + if (share_ant) + return; + + if (wl_pwr == coex_dm->cur_wl_pwr_lvl) + return; + + coex_dm->cur_wl_pwr_lvl = wl_pwr; +} + +static void rtw8821a_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) +{ +} + +static const struct rtw_chip_ops rtw8821a_ops = { + .power_on = rtw88xxa_power_on, + .power_off = rtw8821a_power_off, + .phy_set_param = NULL, + .read_efuse = rtw88xxa_read_efuse, + .query_phy_status = rtw8821a_query_phy_status, + .set_channel = rtw88xxa_set_channel, + .mac_init = NULL, + .read_rf = rtw88xxa_phy_read_rf, + .write_rf = rtw_phy_write_rf_reg_sipi, + .set_antenna = NULL, + .set_tx_power_index = rtw88xxa_set_tx_power_index, + .cfg_ldo25 = rtw8821a_cfg_ldo25, + .efuse_grant = rtw88xxa_efuse_grant, + .false_alarm_statistics = rtw88xxa_false_alarm_statistics, + .phy_calibration = rtw8821a_phy_calibration, + .cck_pd_set = rtw88xxa_phy_cck_pd_set, + .pwr_track = rtw8821a_pwr_track, + .config_bfee = NULL, + .set_gid_table = NULL, + .cfg_csi_rate = NULL, + .fill_txdesc_checksum = rtw8821a_fill_txdesc_checksum, + .coex_set_init = rtw8821a_coex_cfg_init, + .coex_set_ant_switch = rtw8821a_coex_cfg_ant_switch, + .coex_set_gnt_fix = rtw8821a_coex_cfg_gnt_fix, + .coex_set_gnt_debug = rtw8821a_coex_cfg_gnt_debug, + .coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type, + .coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power, + .coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain, +}; + +static const struct rtw_page_table page_table_8821a[] = { + /* hq_num, nq_num, lq_num, exq_num, gapq_num */ + {0, 0, 0, 0, 0}, /* SDIO */ + {0, 0, 0, 0, 0}, /* PCI */ + {8, 0, 0, 0, 1}, /* 2 bulk out endpoints */ + {8, 0, 8, 0, 1}, /* 3 bulk out endpoints */ + {8, 0, 8, 4, 1}, /* 4 bulk out endpoints */ +}; + +static const struct rtw_rqpn rqpn_table_8821a[] = { + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH, + RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, +}; + +static const struct rtw_prioq_addrs prioq_addrs_8821a = { + .prio[RTW_DMA_MAPPING_EXTRA] = { + .rsvd = REG_RQPN_NPQ + 2, .avail = REG_RQPN_NPQ + 3, + }, + .prio[RTW_DMA_MAPPING_LOW] = { + .rsvd = REG_RQPN + 1, .avail = REG_FIFOPAGE_CTRL_2 + 1, + }, + .prio[RTW_DMA_MAPPING_NORMAL] = { + .rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1, + }, + .prio[RTW_DMA_MAPPING_HIGH] = { + .rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2, + }, + .wsize = false, +}; + +static const struct rtw_hw_reg rtw8821a_dig[] = { + [0] = { .addr = REG_RXIGI_A, .mask = 0x7f }, +}; + +static const struct rtw_rfe_def rtw8821a_rfe_defs[] = { + [0] = { .phy_pg_tbl = &rtw8821a_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8821a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8821a_rtw_pwr_track_tbl, }, +}; + +/* TODO */ +/* rssi in percentage % (dbm = % - 100) */ +static const u8 wl_rssi_step_8821a[] = {101, 45, 101, 40}; +static const u8 bt_rssi_step_8821a[] = {101, 101, 101, 101}; + +/* table_sant_8821a, table_nsant_8821a, tdma_sant_8821a, and tdma_nsant_8821a + * are copied from rtw8821c.c because the 8821au driver's tables are not + * compatible with the coex code in rtw88. + * + * tdma case 112 (A2DP) byte 0 had to be modified from 0x61 to 0x51, + * otherwise the firmware gets confused after pausing the music: + * rtw_8821au 1-2:1.2: [BTCoex], Bt_info[1], len=7, data=[81 00 0a 01 00 00] + * - 81 means PAN (personal area network) when it should be 4x (A2DP) + * The music is not smooth with the PAN algorithm. + */ + +/* Shared-Antenna Coex Table */ +static const struct coex_table_para table_sant_8821a[] = { + {0x55555555, 0x55555555}, /* case-0 */ + {0x55555555, 0x55555555}, + {0x66555555, 0x66555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xfafafafa, 0xfafafafa}, /* case-5 */ + {0x6a5a5555, 0xaaaaaaaa}, + {0x6a5a56aa, 0x6a5a56aa}, + {0x6a5a5a5a, 0x6a5a5a5a}, + {0x66555555, 0x5a5a5a5a}, + {0x66555555, 0x6a5a5a5a}, /* case-10 */ + {0x66555555, 0xaaaaaaaa}, + {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0x6aaa6aaa}, + {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0xaaaaaaaa}, /* case-15 */ + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x6afa5afa}, + {0xaaffffaa, 0xfafafafa}, + {0xaa5555aa, 0x5a5a5a5a}, + {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */ + {0xaa5555aa, 0xaaaaaaaa}, + {0xffffffff, 0x55555555}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x5a5a5aaa}, /* case-25 */ + {0x55555555, 0x5a5a5a5a}, + {0x55555555, 0xaaaaaaaa}, + {0x66555555, 0x6a5a6a5a}, + {0x66556655, 0x66556655}, + {0x66556aaa, 0x6a5a6aaa}, /* case-30 */ + {0xffffffff, 0x5aaa5aaa}, + {0x56555555, 0x5a5a5aaa} +}; + +/* Non-Shared-Antenna Coex Table */ +static const struct coex_table_para table_nsant_8821a[] = { + {0xffffffff, 0xffffffff}, /* case-100 */ + {0xffff55ff, 0xfafafafa}, + {0x66555555, 0x66555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xffffffff, 0xffffffff}, /* case-105 */ + {0x5afa5afa, 0x5afa5afa}, + {0x55555555, 0xfafafafa}, + {0x66555555, 0xfafafafa}, + {0x66555555, 0x5a5a5a5a}, + {0x66555555, 0x6a5a5a5a}, /* case-110 */ + {0x66555555, 0xaaaaaaaa}, + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0xaaaaaaaa}, + {0xffff55ff, 0xffff55ff}, /* case-115 */ + {0xaaffffaa, 0x5afa5afa}, + {0xaaffffaa, 0xaaaaaaaa}, + {0xffffffff, 0xfafafafa}, + {0xffff55ff, 0xfafafafa}, + {0xffffffff, 0xaaaaaaaa}, /* case-120 */ + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0x5afa5afa}, + {0x55ff55ff, 0x55ff55ff} +}; + +/* Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_sant_8821a[] = { + { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */ + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, + { {0x61, 0x35, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, /* case-5 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x35, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */ + { {0x61, 0x08, 0x03, 0x11, 0x15} }, + { {0x61, 0x08, 0x03, 0x10, 0x14} }, + { {0x51, 0x08, 0x03, 0x10, 0x54} }, + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x11, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */ + { {0x51, 0x4a, 0x03, 0x10, 0x50} }, + { {0x51, 0x08, 0x03, 0x30, 0x54} }, + { {0x55, 0x08, 0x03, 0x10, 0x54} }, + { {0x65, 0x10, 0x03, 0x11, 0x10} }, + { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */ + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x61, 0x08, 0x03, 0x11, 0x11} } +}; + +/* Non-Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_nsant_8821a[] = { + { {0x00, 0x00, 0x00, 0x40, 0x00} }, /* case-100 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, + { {0x61, 0x25, 0x03, 0x11, 0x11} }, + { {0x61, 0x35, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */ + { {0x61, 0x10, 0x03, 0x11, 0x11} }, + { {0x51, 0x08, 0x03, 0x10, 0x14} }, /* a2dp high rssi */ + { {0x51, 0x08, 0x03, 0x10, 0x54} }, /* a2dp not high rssi */ + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x10, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, /* case-120 */ + { {0x51, 0x10, 0x03, 0x10, 0x50} } +}; + +/* TODO */ +static const struct coex_rf_para rf_para_tx_8821a[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {8, 17, true, 4}, + {7, 18, true, 4}, + {6, 19, true, 4}, + {5, 20, true, 4} +}; + +static const struct coex_rf_para rf_para_rx_8821a[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {3, 24, true, 5}, + {2, 26, true, 5}, + {1, 27, true, 5}, + {0, 28, true, 5} +}; + +static_assert(ARRAY_SIZE(rf_para_tx_8821a) == ARRAY_SIZE(rf_para_rx_8821a)); + +static const struct coex_5g_afh_map afh_5g_8821a[] = { {0, 0, 0} }; + +static const struct rtw_reg_domain coex_info_hw_regs_8821a[] = { + {0xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0xCBA, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x430, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x434, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x42a, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0x426, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x45e, BIT(3), RTW_REG_DOMAIN_MAC8}, + {0x454, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x4c, BIT(24) | BIT(23), RTW_REG_DOMAIN_MAC32}, + {0x64, BIT(0), RTW_REG_DOMAIN_MAC8}, + {0x4c6, BIT(4), RTW_REG_DOMAIN_MAC8}, + {0x40, BIT(5), RTW_REG_DOMAIN_MAC8}, + {0x1, RFREG_MASK, RTW_REG_DOMAIN_RF_A}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x550, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x522, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x953, BIT(1), RTW_REG_DOMAIN_MAC8}, + {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, +}; + +const struct rtw_chip_info rtw8821a_hw_spec = { + .ops = &rtw8821a_ops, + .id = RTW_CHIP_TYPE_8821A, + .fw_name = "rtw88/rtw8821a_fw.bin", + .wlan_cpu = RTW_WCPU_11N, + .tx_pkt_desc_sz = 40, + .tx_buf_desc_sz = 16, + .rx_pkt_desc_sz = 24, + .rx_buf_desc_sz = 8, + .phy_efuse_size = 512, + .log_efuse_size = 512, + .ptct_efuse_size = 96 + 1, /* TODO or just 18? */ + .txff_size = 65536, + .rxff_size = 16128, + .rsvd_drv_pg_num = 8, + .txgi_factor = 1, + .is_pwr_by_rate_dec = true, + .max_power_index = 0x3f, + .csi_buf_pg_num = 0, + .band = RTW_BAND_2G | RTW_BAND_5G, + .page_size = 256, + .dig_min = 0x20, + .ht_supported = true, + .vht_supported = true, + .lps_deep_mode_supported = 0, + .sys_func_en = 0xFD, + .pwr_on_seq = card_enable_flow_8821a, + .pwr_off_seq = card_disable_flow_8821a, + .page_table = page_table_8821a, + .rqpn_table = rqpn_table_8821a, + .prioq_addrs = &prioq_addrs_8821a, + .intf_table = NULL, + .dig = rtw8821a_dig, + .rf_sipi_addr = {REG_LSSI_WRITE_A, REG_LSSI_WRITE_B}, + .ltecoex_addr = NULL, + .mac_tbl = &rtw8821a_mac_tbl, + .agc_tbl = &rtw8821a_agc_tbl, + .bb_tbl = &rtw8821a_bb_tbl, + .rf_tbl = {&rtw8821a_rf_a_tbl}, + .rfe_defs = rtw8821a_rfe_defs, + .rfe_defs_size = ARRAY_SIZE(rtw8821a_rfe_defs), + .rx_ldpc = false, + .hw_feature_report = false, + .c2h_ra_report_size = 4, + .old_datarate_fb_limit = true, + .usb_tx_agg_desc_num = 6, + .iqk_threshold = 8, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, + + .coex_para_ver = 20190509, /* glcoex_ver_date_8821a_1ant */ + .bt_desired_ver = 0x62, /* But for 2 ant it's 0x5c */ + .scbd_support = false, + .new_scbd10_def = false, + .ble_hid_profile_support = false, + .wl_mimo_ps_support = false, + .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, + .bt_rssi_type = COEX_BTRSSI_RATIO, + .ant_isolation = 10, + .rssi_tolerance = 2, + .wl_rssi_step = wl_rssi_step_8821a, + .bt_rssi_step = bt_rssi_step_8821a, + .table_sant_num = ARRAY_SIZE(table_sant_8821a), + .table_sant = table_sant_8821a, + .table_nsant_num = ARRAY_SIZE(table_nsant_8821a), + .table_nsant = table_nsant_8821a, + .tdma_sant_num = ARRAY_SIZE(tdma_sant_8821a), + .tdma_sant = tdma_sant_8821a, + .tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8821a), + .tdma_nsant = tdma_nsant_8821a, + .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8821a), + .wl_rf_para_tx = rf_para_tx_8821a, + .wl_rf_para_rx = rf_para_rx_8821a, + .bt_afh_span_bw20 = 0x20, + .bt_afh_span_bw40 = 0x30, + .afh_5g_num = ARRAY_SIZE(afh_5g_8821a), + .afh_5g = afh_5g_8821a, + + .coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8821a), + .coex_info_hw_regs = coex_info_hw_regs_8821a, +}; +EXPORT_SYMBOL(rtw8821a_hw_spec); + +MODULE_FIRMWARE("rtw88/rtw8821a_fw.bin"); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.h b/drivers/net/wireless/realtek/rtw88/rtw8821a.h new file mode 100644 index 000000000000..1b2e548f7234 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW8821A_H__ +#define __RTW8821A_H__ + +extern const struct rtw_chip_info rtw8821a_hw_spec; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c new file mode 100644 index 000000000000..c8fd8e331f69 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c @@ -0,0 +1,2350 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "main.h" +#include "phy.h" +#include "rtw8821a_table.h" + +static const u32 rtw8821a_mac[] = { + 0x421, 0x0000000F, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000007, + 0x437, 0x00000008, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000007, + 0x43F, 0x00000008, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000010, + 0x445, 0x00000000, + 0x446, 0x00000000, + 0x447, 0x00000000, + 0x448, 0x00000000, + 0x449, 0x000000F0, + 0x44A, 0x0000000F, + 0x44B, 0x0000003E, + 0x44C, 0x00000010, + 0x44D, 0x00000000, + 0x44E, 0x00000000, + 0x44F, 0x00000000, + 0x450, 0x00000000, + 0x451, 0x000000F0, + 0x452, 0x0000000F, + 0x453, 0x00000000, + 0x456, 0x0000005E, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x4C8, 0x0000003F, + 0x4C9, 0x000000FF, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55C, 0x00000050, + 0x55D, 0x000000FF, + 0x605, 0x00000030, + 0x607, 0x00000007, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x638, 0x00000050, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000040, + 0x642, 0x00000040, + 0x643, 0x00000000, + 0x652, 0x000000C8, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + 0x718, 0x00000040, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821a_mac, rtw_phy_cfg_mac); + +static const u32 rtw8821a_agc[] = { + 0x81C, 0xBF000001, + 0x81C, 0xBF020001, + 0x81C, 0xBF040001, + 0x81C, 0xBF060001, + 0x81C, 0xBE080001, + 0x81C, 0xBD0A0001, + 0x81C, 0xBC0C0001, + 0x81C, 0xBA0E0001, + 0x81C, 0xB9100001, + 0x81C, 0xB8120001, + 0x81C, 0xB7140001, + 0x81C, 0xB6160001, + 0x81C, 0xB5180001, + 0x81C, 0xB41A0001, + 0x81C, 0xB31C0001, + 0x81C, 0xB21E0001, + 0x81C, 0xB1200001, + 0x81C, 0xB0220001, + 0x81C, 0xAF240001, + 0x81C, 0xAE260001, + 0x81C, 0xAD280001, + 0x81C, 0xAC2A0001, + 0x81C, 0xAB2C0001, + 0x81C, 0xAA2E0001, + 0x81C, 0xA9300001, + 0x81C, 0xA8320001, + 0x81C, 0xA7340001, + 0x81C, 0xA6360001, + 0x81C, 0xA5380001, + 0x81C, 0xA43A0001, + 0x81C, 0x683C0001, + 0x81C, 0x673E0001, + 0x81C, 0x66400001, + 0x81C, 0x65420001, + 0x81C, 0x64440001, + 0x81C, 0x63460001, + 0x81C, 0x62480001, + 0x81C, 0x614A0001, + 0x81C, 0x474C0001, + 0x81C, 0x464E0001, + 0x81C, 0x45500001, + 0x81C, 0x44520001, + 0x81C, 0x43540001, + 0x81C, 0x42560001, + 0x81C, 0x41580001, + 0x81C, 0x285A0001, + 0x81C, 0x275C0001, + 0x81C, 0x265E0001, + 0x81C, 0x25600001, + 0x81C, 0x24620001, + 0x81C, 0x0A640001, + 0x81C, 0x09660001, + 0x81C, 0x08680001, + 0x81C, 0x076A0001, + 0x81C, 0x066C0001, + 0x81C, 0x056E0001, + 0x81C, 0x04700001, + 0x81C, 0x03720001, + 0x81C, 0x02740001, + 0x81C, 0x01760001, + 0x81C, 0x01780001, + 0x81C, 0x017A0001, + 0x81C, 0x017C0001, + 0x81C, 0x017E0001, + 0x8000020c, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000101, + 0x81C, 0xFA020101, + 0x81C, 0xF9040101, + 0x81C, 0xF8060101, + 0x81C, 0xF7080101, + 0x81C, 0xF60A0101, + 0x81C, 0xF50C0101, + 0x81C, 0xF40E0101, + 0x81C, 0xF3100101, + 0x81C, 0xF2120101, + 0x81C, 0xF1140101, + 0x81C, 0xF0160101, + 0x81C, 0xEF180101, + 0x81C, 0xEE1A0101, + 0x81C, 0xED1C0101, + 0x81C, 0xEC1E0101, + 0x81C, 0xEB200101, + 0x81C, 0xEA220101, + 0x81C, 0xE9240101, + 0x81C, 0xE8260101, + 0x81C, 0xE7280101, + 0x81C, 0xE62A0101, + 0x81C, 0xE52C0101, + 0x81C, 0xE42E0101, + 0x81C, 0xE3300101, + 0x81C, 0xA5320101, + 0x81C, 0xA4340101, + 0x81C, 0xA3360101, + 0x81C, 0x87380101, + 0x81C, 0x863A0101, + 0x81C, 0x853C0101, + 0x81C, 0x843E0101, + 0x81C, 0x69400101, + 0x81C, 0x68420101, + 0x81C, 0x67440101, + 0x81C, 0x66460101, + 0x81C, 0x49480101, + 0x81C, 0x484A0101, + 0x81C, 0x474C0101, + 0x81C, 0x2A4E0101, + 0x81C, 0x29500101, + 0x81C, 0x28520101, + 0x81C, 0x27540101, + 0x81C, 0x26560101, + 0x81C, 0x25580101, + 0x81C, 0x245A0101, + 0x81C, 0x235C0101, + 0x81C, 0x055E0101, + 0x81C, 0x04600101, + 0x81C, 0x03620101, + 0x81C, 0x02640101, + 0x81C, 0x01660101, + 0x81C, 0x01680101, + 0x81C, 0x016A0101, + 0x81C, 0x016C0101, + 0x81C, 0x016E0101, + 0x81C, 0x01700101, + 0x81C, 0x01720101, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000101, + 0x81C, 0xFA020101, + 0x81C, 0xF9040101, + 0x81C, 0xF8060101, + 0x81C, 0xF7080101, + 0x81C, 0xF60A0101, + 0x81C, 0xF50C0101, + 0x81C, 0xF40E0101, + 0x81C, 0xF3100101, + 0x81C, 0xF2120101, + 0x81C, 0xF1140101, + 0x81C, 0xF0160101, + 0x81C, 0xEF180101, + 0x81C, 0xEE1A0101, + 0x81C, 0xED1C0101, + 0x81C, 0xEC1E0101, + 0x81C, 0xEB200101, + 0x81C, 0xEA220101, + 0x81C, 0xE9240101, + 0x81C, 0xE8260101, + 0x81C, 0xE7280101, + 0x81C, 0xE62A0101, + 0x81C, 0xE52C0101, + 0x81C, 0xE42E0101, + 0x81C, 0xE3300101, + 0x81C, 0xA5320101, + 0x81C, 0xA4340101, + 0x81C, 0xA3360101, + 0x81C, 0x87380101, + 0x81C, 0x863A0101, + 0x81C, 0x853C0101, + 0x81C, 0x843E0101, + 0x81C, 0x69400101, + 0x81C, 0x68420101, + 0x81C, 0x67440101, + 0x81C, 0x66460101, + 0x81C, 0x49480101, + 0x81C, 0x484A0101, + 0x81C, 0x474C0101, + 0x81C, 0x2A4E0101, + 0x81C, 0x29500101, + 0x81C, 0x28520101, + 0x81C, 0x27540101, + 0x81C, 0x26560101, + 0x81C, 0x25580101, + 0x81C, 0x245A0101, + 0x81C, 0x235C0101, + 0x81C, 0x055E0101, + 0x81C, 0x04600101, + 0x81C, 0x03620101, + 0x81C, 0x02640101, + 0x81C, 0x01660101, + 0x81C, 0x01680101, + 0x81C, 0x016A0101, + 0x81C, 0x016C0101, + 0x81C, 0x016E0101, + 0x81C, 0x01700101, + 0x81C, 0x01720101, + 0xA0000000, 0x00000000, + 0x81C, 0xFF000101, + 0x81C, 0xFF020101, + 0x81C, 0xFE040101, + 0x81C, 0xFD060101, + 0x81C, 0xFC080101, + 0x81C, 0xFD0A0101, + 0x81C, 0xFC0C0101, + 0x81C, 0xFB0E0101, + 0x81C, 0xFA100101, + 0x81C, 0xF9120101, + 0x81C, 0xF8140101, + 0x81C, 0xF7160101, + 0x81C, 0xF6180101, + 0x81C, 0xF51A0101, + 0x81C, 0xF41C0101, + 0x81C, 0xF31E0101, + 0x81C, 0xF2200101, + 0x81C, 0xF1220101, + 0x81C, 0xF0240101, + 0x81C, 0xEF260101, + 0x81C, 0xEE280101, + 0x81C, 0xED2A0101, + 0x81C, 0xEC2C0101, + 0x81C, 0xEB2E0101, + 0x81C, 0xEA300101, + 0x81C, 0xE9320101, + 0x81C, 0xE8340101, + 0x81C, 0xE7360101, + 0x81C, 0xE6380101, + 0x81C, 0xE53A0101, + 0x81C, 0xE43C0101, + 0x81C, 0xE33E0101, + 0x81C, 0xA5400101, + 0x81C, 0xA4420101, + 0x81C, 0xA3440101, + 0x81C, 0x87460101, + 0x81C, 0x86480101, + 0x81C, 0x854A0101, + 0x81C, 0x844C0101, + 0x81C, 0x694E0101, + 0x81C, 0x68500101, + 0x81C, 0x67520101, + 0x81C, 0x66540101, + 0x81C, 0x49560101, + 0x81C, 0x48580101, + 0x81C, 0x475A0101, + 0x81C, 0x2A5C0101, + 0x81C, 0x295E0101, + 0x81C, 0x28600101, + 0x81C, 0x27620101, + 0x81C, 0x26640101, + 0x81C, 0x25660101, + 0x81C, 0x24680101, + 0x81C, 0x236A0101, + 0x81C, 0x056C0101, + 0x81C, 0x046E0101, + 0x81C, 0x03700101, + 0x81C, 0x02720101, + 0xB0000000, 0x00000000, + 0x81C, 0x01740101, + 0x81C, 0x01760101, + 0x81C, 0x01780101, + 0x81C, 0x017A0101, + 0x81C, 0x017C0101, + 0x81C, 0x017E0101, + 0xC50, 0x00000022, + 0xC50, 0x00000020, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821a_agc, rtw_phy_cfg_agc); + +static const u32 rtw8821a_bb[] = { + 0x800, 0x0020D090, + 0x804, 0x080112E0, + 0x808, 0x0E028211, + 0x80C, 0x92131111, + 0x810, 0x20101261, + 0x814, 0x020C3D10, + 0x818, 0x03A00385, + 0x820, 0x00000000, + 0x824, 0x00030FE0, + 0x828, 0x00000000, + 0x82C, 0x002081DD, + 0x830, 0x2AAAEEC8, + 0x834, 0x0037A706, + 0x838, 0x06489B44, + 0x83C, 0x0000095B, + 0x840, 0xC0000001, + 0x844, 0x40003CDE, + 0x848, 0x62103F8B, + 0x84C, 0x6CFDFFB8, + 0x850, 0x28874706, + 0x854, 0x0001520C, + 0x858, 0x8060E000, + 0x85C, 0x74210168, + 0x860, 0x6929C321, + 0x864, 0x79727432, + 0x868, 0x8CA7A314, + 0x86C, 0x888C2878, + 0x870, 0x08888888, + 0x874, 0x31612C2E, + 0x878, 0x00000152, + 0x87C, 0x000FD000, + 0x8A0, 0x00000013, + 0x8A4, 0x7F7F7F7F, + 0x8A8, 0xA2000338, + 0x8AC, 0x0FF0FA0A, + 0x8B4, 0x000FC080, + 0x8B8, 0x6C10D7FF, + 0x8BC, 0x0CA52090, + 0x8C0, 0x1BF00020, + 0x8C4, 0x00000000, + 0x8C8, 0x00013169, + 0x8CC, 0x08248492, + 0x8D4, 0x940008A0, + 0x8D8, 0x290B5612, + 0x8F8, 0x400002C0, + 0x8FC, 0x00000000, + 0x900, 0x00000700, + 0x90C, 0x00000000, + 0x910, 0x0000FC00, + 0x914, 0x00000404, + 0x918, 0x1C1028C0, + 0x91C, 0x64B11A1C, + 0x920, 0xE0767233, + 0x924, 0x055AA500, + 0x928, 0x00000004, + 0x92C, 0xFFFE0000, + 0x930, 0xFFFFFFFE, + 0x934, 0x001FFFFF, + 0x960, 0x00000000, + 0x964, 0x00000000, + 0x968, 0x00000000, + 0x96C, 0x00000000, + 0x970, 0x801FFFFF, + 0x974, 0x000003FF, + 0x978, 0x00000000, + 0x97C, 0x00000000, + 0x980, 0x00000000, + 0x984, 0x00000000, + 0x988, 0x00000000, + 0x990, 0x27100000, + 0x994, 0xFFFF0100, + 0x998, 0xFFFFFF5C, + 0x99C, 0xFFFFFFFF, + 0x9A0, 0x000000FF, + 0x9A4, 0x00480080, + 0x9A8, 0x00000000, + 0x9AC, 0x00000000, + 0x9B0, 0x81081008, + 0x9B4, 0x01081008, + 0x9B8, 0x01081008, + 0x9BC, 0x01081008, + 0x9D0, 0x00000000, + 0x9D4, 0x00000000, + 0x9D8, 0x00000000, + 0x9DC, 0x00000000, + 0x9E0, 0x00005D00, + 0x9E4, 0x00000003, + 0x9E8, 0x00000001, + 0xA00, 0x00D047C8, + 0xA04, 0x01FF800C, + 0xA08, 0x8C8A8300, + 0xA0C, 0x2E68000F, + 0xA10, 0x9500BB78, + 0xA14, 0x11144028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1317, + 0xA28, 0x00000204, + 0xA2C, 0x00900000, + 0xA70, 0x101FFF00, + 0xA74, 0x00000008, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x21805490, + 0xA84, 0x001F0000, + 0XB00, 0x03100040, + 0XB04, 0x0000B000, + 0XB08, 0xAE0201EB, + 0XB0C, 0x01003207, + 0XB10, 0x00009807, + 0XB14, 0x01000000, + 0XB18, 0x00000002, + 0XB1C, 0x00000002, + 0XB20, 0x0000001F, + 0XB24, 0x03020100, + 0XB28, 0x07060504, + 0XB2C, 0x0B0A0908, + 0XB30, 0x0F0E0D0C, + 0XB34, 0x13121110, + 0XB38, 0x17161514, + 0XB3C, 0x0000003A, + 0XB40, 0x00000000, + 0XB44, 0x00000000, + 0XB48, 0x13000032, + 0XB4C, 0x48080000, + 0XB50, 0x00000000, + 0XB54, 0x00000000, + 0XB58, 0x00000000, + 0XB5C, 0x00000000, + 0xC00, 0x00000007, + 0xC04, 0x00042020, + 0xC08, 0x80410231, + 0xC0C, 0x00000000, + 0xC10, 0x00000100, + 0xC14, 0x01000000, + 0xC1C, 0x40000003, + 0xC20, 0x2C2C2C2C, + 0xC24, 0x30303030, + 0xC28, 0x30303030, + 0xC2C, 0x2C2C2C2C, + 0xC30, 0x2C2C2C2C, + 0xC34, 0x2C2C2C2C, + 0xC38, 0x2C2C2C2C, + 0xC3C, 0x2A2A2A2A, + 0xC40, 0x2A2A2A2A, + 0xC44, 0x2A2A2A2A, + 0xC48, 0x2A2A2A2A, + 0xC4C, 0x2A2A2A2A, + 0xC50, 0x00000020, + 0xC54, 0x001C1208, + 0xC58, 0x30000C1C, + 0xC5C, 0x00000058, + 0xC60, 0x34344443, + 0xC64, 0x07003333, + 0xC68, 0x19791979, + 0xC6C, 0x19791979, + 0xC70, 0x19791979, + 0xC74, 0x19791979, + 0xC78, 0x19791979, + 0xC7C, 0x19791979, + 0xC80, 0x19791979, + 0xC84, 0x19791979, + 0xC94, 0x0100005C, + 0xC98, 0x00000000, + 0xC9C, 0x00000000, + 0xCA0, 0x00000029, + 0xCA4, 0x08040201, + 0xCA8, 0x80402010, + 0xCB0, 0x77775747, + 0xCB4, 0x10000077, + 0xCB8, 0x00508240, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821a_bb, rtw_phy_cfg_bb); + +static const struct rtw_phy_pg_cfg_pair rtw8821a_bb_pg[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36363838, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363838, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 0, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x34343636, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343636, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022, }, +}; + +RTW_DECL_TABLE_BB_PG(rtw8821a_bb_pg); + +static const u32 rtw8821a_rf_a[] = { + 0x018, 0x0001712A, + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x000, 0x00010000, + 0x01E, 0x00080000, + 0x082, 0x00000830, + 0x083, 0x00021800, + 0x084, 0x00028000, + 0x085, 0x00048000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x086, 0x0009483A, + 0xA0000000, 0x00000000, + 0x086, 0x00094838, + 0xB0000000, 0x00000000, + 0x087, 0x00044980, + 0x088, 0x00048000, + 0x089, 0x0000D480, + 0x08A, 0x00042240, + 0x08B, 0x000F0380, + 0x08C, 0x00090000, + 0x08D, 0x00022852, + 0x08E, 0x00065540, + 0x08F, 0x00088001, + 0x0EF, 0x00020000, + 0x03E, 0x00000380, + 0x03F, 0x00090018, + 0x03E, 0x00020380, + 0x03F, 0x000A0018, + 0x03E, 0x00040308, + 0x03F, 0x000A0018, + 0x03E, 0x00060018, + 0x03F, 0x000A0018, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x089, 0x00000080, + 0x08B, 0x00080180, + 0x0EF, 0x00001000, + 0x03A, 0x00000244, + 0x03B, 0x00038027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x00030113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x00028027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x00027027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0001F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00017F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00008027, + 0x03C, 0x000CA000, + 0x03A, 0x00000244, + 0x03B, 0x00078027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x00070113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x00068027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x00067027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0005F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00057F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00048027, + 0x03C, 0x000CA000, + 0x03A, 0x00000244, + 0x03B, 0x000B8027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x000B0113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x000A8027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x000A7027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0009F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00097F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00088027, + 0x03C, 0x000CA000, + 0x0EF, 0x00000000, + 0x0EF, 0x00001100, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0F3, + 0x034, 0x000490B1, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0F3, + 0x034, 0x000490B1, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0xA0000000, 0x00000000, + 0x034, 0x0004ADF7, + 0x034, 0x00049DF3, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000480AE, + 0x034, 0x000470AB, + 0x034, 0x0004608B, + 0x034, 0x00045069, + 0x034, 0x00044048, + 0x034, 0x00043045, + 0x034, 0x00042026, + 0x034, 0x00041023, + 0x034, 0x00040002, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000480AE, + 0x034, 0x000470AB, + 0x034, 0x0004608B, + 0x034, 0x00045069, + 0x034, 0x00044048, + 0x034, 0x00043045, + 0x034, 0x00042026, + 0x034, 0x00041023, + 0x034, 0x00040002, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0xA0000000, 0x00000000, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045CCB, + 0x034, 0x0004488D, + 0x034, 0x0004348D, + 0x034, 0x0004248A, + 0x034, 0x0004108D, + 0x034, 0x0004008A, + 0xB0000000, 0x00000000, + 0x80000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002ADF4, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0F3, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0F3, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002ADF4, + 0xA0000000, 0x00000000, + 0x034, 0x0002ADF7, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF4, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF4, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF1, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000290F0, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000290F0, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF1, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF4, + 0xA0000000, 0x00000000, + 0x034, 0x00029DF2, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000280AF, + 0x034, 0x000270AC, + 0x034, 0x0002608B, + 0x034, 0x00025069, + 0x034, 0x00024048, + 0x034, 0x00023045, + 0x034, 0x00022026, + 0x034, 0x00021023, + 0x034, 0x00020002, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000280AF, + 0x034, 0x000270AC, + 0x034, 0x0002608B, + 0x034, 0x00025069, + 0x034, 0x00024048, + 0x034, 0x00023045, + 0x034, 0x00022026, + 0x034, 0x00021023, + 0x034, 0x00020002, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0xA0000000, 0x00000000, + 0x034, 0x00028DEE, + 0x034, 0x00027DEB, + 0x034, 0x00026CCD, + 0x034, 0x00025CCA, + 0x034, 0x0002488C, + 0x034, 0x0002384C, + 0x034, 0x00022849, + 0x034, 0x00021449, + 0x034, 0x0002004D, + 0xB0000000, 0x00000000, + 0x8000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0D7, + 0x034, 0x000090D3, + 0x034, 0x000080B1, + 0x034, 0x000070AE, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0D7, + 0x034, 0x000090D3, + 0x034, 0x000080B1, + 0x034, 0x000070AE, + 0xA0000000, 0x00000000, + 0x034, 0x0000ADF7, + 0x034, 0x00009DF4, + 0x034, 0x00008DF1, + 0x034, 0x00007DEE, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000608D, + 0x034, 0x0000506B, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x00002044, + 0x034, 0x00001025, + 0x034, 0x00000004, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000608D, + 0x034, 0x0000506B, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x00002044, + 0x034, 0x00001025, + 0x034, 0x00000004, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0xA0000000, 0x00000000, + 0x034, 0x00006DCD, + 0x034, 0x00005CCD, + 0x034, 0x00004CCA, + 0x034, 0x0000388C, + 0x034, 0x00002888, + 0x034, 0x00001488, + 0x034, 0x00000486, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000128, + 0x035, 0x00008128, + 0x035, 0x00010128, + 0x035, 0x000201C8, + 0x035, 0x000281C8, + 0x035, 0x000301C8, + 0x035, 0x000401C8, + 0x035, 0x000481C8, + 0x035, 0x000501C8, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000145, + 0x035, 0x00008145, + 0x035, 0x00010145, + 0x035, 0x00020196, + 0x035, 0x00028196, + 0x035, 0x00030196, + 0x035, 0x000401C7, + 0x035, 0x000481C7, + 0x035, 0x000501C7, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000128, + 0x035, 0x00008128, + 0x035, 0x00010128, + 0x035, 0x000201C8, + 0x035, 0x000281C8, + 0x035, 0x000301C8, + 0x035, 0x000401C8, + 0x035, 0x000481C8, + 0x035, 0x000501C8, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0xA0000000, 0x00000000, + 0x035, 0x00000145, + 0x035, 0x00008145, + 0x035, 0x00010145, + 0x035, 0x00020196, + 0x035, 0x00028196, + 0x035, 0x00030196, + 0x035, 0x000401C7, + 0x035, 0x000481C7, + 0x035, 0x000501C7, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x000063B5, + 0x036, 0x0000E3B5, + 0x036, 0x000163B5, + 0x036, 0x0001E3B5, + 0x036, 0x000263B5, + 0x036, 0x0002E3B5, + 0x036, 0x000363B5, + 0x036, 0x0003E3B5, + 0x036, 0x000463B5, + 0x036, 0x0004E3B5, + 0x036, 0x000563B5, + 0x036, 0x0005E3B5, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x000056B3, + 0x036, 0x0000D6B3, + 0x036, 0x000156B3, + 0x036, 0x0001D6B3, + 0x036, 0x00026634, + 0x036, 0x0002E634, + 0x036, 0x00036634, + 0x036, 0x0003E634, + 0x036, 0x000467B4, + 0x036, 0x0004E7B4, + 0x036, 0x000567B4, + 0x036, 0x0005E7B4, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x000063B5, + 0x036, 0x0000E3B5, + 0x036, 0x000163B5, + 0x036, 0x0001E3B5, + 0x036, 0x000263B5, + 0x036, 0x0002E3B5, + 0x036, 0x000363B5, + 0x036, 0x0003E3B5, + 0x036, 0x000463B5, + 0x036, 0x0004E3B5, + 0x036, 0x000563B5, + 0x036, 0x0005E3B5, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0xA0000000, 0x00000000, + 0x036, 0x000056B3, + 0x036, 0x0000D6B3, + 0x036, 0x000156B3, + 0x036, 0x0001D6B3, + 0x036, 0x00026634, + 0x036, 0x0002E634, + 0x036, 0x00036634, + 0x036, 0x0003E634, + 0x036, 0x000467B4, + 0x036, 0x0004E7B4, + 0x036, 0x000567B4, + 0x036, 0x0005E7B4, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001B6, + 0x03C, 0x00000492, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x0000022A, + 0x03C, 0x00000594, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001B6, + 0x03C, 0x00000492, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0xA0000000, 0x00000000, + 0x03C, 0x0000022A, + 0x03C, 0x00000594, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000820, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000820, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0xA0000000, 0x00000000, + 0x03C, 0x00000900, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x00002000, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x00002000, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x00002000, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x00002000, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, + 0xA0000000, 0x00000000, + 0x008, 0x00002000, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0DF, 0x000000C0, + 0x01F, 0x00000064, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0xA0000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EFD83, + 0x062, 0x00093FCC, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EAD53, + 0x062, 0x00093BC4, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EFD83, + 0x062, 0x00093FCC, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0xA0000000, 0x00000000, + 0x061, 0x000EAD53, + 0x062, 0x00093BC4, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110EB, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110EB, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0xA0000000, 0x00000000, + 0x063, 0x000714E9, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C67C, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0xA0000000, 0x00000000, + 0x064, 0x0001C67C, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00091016, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00091016, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093016, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093015, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093015, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093016, + 0xA0000000, 0x00000000, + 0x065, 0x00091016, + 0xB0000000, 0x00000000, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0x03B, 0x0003824B, + 0x03B, 0x0003024B, + 0x03B, 0x0002844B, + 0x03B, 0x00020F4B, + 0x03B, 0x00018F4B, + 0x03B, 0x000104B2, + 0x03B, 0x00008049, + 0x03B, 0x00000148, + 0x03B, 0x0007824B, + 0x03B, 0x0007024B, + 0x03B, 0x0006824B, + 0x03B, 0x00060F4B, + 0x03B, 0x00058F4B, + 0x03B, 0x000504B2, + 0x03B, 0x00048049, + 0x03B, 0x00040148, + 0x0EF, 0x00000000, + 0x0EF, 0x00000100, + 0x034, 0x0000ADF3, + 0x034, 0x00009DF0, + 0x034, 0x00008D70, + 0x034, 0x00007D6D, + 0x034, 0x00006CEE, + 0x034, 0x00005CCC, + 0x034, 0x000044EC, + 0x034, 0x000034AC, + 0x034, 0x0000246D, + 0x034, 0x0000106F, + 0x034, 0x0000006C, + 0x0EF, 0x00000000, + 0x0ED, 0x00000010, + 0x044, 0x0000ADF2, + 0x044, 0x00009DEF, + 0x044, 0x00008DEC, + 0x044, 0x00007DE9, + 0x044, 0x00006CEC, + 0x044, 0x00005CE9, + 0x044, 0x000044EC, + 0x044, 0x000034E9, + 0x044, 0x0000246C, + 0x044, 0x00001469, + 0x044, 0x0000006C, + 0x0ED, 0x00000000, + 0x0ED, 0x00000001, + 0x040, 0x00038DA7, + 0x040, 0x000300C2, + 0x040, 0x000288E2, + 0x040, 0x000200B8, + 0x040, 0x000188A5, + 0x040, 0x00010FBC, + 0x040, 0x00008F71, + 0x040, 0x00000240, + 0x0ED, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000120, + 0x035, 0x00008120, + 0x035, 0x00010120, + 0x036, 0x00000085, + 0x036, 0x00008085, + 0x036, 0x00010085, + 0x036, 0x00018085, + 0x0EF, 0x00000000, + 0x051, 0x00000C31, + 0x052, 0x00000622, + 0x053, 0x000FC70B, + 0x054, 0x0000017E, + 0x056, 0x00051DF3, + 0x051, 0x00000C01, + 0x052, 0x000006D6, + 0x053, 0x000FC649, + 0x070, 0x00049661, + 0x071, 0x0007843E, + 0x072, 0x00000382, + 0x074, 0x00051400, + 0x035, 0x00000160, + 0x035, 0x00008160, + 0x035, 0x00010160, + 0x036, 0x00000124, + 0x036, 0x00008124, + 0x036, 0x00010124, + 0x036, 0x00018124, + 0x0ED, 0x0000000C, + 0x045, 0x00000140, + 0x045, 0x00008140, + 0x045, 0x00010140, + 0x046, 0x00000124, + 0x046, 0x00008124, + 0x046, 0x00010124, + 0x046, 0x00018124, + 0x0DF, 0x00000088, + 0x0B3, 0x000F0E18, + 0x0B4, 0x0001214C, + 0x0B7, 0x0003000C, + 0x01C, 0x000539D2, + 0x0C4, 0x000AFE00, + 0x018, 0x0001F12A, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x018, 0x0001712A, +}; + +RTW_DECL_TABLE_RF_RADIO(rtw8821a_rf_a, A); + +static const struct rtw_txpwr_lmt_cfg_pair rtw8821a_txpwr_lmt[] = { + { 0, 0, 0, 0, 1, 32, }, + { 2, 0, 0, 0, 1, 28, }, + { 1, 0, 0, 0, 1, 32, }, + { 0, 0, 0, 0, 2, 32, }, + { 2, 0, 0, 0, 2, 28, }, + { 1, 0, 0, 0, 2, 32, }, + { 0, 0, 0, 0, 3, 36, }, + { 2, 0, 0, 0, 3, 28, }, + { 1, 0, 0, 0, 3, 32, }, + { 0, 0, 0, 0, 4, 36, }, + { 2, 0, 0, 0, 4, 28, }, + { 1, 0, 0, 0, 4, 32, }, + { 0, 0, 0, 0, 5, 36, }, + { 2, 0, 0, 0, 5, 28, }, + { 1, 0, 0, 0, 5, 32, }, + { 0, 0, 0, 0, 6, 36, }, + { 2, 0, 0, 0, 6, 28, }, + { 1, 0, 0, 0, 6, 32, }, + { 0, 0, 0, 0, 7, 36, }, + { 2, 0, 0, 0, 7, 28, }, + { 1, 0, 0, 0, 7, 32, }, + { 0, 0, 0, 0, 8, 36, }, + { 2, 0, 0, 0, 8, 28, }, + { 1, 0, 0, 0, 8, 32, }, + { 0, 0, 0, 0, 9, 32, }, + { 2, 0, 0, 0, 9, 28, }, + { 1, 0, 0, 0, 9, 32, }, + { 0, 0, 0, 0, 10, 32, }, + { 2, 0, 0, 0, 10, 28, }, + { 1, 0, 0, 0, 10, 32, }, + { 0, 0, 0, 0, 11, 32, }, + { 2, 0, 0, 0, 11, 28, }, + { 1, 0, 0, 0, 11, 32, }, + { 0, 0, 0, 0, 12, 28, }, + { 2, 0, 0, 0, 12, 28, }, + { 1, 0, 0, 0, 12, 32, }, + { 0, 0, 0, 0, 13, 26, }, + { 2, 0, 0, 0, 13, 28, }, + { 1, 0, 0, 0, 13, 32, }, + { 0, 0, 0, 0, 14, 63, }, + { 2, 0, 0, 0, 14, 63, }, + { 1, 0, 0, 0, 14, 32, }, + { 0, 0, 0, 1, 1, 30, }, + { 2, 0, 0, 1, 1, 30, }, + { 1, 0, 0, 1, 1, 32, }, + { 0, 0, 0, 1, 2, 30, }, + { 2, 0, 0, 1, 2, 32, }, + { 1, 0, 0, 1, 2, 32, }, + { 0, 0, 0, 1, 3, 32, }, + { 2, 0, 0, 1, 3, 32, }, + { 1, 0, 0, 1, 3, 32, }, + { 0, 0, 0, 1, 4, 32, }, + { 2, 0, 0, 1, 4, 32, }, + { 1, 0, 0, 1, 4, 32, }, + { 0, 0, 0, 1, 5, 32, }, + { 2, 0, 0, 1, 5, 32, }, + { 1, 0, 0, 1, 5, 32, }, + { 0, 0, 0, 1, 6, 32, }, + { 2, 0, 0, 1, 6, 32, }, + { 1, 0, 0, 1, 6, 32, }, + { 0, 0, 0, 1, 7, 32, }, + { 2, 0, 0, 1, 7, 32, }, + { 1, 0, 0, 1, 7, 32, }, + { 0, 0, 0, 1, 8, 32, }, + { 2, 0, 0, 1, 8, 32, }, + { 1, 0, 0, 1, 8, 32, }, + { 0, 0, 0, 1, 9, 30, }, + { 2, 0, 0, 1, 9, 32, }, + { 1, 0, 0, 1, 9, 32, }, + { 0, 0, 0, 1, 10, 30, }, + { 2, 0, 0, 1, 10, 32, }, + { 1, 0, 0, 1, 10, 32, }, + { 0, 0, 0, 1, 11, 30, }, + { 2, 0, 0, 1, 11, 32, }, + { 1, 0, 0, 1, 11, 32, }, + { 0, 0, 0, 1, 12, 26, }, + { 2, 0, 0, 1, 12, 32, }, + { 1, 0, 0, 1, 12, 32, }, + { 0, 0, 0, 1, 13, 24, }, + { 2, 0, 0, 1, 13, 30, }, + { 1, 0, 0, 1, 13, 32, }, + { 0, 0, 0, 1, 14, 63, }, + { 2, 0, 0, 1, 14, 63, }, + { 1, 0, 0, 1, 14, 63, }, + { 0, 0, 0, 2, 1, 26, }, + { 2, 0, 0, 2, 1, 26, }, + { 1, 0, 0, 2, 1, 32, }, + { 0, 0, 0, 2, 2, 26, }, + { 2, 0, 0, 2, 2, 32, }, + { 1, 0, 0, 2, 2, 32, }, + { 0, 0, 0, 2, 3, 32, }, + { 2, 0, 0, 2, 3, 32, }, + { 1, 0, 0, 2, 3, 32, }, + { 0, 0, 0, 2, 4, 32, }, + { 2, 0, 0, 2, 4, 32, }, + { 1, 0, 0, 2, 4, 32, }, + { 0, 0, 0, 2, 5, 32, }, + { 2, 0, 0, 2, 5, 32, }, + { 1, 0, 0, 2, 5, 32, }, + { 0, 0, 0, 2, 6, 32, }, + { 2, 0, 0, 2, 6, 32, }, + { 1, 0, 0, 2, 6, 32, }, + { 0, 0, 0, 2, 7, 32, }, + { 2, 0, 0, 2, 7, 32, }, + { 1, 0, 0, 2, 7, 32, }, + { 0, 0, 0, 2, 8, 32, }, + { 2, 0, 0, 2, 8, 32, }, + { 1, 0, 0, 2, 8, 32, }, + { 0, 0, 0, 2, 9, 26, }, + { 2, 0, 0, 2, 9, 32, }, + { 1, 0, 0, 2, 9, 32, }, + { 0, 0, 0, 2, 10, 26, }, + { 2, 0, 0, 2, 10, 32, }, + { 1, 0, 0, 2, 10, 32, }, + { 0, 0, 0, 2, 11, 26, }, + { 2, 0, 0, 2, 11, 32, }, + { 1, 0, 0, 2, 11, 32, }, + { 0, 0, 0, 2, 12, 26, }, + { 2, 0, 0, 2, 12, 32, }, + { 1, 0, 0, 2, 12, 32, }, + { 0, 0, 0, 2, 13, 24, }, + { 2, 0, 0, 2, 13, 26, }, + { 1, 0, 0, 2, 13, 32, }, + { 0, 0, 0, 2, 14, 63, }, + { 2, 0, 0, 2, 14, 63, }, + { 1, 0, 0, 2, 14, 63, }, + { 0, 0, 0, 3, 1, 30, }, + { 2, 0, 0, 3, 1, 32, }, + { 1, 0, 0, 3, 1, 32, }, + { 0, 0, 0, 3, 2, 32, }, + { 2, 0, 0, 3, 2, 32, }, + { 1, 0, 0, 3, 2, 32, }, + { 0, 0, 0, 3, 3, 32, }, + { 2, 0, 0, 3, 3, 32, }, + { 1, 0, 0, 3, 3, 32, }, + { 0, 0, 0, 3, 4, 32, }, + { 2, 0, 0, 3, 4, 32, }, + { 1, 0, 0, 3, 4, 32, }, + { 0, 0, 0, 3, 5, 32, }, + { 2, 0, 0, 3, 5, 32, }, + { 1, 0, 0, 3, 5, 32, }, + { 0, 0, 0, 3, 6, 32, }, + { 2, 0, 0, 3, 6, 32, }, + { 1, 0, 0, 3, 6, 32, }, + { 0, 0, 0, 3, 7, 32, }, + { 2, 0, 0, 3, 7, 32, }, + { 1, 0, 0, 3, 7, 32, }, + { 0, 0, 0, 3, 8, 32, }, + { 2, 0, 0, 3, 8, 32, }, + { 1, 0, 0, 3, 8, 32, }, + { 0, 0, 0, 3, 9, 32, }, + { 2, 0, 0, 3, 9, 32, }, + { 1, 0, 0, 3, 9, 32, }, + { 0, 0, 0, 3, 10, 32, }, + { 2, 0, 0, 3, 10, 32, }, + { 1, 0, 0, 3, 10, 32, }, + { 0, 0, 0, 3, 11, 30, }, + { 2, 0, 0, 3, 11, 32, }, + { 1, 0, 0, 3, 11, 32, }, + { 0, 0, 0, 3, 12, 63, }, + { 2, 0, 0, 3, 12, 32, }, + { 1, 0, 0, 3, 12, 32, }, + { 0, 0, 0, 3, 13, 63, }, + { 2, 0, 0, 3, 13, 32, }, + { 1, 0, 0, 3, 13, 32, }, + { 0, 0, 0, 3, 14, 63, }, + { 2, 0, 0, 3, 14, 63, }, + { 1, 0, 0, 3, 14, 63, }, + { 0, 0, 1, 2, 1, 63, }, + { 2, 0, 1, 2, 1, 63, }, + { 1, 0, 1, 2, 1, 63, }, + { 0, 0, 1, 2, 2, 63, }, + { 2, 0, 1, 2, 2, 63, }, + { 1, 0, 1, 2, 2, 63, }, + { 0, 0, 1, 2, 3, 26, }, + { 2, 0, 1, 2, 3, 26, }, + { 1, 0, 1, 2, 3, 32, }, + { 0, 0, 1, 2, 4, 26, }, + { 2, 0, 1, 2, 4, 32, }, + { 1, 0, 1, 2, 4, 32, }, + { 0, 0, 1, 2, 5, 26, }, + { 2, 0, 1, 2, 5, 32, }, + { 1, 0, 1, 2, 5, 32, }, + { 0, 0, 1, 2, 6, 32, }, + { 2, 0, 1, 2, 6, 32, }, + { 1, 0, 1, 2, 6, 32, }, + { 0, 0, 1, 2, 7, 32, }, + { 2, 0, 1, 2, 7, 32, }, + { 1, 0, 1, 2, 7, 32, }, + { 0, 0, 1, 2, 8, 32, }, + { 2, 0, 1, 2, 8, 32, }, + { 1, 0, 1, 2, 8, 32, }, + { 0, 0, 1, 2, 9, 26, }, + { 2, 0, 1, 2, 9, 32, }, + { 1, 0, 1, 2, 9, 32, }, + { 0, 0, 1, 2, 10, 24, }, + { 2, 0, 1, 2, 10, 32, }, + { 1, 0, 1, 2, 10, 32, }, + { 0, 0, 1, 2, 11, 22, }, + { 2, 0, 1, 2, 11, 26, }, + { 1, 0, 1, 2, 11, 32, }, + { 0, 0, 1, 2, 12, 63, }, + { 2, 0, 1, 2, 12, 63, }, + { 1, 0, 1, 2, 12, 63, }, + { 0, 0, 1, 2, 13, 63, }, + { 2, 0, 1, 2, 13, 63, }, + { 1, 0, 1, 2, 13, 63, }, + { 0, 0, 1, 2, 14, 63, }, + { 2, 0, 1, 2, 14, 63, }, + { 1, 0, 1, 2, 14, 63, }, + { 0, 0, 1, 3, 1, 63, }, + { 2, 0, 1, 3, 1, 63, }, + { 1, 0, 1, 3, 1, 63, }, + { 0, 0, 1, 3, 2, 63, }, + { 2, 0, 1, 3, 2, 63, }, + { 1, 0, 1, 3, 2, 63, }, + { 0, 0, 1, 3, 3, 30, }, + { 2, 0, 1, 3, 3, 30, }, + { 1, 0, 1, 3, 3, 30, }, + { 0, 0, 1, 3, 4, 32, }, + { 2, 0, 1, 3, 4, 30, }, + { 1, 0, 1, 3, 4, 30, }, + { 0, 0, 1, 3, 5, 32, }, + { 2, 0, 1, 3, 5, 30, }, + { 1, 0, 1, 3, 5, 30, }, + { 0, 0, 1, 3, 6, 32, }, + { 2, 0, 1, 3, 6, 30, }, + { 1, 0, 1, 3, 6, 30, }, + { 0, 0, 1, 3, 7, 32, }, + { 2, 0, 1, 3, 7, 30, }, + { 1, 0, 1, 3, 7, 30, }, + { 0, 0, 1, 3, 8, 32, }, + { 2, 0, 1, 3, 8, 30, }, + { 1, 0, 1, 3, 8, 30, }, + { 0, 0, 1, 3, 9, 32, }, + { 2, 0, 1, 3, 9, 30, }, + { 1, 0, 1, 3, 9, 30, }, + { 0, 0, 1, 3, 10, 32, }, + { 2, 0, 1, 3, 10, 30, }, + { 1, 0, 1, 3, 10, 30, }, + { 0, 0, 1, 3, 11, 30, }, + { 2, 0, 1, 3, 11, 30, }, + { 1, 0, 1, 3, 11, 30, }, + { 0, 0, 1, 3, 12, 63, }, + { 2, 0, 1, 3, 12, 32, }, + { 1, 0, 1, 3, 12, 32, }, + { 0, 0, 1, 3, 13, 63, }, + { 2, 0, 1, 3, 13, 32, }, + { 1, 0, 1, 3, 13, 32, }, + { 0, 0, 1, 3, 14, 63, }, + { 2, 0, 1, 3, 14, 63, }, + { 1, 0, 1, 3, 14, 63, }, + { 0, 1, 0, 1, 36, 32, }, + { 2, 1, 0, 1, 36, 30, }, + { 1, 1, 0, 1, 36, 30, }, + { 0, 1, 0, 1, 40, 32, }, + { 2, 1, 0, 1, 40, 30, }, + { 1, 1, 0, 1, 40, 30, }, + { 0, 1, 0, 1, 44, 32, }, + { 2, 1, 0, 1, 44, 30, }, + { 1, 1, 0, 1, 44, 30, }, + { 0, 1, 0, 1, 48, 32, }, + { 2, 1, 0, 1, 48, 30, }, + { 1, 1, 0, 1, 48, 30, }, + { 0, 1, 0, 1, 52, 32, }, + { 2, 1, 0, 1, 52, 30, }, + { 1, 1, 0, 1, 52, 30, }, + { 0, 1, 0, 1, 56, 32, }, + { 2, 1, 0, 1, 56, 30, }, + { 1, 1, 0, 1, 56, 30, }, + { 0, 1, 0, 1, 60, 32, }, + { 2, 1, 0, 1, 60, 30, }, + { 1, 1, 0, 1, 60, 30, }, + { 0, 1, 0, 1, 64, 32, }, + { 2, 1, 0, 1, 64, 30, }, + { 1, 1, 0, 1, 64, 30, }, + { 0, 1, 0, 1, 100, 32, }, + { 2, 1, 0, 1, 100, 30, }, + { 1, 1, 0, 1, 100, 30, }, + { 0, 1, 0, 1, 104, 32, }, + { 2, 1, 0, 1, 104, 30, }, + { 1, 1, 0, 1, 104, 30, }, + { 0, 1, 0, 1, 108, 32, }, + { 2, 1, 0, 1, 108, 30, }, + { 1, 1, 0, 1, 108, 30, }, + { 0, 1, 0, 1, 112, 32, }, + { 2, 1, 0, 1, 112, 30, }, + { 1, 1, 0, 1, 112, 30, }, + { 0, 1, 0, 1, 116, 32, }, + { 2, 1, 0, 1, 116, 30, }, + { 1, 1, 0, 1, 116, 30, }, + { 0, 1, 0, 1, 120, 32, }, + { 2, 1, 0, 1, 120, 30, }, + { 1, 1, 0, 1, 120, 30, }, + { 0, 1, 0, 1, 124, 32, }, + { 2, 1, 0, 1, 124, 30, }, + { 1, 1, 0, 1, 124, 30, }, + { 0, 1, 0, 1, 128, 32, }, + { 2, 1, 0, 1, 128, 30, }, + { 1, 1, 0, 1, 128, 30, }, + { 0, 1, 0, 1, 132, 32, }, + { 2, 1, 0, 1, 132, 30, }, + { 1, 1, 0, 1, 132, 30, }, + { 0, 1, 0, 1, 136, 32, }, + { 2, 1, 0, 1, 136, 30, }, + { 1, 1, 0, 1, 136, 30, }, + { 0, 1, 0, 1, 140, 32, }, + { 2, 1, 0, 1, 140, 30, }, + { 1, 1, 0, 1, 140, 30, }, + { 0, 1, 0, 1, 149, 32, }, + { 2, 1, 0, 1, 149, 30, }, + { 1, 1, 0, 1, 149, 63, }, + { 0, 1, 0, 1, 153, 32, }, + { 2, 1, 0, 1, 153, 30, }, + { 1, 1, 0, 1, 153, 63, }, + { 0, 1, 0, 1, 157, 32, }, + { 2, 1, 0, 1, 157, 30, }, + { 1, 1, 0, 1, 157, 63, }, + { 0, 1, 0, 1, 161, 32, }, + { 2, 1, 0, 1, 161, 30, }, + { 1, 1, 0, 1, 161, 63, }, + { 0, 1, 0, 1, 165, 32, }, + { 2, 1, 0, 1, 165, 30, }, + { 1, 1, 0, 1, 165, 63, }, + { 0, 1, 0, 2, 36, 32, }, + { 2, 1, 0, 2, 36, 30, }, + { 1, 1, 0, 2, 36, 30, }, + { 0, 1, 0, 2, 40, 32, }, + { 2, 1, 0, 2, 40, 30, }, + { 1, 1, 0, 2, 40, 30, }, + { 0, 1, 0, 2, 44, 32, }, + { 2, 1, 0, 2, 44, 30, }, + { 1, 1, 0, 2, 44, 30, }, + { 0, 1, 0, 2, 48, 32, }, + { 2, 1, 0, 2, 48, 30, }, + { 1, 1, 0, 2, 48, 30, }, + { 0, 1, 0, 2, 52, 32, }, + { 2, 1, 0, 2, 52, 30, }, + { 1, 1, 0, 2, 52, 30, }, + { 0, 1, 0, 2, 56, 32, }, + { 2, 1, 0, 2, 56, 30, }, + { 1, 1, 0, 2, 56, 30, }, + { 0, 1, 0, 2, 60, 32, }, + { 2, 1, 0, 2, 60, 30, }, + { 1, 1, 0, 2, 60, 30, }, + { 0, 1, 0, 2, 64, 32, }, + { 2, 1, 0, 2, 64, 30, }, + { 1, 1, 0, 2, 64, 30, }, + { 0, 1, 0, 2, 100, 32, }, + { 2, 1, 0, 2, 100, 30, }, + { 1, 1, 0, 2, 100, 30, }, + { 0, 1, 0, 2, 104, 32, }, + { 2, 1, 0, 2, 104, 30, }, + { 1, 1, 0, 2, 104, 30, }, + { 0, 1, 0, 2, 108, 32, }, + { 2, 1, 0, 2, 108, 30, }, + { 1, 1, 0, 2, 108, 30, }, + { 0, 1, 0, 2, 112, 32, }, + { 2, 1, 0, 2, 112, 30, }, + { 1, 1, 0, 2, 112, 30, }, + { 0, 1, 0, 2, 116, 32, }, + { 2, 1, 0, 2, 116, 30, }, + { 1, 1, 0, 2, 116, 30, }, + { 0, 1, 0, 2, 120, 32, }, + { 2, 1, 0, 2, 120, 30, }, + { 1, 1, 0, 2, 120, 30, }, + { 0, 1, 0, 2, 124, 32, }, + { 2, 1, 0, 2, 124, 30, }, + { 1, 1, 0, 2, 124, 30, }, + { 0, 1, 0, 2, 128, 32, }, + { 2, 1, 0, 2, 128, 30, }, + { 1, 1, 0, 2, 128, 30, }, + { 0, 1, 0, 2, 132, 32, }, + { 2, 1, 0, 2, 132, 30, }, + { 1, 1, 0, 2, 132, 30, }, + { 0, 1, 0, 2, 136, 32, }, + { 2, 1, 0, 2, 136, 30, }, + { 1, 1, 0, 2, 136, 30, }, + { 0, 1, 0, 2, 140, 32, }, + { 2, 1, 0, 2, 140, 30, }, + { 1, 1, 0, 2, 140, 30, }, + { 0, 1, 0, 2, 149, 32, }, + { 2, 1, 0, 2, 149, 30, }, + { 1, 1, 0, 2, 149, 63, }, + { 0, 1, 0, 2, 153, 32, }, + { 2, 1, 0, 2, 153, 30, }, + { 1, 1, 0, 2, 153, 63, }, + { 0, 1, 0, 2, 157, 32, }, + { 2, 1, 0, 2, 157, 30, }, + { 1, 1, 0, 2, 157, 63, }, + { 0, 1, 0, 2, 161, 32, }, + { 2, 1, 0, 2, 161, 30, }, + { 1, 1, 0, 2, 161, 63, }, + { 0, 1, 0, 2, 165, 32, }, + { 2, 1, 0, 2, 165, 30, }, + { 1, 1, 0, 2, 165, 63, }, + { 0, 1, 0, 3, 36, 28, }, + { 2, 1, 0, 3, 36, 30, }, + { 1, 1, 0, 3, 36, 30, }, + { 0, 1, 0, 3, 40, 28, }, + { 2, 1, 0, 3, 40, 30, }, + { 1, 1, 0, 3, 40, 30, }, + { 0, 1, 0, 3, 44, 28, }, + { 2, 1, 0, 3, 44, 30, }, + { 1, 1, 0, 3, 44, 30, }, + { 0, 1, 0, 3, 48, 28, }, + { 2, 1, 0, 3, 48, 30, }, + { 1, 1, 0, 3, 48, 30, }, + { 0, 1, 0, 3, 52, 34, }, + { 2, 1, 0, 3, 52, 30, }, + { 1, 1, 0, 3, 52, 30, }, + { 0, 1, 0, 3, 56, 32, }, + { 2, 1, 0, 3, 56, 30, }, + { 1, 1, 0, 3, 56, 30, }, + { 0, 1, 0, 3, 60, 30, }, + { 2, 1, 0, 3, 60, 30, }, + { 1, 1, 0, 3, 60, 30, }, + { 0, 1, 0, 3, 64, 26, }, + { 2, 1, 0, 3, 64, 30, }, + { 1, 1, 0, 3, 64, 30, }, + { 0, 1, 0, 3, 100, 28, }, + { 2, 1, 0, 3, 100, 30, }, + { 1, 1, 0, 3, 100, 30, }, + { 0, 1, 0, 3, 104, 28, }, + { 2, 1, 0, 3, 104, 30, }, + { 1, 1, 0, 3, 104, 30, }, + { 0, 1, 0, 3, 108, 30, }, + { 2, 1, 0, 3, 108, 30, }, + { 1, 1, 0, 3, 108, 30, }, + { 0, 1, 0, 3, 112, 32, }, + { 2, 1, 0, 3, 112, 30, }, + { 1, 1, 0, 3, 112, 30, }, + { 0, 1, 0, 3, 116, 32, }, + { 2, 1, 0, 3, 116, 30, }, + { 1, 1, 0, 3, 116, 30, }, + { 0, 1, 0, 3, 120, 34, }, + { 2, 1, 0, 3, 120, 30, }, + { 1, 1, 0, 3, 120, 30, }, + { 0, 1, 0, 3, 124, 32, }, + { 2, 1, 0, 3, 124, 30, }, + { 1, 1, 0, 3, 124, 30, }, + { 0, 1, 0, 3, 128, 30, }, + { 2, 1, 0, 3, 128, 30, }, + { 1, 1, 0, 3, 128, 30, }, + { 0, 1, 0, 3, 132, 28, }, + { 2, 1, 0, 3, 132, 30, }, + { 1, 1, 0, 3, 132, 30, }, + { 0, 1, 0, 3, 136, 28, }, + { 2, 1, 0, 3, 136, 30, }, + { 1, 1, 0, 3, 136, 30, }, + { 0, 1, 0, 3, 140, 26, }, + { 2, 1, 0, 3, 140, 30, }, + { 1, 1, 0, 3, 140, 30, }, + { 0, 1, 0, 3, 149, 34, }, + { 2, 1, 0, 3, 149, 30, }, + { 1, 1, 0, 3, 149, 63, }, + { 0, 1, 0, 3, 153, 34, }, + { 2, 1, 0, 3, 153, 30, }, + { 1, 1, 0, 3, 153, 63, }, + { 0, 1, 0, 3, 157, 34, }, + { 2, 1, 0, 3, 157, 30, }, + { 1, 1, 0, 3, 157, 63, }, + { 0, 1, 0, 3, 161, 34, }, + { 2, 1, 0, 3, 161, 30, }, + { 1, 1, 0, 3, 161, 63, }, + { 0, 1, 0, 3, 165, 34, }, + { 2, 1, 0, 3, 165, 30, }, + { 1, 1, 0, 3, 165, 63, }, + { 0, 1, 1, 2, 38, 26, }, + { 2, 1, 1, 2, 38, 30, }, + { 1, 1, 1, 2, 38, 30, }, + { 0, 1, 1, 2, 46, 32, }, + { 2, 1, 1, 2, 46, 30, }, + { 1, 1, 1, 2, 46, 30, }, + { 0, 1, 1, 2, 54, 32, }, + { 2, 1, 1, 2, 54, 30, }, + { 1, 1, 1, 2, 54, 30, }, + { 0, 1, 1, 2, 62, 24, }, + { 2, 1, 1, 2, 62, 30, }, + { 1, 1, 1, 2, 62, 30, }, + { 0, 1, 1, 2, 102, 24, }, + { 2, 1, 1, 2, 102, 30, }, + { 1, 1, 1, 2, 102, 30, }, + { 0, 1, 1, 2, 110, 32, }, + { 2, 1, 1, 2, 110, 30, }, + { 1, 1, 1, 2, 110, 30, }, + { 0, 1, 1, 2, 118, 32, }, + { 2, 1, 1, 2, 118, 30, }, + { 1, 1, 1, 2, 118, 30, }, + { 0, 1, 1, 2, 126, 32, }, + { 2, 1, 1, 2, 126, 30, }, + { 1, 1, 1, 2, 126, 30, }, + { 0, 1, 1, 2, 134, 32, }, + { 2, 1, 1, 2, 134, 30, }, + { 1, 1, 1, 2, 134, 30, }, + { 0, 1, 1, 2, 151, 30, }, + { 2, 1, 1, 2, 151, 30, }, + { 1, 1, 1, 2, 151, 63, }, + { 0, 1, 1, 2, 159, 32, }, + { 2, 1, 1, 2, 159, 30, }, + { 1, 1, 1, 2, 159, 63, }, + { 0, 1, 1, 3, 38, 28, }, + { 2, 1, 1, 3, 38, 30, }, + { 1, 1, 1, 3, 38, 30, }, + { 0, 1, 1, 3, 46, 28, }, + { 2, 1, 1, 3, 46, 30, }, + { 1, 1, 1, 3, 46, 30, }, + { 0, 1, 1, 3, 54, 30, }, + { 2, 1, 1, 3, 54, 30, }, + { 1, 1, 1, 3, 54, 30, }, + { 0, 1, 1, 3, 62, 30, }, + { 2, 1, 1, 3, 62, 30, }, + { 1, 1, 1, 3, 62, 30, }, + { 0, 1, 1, 3, 102, 26, }, + { 2, 1, 1, 3, 102, 30, }, + { 1, 1, 1, 3, 102, 30, }, + { 0, 1, 1, 3, 110, 30, }, + { 2, 1, 1, 3, 110, 30, }, + { 1, 1, 1, 3, 110, 30, }, + { 0, 1, 1, 3, 118, 34, }, + { 2, 1, 1, 3, 118, 30, }, + { 1, 1, 1, 3, 118, 30, }, + { 0, 1, 1, 3, 126, 32, }, + { 2, 1, 1, 3, 126, 30, }, + { 1, 1, 1, 3, 126, 30, }, + { 0, 1, 1, 3, 134, 30, }, + { 2, 1, 1, 3, 134, 30, }, + { 1, 1, 1, 3, 134, 30, }, + { 0, 1, 1, 3, 151, 34, }, + { 2, 1, 1, 3, 151, 30, }, + { 1, 1, 1, 3, 151, 63, }, + { 0, 1, 1, 3, 159, 34, }, + { 2, 1, 1, 3, 159, 30, }, + { 1, 1, 1, 3, 159, 63, }, + { 0, 1, 2, 4, 42, 22, }, + { 2, 1, 2, 4, 42, 30, }, + { 1, 1, 2, 4, 42, 30, }, + { 0, 1, 2, 4, 58, 20, }, + { 2, 1, 2, 4, 58, 30, }, + { 1, 1, 2, 4, 58, 30, }, + { 0, 1, 2, 4, 106, 20, }, + { 2, 1, 2, 4, 106, 30, }, + { 1, 1, 2, 4, 106, 30, }, + { 0, 1, 2, 4, 122, 20, }, + { 2, 1, 2, 4, 122, 30, }, + { 1, 1, 2, 4, 122, 30, }, + { 0, 1, 2, 4, 155, 28, }, + { 2, 1, 2, 4, 155, 30, }, + { 1, 1, 2, 4, 155, 63, }, + { 0, 1, 2, 5, 42, 28, }, + { 2, 1, 2, 5, 42, 30, }, + { 1, 1, 2, 5, 42, 30, }, + { 0, 1, 2, 5, 58, 26, }, + { 2, 1, 2, 5, 58, 30, }, + { 1, 1, 2, 5, 58, 30, }, + { 0, 1, 2, 5, 106, 28, }, + { 2, 1, 2, 5, 106, 30, }, + { 1, 1, 2, 5, 106, 30, }, + { 0, 1, 2, 5, 122, 32, }, + { 2, 1, 2, 5, 122, 30, }, + { 1, 1, 2, 5, 122, 30, }, + { 0, 1, 2, 5, 155, 34, }, + { 2, 1, 2, 5, 155, 30, }, + { 1, 1, 2, 5, 155, 63, }, +}; + +RTW_DECL_TABLE_TXPWR_LMT(rtw8821a_txpwr_lmt); + +static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821a[] = { + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, + {0x004A, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), 0}, + {0x0023, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4), 0}, + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821a[] = { + {0x0020, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4), 0}, + {0x0001, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 1, RTW_PWR_DELAY_MS}, + {0x0000, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4) | BIT(3) | BIT(2), 0}, + {0x0075, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, + {0x0075, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(7), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4) | BIT(3), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(0), 0}, + {0x004F, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5) | BIT(4), BIT(5) | BIT(4)}, + {0x0025, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(6), 0}, + {0x0049, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0063, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0062, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0058, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x005A, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x002E, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x82}, + {0x0010, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(6), BIT(6)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_act_to_lps_8821a[] = { + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0xFF}, + {0x0522, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0xFF}, + {0x05F8, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05F9, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05FA, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05FB, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0100, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x03}, + {0x0101, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0093, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0553, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), BIT(5)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821a[] = { + {0x001F, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x004F, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0049, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), 0}, + {0x0000, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), BIT(5)}, + {0x0020, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821a[] = { + {0x0007, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x20}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), BIT(2)}, + {0x004A, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 1}, + {0x0023, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4), BIT(4)}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_POLLING, BIT(1), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +const struct rtw_pwr_seq_cmd * const card_enable_flow_8821a[] = { + trans_carddis_to_cardemu_8821a, + trans_cardemu_to_act_8821a, + NULL +}; + +const struct rtw_pwr_seq_cmd * const enter_lps_flow_8821a[] = { + trans_act_to_lps_8821a, + NULL +}; + +const struct rtw_pwr_seq_cmd * const card_disable_flow_8821a[] = { + trans_act_to_cardemu_8821a, + trans_cardemu_to_carddis_8821a, + NULL +}; + +static const u8 rtw8821a_pwrtrk_5gb_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8821a_pwrtrk_5gb_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8821a_pwrtrk_5ga_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8821a_pwrtrk_5ga_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8821a_pwrtrk_2gb_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10 +}; + +static const u8 rtw8821a_pwrtrk_2gb_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12 +}; + +static const u8 rtw8821a_pwrtrk_2ga_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10 +}; + +static const u8 rtw8821a_pwrtrk_2ga_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12 +}; + +static const u8 rtw8821a_pwrtrk_2g_cck_b_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10 +}; + +static const u8 rtw8821a_pwrtrk_2g_cck_b_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12 +}; + +static const u8 rtw8821a_pwrtrk_2g_cck_a_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10 +}; + +static const u8 rtw8821a_pwrtrk_2g_cck_a_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12 +}; + +const struct rtw_pwr_track_tbl rtw8821a_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[0] = rtw8821a_pwrtrk_5gb_n[0], + .pwrtrk_5gb_n[1] = rtw8821a_pwrtrk_5gb_n[1], + .pwrtrk_5gb_n[2] = rtw8821a_pwrtrk_5gb_n[2], + .pwrtrk_5gb_p[0] = rtw8821a_pwrtrk_5gb_p[0], + .pwrtrk_5gb_p[1] = rtw8821a_pwrtrk_5gb_p[1], + .pwrtrk_5gb_p[2] = rtw8821a_pwrtrk_5gb_p[2], + .pwrtrk_5ga_n[0] = rtw8821a_pwrtrk_5ga_n[0], + .pwrtrk_5ga_n[1] = rtw8821a_pwrtrk_5ga_n[1], + .pwrtrk_5ga_n[2] = rtw8821a_pwrtrk_5ga_n[2], + .pwrtrk_5ga_p[0] = rtw8821a_pwrtrk_5ga_p[0], + .pwrtrk_5ga_p[1] = rtw8821a_pwrtrk_5ga_p[1], + .pwrtrk_5ga_p[2] = rtw8821a_pwrtrk_5ga_p[2], + .pwrtrk_2gb_n = rtw8821a_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8821a_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8821a_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8821a_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8821a_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8821a_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8821a_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8821a_pwrtrk_2g_cck_a_p, +}; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h new file mode 100644 index 000000000000..90379ac7a817 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW8821A_TABLE_H__ +#define __RTW8821A_TABLE_H__ + +extern const struct rtw_table rtw8821a_mac_tbl; +extern const struct rtw_table rtw8821a_agc_tbl; +extern const struct rtw_table rtw8821a_bb_tbl; +extern const struct rtw_table rtw8821a_bb_pg_tbl; +extern const struct rtw_table rtw8821a_rf_a_tbl; +extern const struct rtw_table rtw8821a_txpwr_lmt_tbl; + +extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8821a[]; +extern const struct rtw_pwr_seq_cmd * const enter_lps_flow_8821a[]; +extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8821a[]; + +extern const struct rtw_pwr_track_tbl rtw8821a_rtw_pwr_track_tbl; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821au.c b/drivers/net/wireless/realtek/rtw88/rtw8821au.c new file mode 100644 index 000000000000..730018773e1c --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821au.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include <linux/module.h> +#include <linux/usb.h> +#include "main.h" +#include "rtw8821a.h" +#include "usb.h" + +static const struct usb_device_id rtw_8821au_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x011e, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8821au_id_table); + +static struct usb_driver rtw_8821au_driver = { + .name = "rtw_8821au", + .id_table = rtw_8821au_id_table, + .probe = rtw_usb_probe, + .disconnect = rtw_usb_disconnect, +}; +module_usb_driver(rtw_8821au_driver); + +MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821au/8811au driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index 526e8de77b3e..0270225b9c20 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -679,47 +679,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, } } -static void rtw8821c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc); - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - /* drv_info_sz is in unit of 8-bytes */ - pkt_stat->drv_info_sz *= 8; - - /* c2h cmd pkt's rx/phy status is not interested */ - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); -} - static void rtw8821c_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) { @@ -1254,7 +1213,7 @@ static void rtw8821c_fill_txdesc_checksum(struct rtw_dev *rtwdev, fill_txdesc_checksum_common(txdesc, 16); } -static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { +static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { {0x0086, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_SDIO_MSK, @@ -1292,7 +1251,7 @@ static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = { +static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = { {0x0020, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, @@ -1396,7 +1355,7 @@ static struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = { +static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = { {0x0093, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, @@ -1454,7 +1413,7 @@ static struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = { +static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = { {0x0007, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, @@ -1567,13 +1526,13 @@ static struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8821c[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8821c[] = { trans_carddis_to_cardemu_8821c, trans_cardemu_to_act_8821c, NULL }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8821c[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8821c[] = { trans_act_to_cardemu_8821c, trans_cardemu_to_carddis_8821c, NULL @@ -1622,14 +1581,7 @@ static const struct rtw_intf_phy_para_table phy_para_table_8821c = { .n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8821c), }; -static const struct rtw_rfe_def rtw8821c_rfe_defs[] = { - [0] = RTW_DEF_RFE(8821c, 0, 0), - [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), - [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), - [6] = RTW_DEF_RFE(8821c, 0, 0), -}; - -static struct rtw_hw_reg rtw8821c_dig[] = { +static const struct rtw_hw_reg rtw8821c_dig[] = { [0] = { .addr = 0xc50, .mask = 0x7f }, }; @@ -1639,7 +1591,7 @@ static const struct rtw_ltecoex_addr rtw8821c_ltecoex_addr = { .rdata = LTECOEX_READ_DATA, }; -static struct rtw_page_table page_table_8821c[] = { +static const struct rtw_page_table page_table_8821c[] = { /* not sure what [0] stands for */ {16, 16, 16, 14, 1}, {16, 16, 16, 14, 1}, @@ -1648,7 +1600,7 @@ static struct rtw_page_table page_table_8821c[] = { {16, 16, 16, 14, 1}, }; -static struct rtw_rqpn rqpn_table_8821c[] = { +static const struct rtw_rqpn rqpn_table_8821c[] = { /* not sure what [0] stands for */ {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, @@ -1667,7 +1619,7 @@ static struct rtw_rqpn rqpn_table_8821c[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; -static struct rtw_prioq_addrs prioq_addrs_8821c = { +static const struct rtw_prioq_addrs prioq_addrs_8821c = { .prio[RTW_DMA_MAPPING_EXTRA] = { .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, }, @@ -1683,10 +1635,12 @@ static struct rtw_prioq_addrs prioq_addrs_8821c = { .wsize = true, }; -static struct rtw_chip_ops rtw8821c_ops = { +static const struct rtw_chip_ops rtw8821c_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .phy_set_param = rtw8821c_phy_set_param, .read_efuse = rtw8821c_read_efuse, - .query_rx_desc = rtw8821c_query_rx_desc, + .query_phy_status = query_phy_status, .set_channel = rtw8821c_set_channel, .mac_init = rtw8821c_mac_init, .read_rf = rtw_phy_read_rf, @@ -1938,7 +1892,7 @@ static const u8 rtw8821c_pwrtrk_2g_cck_a_p[] = { 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9 }; -static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = { +static const struct rtw_pwr_track_tbl rtw8821c_pwr_track_type0_tbl = { .pwrtrk_5gb_n[0] = rtw8821c_pwrtrk_5gb_n[0], .pwrtrk_5gb_n[1] = rtw8821c_pwrtrk_5gb_n[1], .pwrtrk_5gb_n[2] = rtw8821c_pwrtrk_5gb_n[2], @@ -1961,6 +1915,13 @@ static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = { .pwrtrk_2g_ccka_p = rtw8821c_pwrtrk_2g_cck_a_p, }; +static const struct rtw_rfe_def rtw8821c_rfe_defs[] = { + [0] = RTW_DEF_RFE(8821c, 0, 0, 0), + [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 0, 2), + [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 0, 2), + [6] = RTW_DEF_RFE(8821c, 0, 0, 0), +}; + static const struct rtw_reg_domain coex_info_hw_regs_8821c[] = { {0xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32}, {0xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32}, @@ -2009,6 +1970,9 @@ const struct rtw_chip_info rtw8821c_hw_spec = { .page_size = TX_PAGE_SIZE, .dig_min = 0x1c, .usb_tx_agg_desc_num = 3, + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = false, .ht_supported = true, .vht_supported = true, .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), @@ -2030,7 +1994,6 @@ const struct rtw_chip_info rtw8821c_hw_spec = { .rfe_defs = rtw8821c_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8821c_rfe_defs), .rx_ldpc = false, - .pwr_track_tbl = &rtw8821c_rtw_pwr_track_tbl, .iqk_threshold = 8, .bfer_su_max_num = 2, .bfer_mu_max_num = 1, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h index 91ed921407bb..7a33ebd612ed 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h @@ -214,19 +214,10 @@ extern const struct rtw_chip_info rtw8821c_hw_spec; #define BIT_FEN_EN BIT(26) #define REG_INIRTS_RATE_SEL 0x0480 #define REG_HTSTFWT 0x800 -#define REG_RXPSEL 0x808 -#define BIT_RX_PSEL_RST (BIT(28) | BIT(29)) -#define REG_TXPSEL 0x80c #define REG_RXCCAMSK 0x814 -#define REG_CCASEL 0x82c -#define REG_PDMFTH 0x830 -#define REG_CCA2ND 0x838 #define REG_L1WT 0x83c #define REG_L1PKWT 0x840 #define REG_MRC 0x850 -#define REG_CLKTRK 0x860 -#define REG_ADCCLK 0x8ac -#define REG_ADC160 0x8c4 #define REG_ADC40 0x8c8 #define REG_CHFIR 0x8f0 #define REG_CDDTXP 0x93c @@ -234,14 +225,11 @@ extern const struct rtw_chip_info rtw8821c_hw_spec; #define REG_ACBB0 0x948 #define REG_ACBBRXFIR 0x94c #define REG_ACGG2TBL 0x958 -#define REG_FAS 0x9a4 -#define REG_RXSB 0xa00 #define REG_ADCINI 0xa04 #define REG_PWRTH 0xa08 #define REG_CCA_FLTR 0xa20 #define REG_TXSF2 0xa24 #define REG_TXSF6 0xa28 -#define REG_FA_CCK 0xa5c #define REG_RXDESC 0xa2c #define REG_ENTXCCK 0xa80 #define BTG_LNA 0xfc84 @@ -252,12 +240,8 @@ extern const struct rtw_chip_info rtw8821c_hw_spec; #define REG_PWRTH2 0xaa8 #define REG_CSRATIO 0xaaa #define REG_TXFILTER 0xaac -#define REG_CNTRST 0xb58 #define REG_AGCTR_A 0xc08 -#define REG_TXSCALE_A 0xc1c #define REG_TXDFIR 0xc20 -#define REG_RXIGI_A 0xc50 -#define REG_TXAGCIDX 0xc94 #define REG_TRSW 0xca0 #define REG_RFESEL0 0xcb0 #define REG_RFESEL8 0xcb4 @@ -269,14 +253,6 @@ extern const struct rtw_chip_info rtw8821c_hw_spec; #define B_WLA_SWITCH BIT(23) #define REG_RFEINV 0xcbc #define REG_AGCTR_B 0xe08 -#define REG_RXIGI_B 0xe50 -#define REG_CRC_CCK 0xf04 -#define REG_CRC_OFDM 0xf14 -#define REG_CRC_HT 0xf10 -#define REG_CRC_VHT 0xf0c -#define REG_CCA_OFDM 0xf08 -#define REG_FA_OFDM 0xf48 -#define REG_CCA_CCK 0xfcc #define REG_DMEM_CTRL 0x1080 #define BIT_WL_RST BIT(16) #define REG_ANTWT 0x1904 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 6edb17aea90e..739809f4cab5 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -934,47 +934,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, } } -static void rtw8822b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc); - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - /* drv_info_sz is in unit of 8-bytes */ - pkt_stat->drv_info_sz *= 8; - - /* c2h cmd pkt's rx/phy status is not interested */ - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); -} - static void rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) { @@ -1978,13 +1937,13 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822b[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8822b[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8822b[] = { trans_carddis_to_cardemu_8822b, trans_cardemu_to_act_8822b, NULL }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8822b[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8822b[] = { trans_act_to_cardemu_8822b, trans_cardemu_to_carddis_8822b, NULL @@ -2113,12 +2072,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8822b = { .n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8822b), }; -static const struct rtw_rfe_def rtw8822b_rfe_defs[] = { - [2] = RTW_DEF_RFE(8822b, 2, 2), - [3] = RTW_DEF_RFE(8822b, 3, 0), - [5] = RTW_DEF_RFE(8822b, 5, 5), -}; - static const struct rtw_hw_reg rtw8822b_dig[] = { [0] = { .addr = 0xc50, .mask = 0x7f }, [1] = { .addr = 0xe50, .mask = 0x7f }, @@ -2156,7 +2109,7 @@ static const struct rtw_rqpn rqpn_table_8822b[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; -static struct rtw_prioq_addrs prioq_addrs_8822b = { +static const struct rtw_prioq_addrs prioq_addrs_8822b = { .prio[RTW_DMA_MAPPING_EXTRA] = { .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, }, @@ -2172,10 +2125,12 @@ static struct rtw_prioq_addrs prioq_addrs_8822b = { .wsize = true, }; -static struct rtw_chip_ops rtw8822b_ops = { +static const struct rtw_chip_ops rtw8822b_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .phy_set_param = rtw8822b_phy_set_param, .read_efuse = rtw8822b_read_efuse, - .query_rx_desc = rtw8822b_query_rx_desc, + .query_phy_status = query_phy_status, .set_channel = rtw8822b_set_channel, .mac_init = rtw8822b_mac_init, .read_rf = rtw_phy_read_rf, @@ -2471,7 +2426,7 @@ static const u8 rtw8822b_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = { 10, 11, 11, 12, 12, 13, 13, 14, 14, 15 }; -static const struct rtw_pwr_track_tbl rtw8822b_rtw_pwr_track_tbl = { +static const struct rtw_pwr_track_tbl rtw8822b_pwr_track_type0_tbl = { .pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1], .pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2], .pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3], @@ -2494,6 +2449,12 @@ static const struct rtw_pwr_track_tbl rtw8822b_rtw_pwr_track_tbl = { .pwrtrk_2g_ccka_p = rtw8822b_pwrtrk_2g_cck_a_p, }; +static const struct rtw_rfe_def rtw8822b_rfe_defs[] = { + [2] = RTW_DEF_RFE(8822b, 2, 2, 0), + [3] = RTW_DEF_RFE(8822b, 3, 0, 0), + [5] = RTW_DEF_RFE(8822b, 5, 5, 0), +}; + static const struct rtw_reg_domain coex_info_hw_regs_8822b[] = { {0xcb0, MASKDWORD, RTW_REG_DOMAIN_MAC32}, {0xcb4, MASKDWORD, RTW_REG_DOMAIN_MAC32}, @@ -2521,7 +2482,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8822b[] = { {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, }; -static struct rtw_hw_reg_offset rtw8822b_edcca_th[] = { +static const struct rtw_hw_reg_offset rtw8822b_edcca_th[] = { [EDCCA_TH_L2H_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE0}, .offset = 0}, [EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0}, }; @@ -2550,6 +2511,9 @@ const struct rtw_chip_info rtw8822b_hw_spec = { .page_size = TX_PAGE_SIZE, .dig_min = 0x1c, .usb_tx_agg_desc_num = 3, + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = false, .ht_supported = true, .vht_supported = true, .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), @@ -2571,7 +2535,6 @@ const struct rtw_chip_info rtw8822b_hw_spec = { .rf_tbl = {&rtw8822b_rf_a_tbl, &rtw8822b_rf_b_tbl}, .rfe_defs = rtw8822b_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8822b_rfe_defs), - .pwr_track_tbl = &rtw8822b_rtw_pwr_track_tbl, .iqk_threshold = 8, .bfer_su_max_num = 2, .bfer_mu_max_num = 1, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.h b/drivers/net/wireless/realtek/rtw88/rtw8822b.h index cf85e63966a1..0514958fb57c 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h @@ -151,21 +151,12 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) #define RTW8822B_EDCCA_MAX 0x7f #define RTW8822B_EDCCA_SRC_DEF 1 #define REG_HTSTFWT 0x800 -#define REG_RXPSEL 0x808 -#define BIT_RX_PSEL_RST (BIT(28) | BIT(29)) -#define REG_TXPSEL 0x80c #define REG_RXCCAMSK 0x814 -#define REG_CCASEL 0x82c -#define REG_PDMFTH 0x830 -#define REG_CCA2ND 0x838 #define REG_L1WT 0x83c #define REG_L1PKWT 0x840 #define REG_MRC 0x850 -#define REG_CLKTRK 0x860 #define REG_EDCCA_POW_MA 0x8a0 #define BIT_MA_LEVEL GENMASK(1, 0) -#define REG_ADCCLK 0x8ac -#define REG_ADC160 0x8c4 #define REG_ADC40 0x8c8 #define REG_EDCCA_DECISION 0x8dc #define BIT_EDCCA_OPTION BIT(5) @@ -176,7 +167,6 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) #define REG_ACBB0 0x948 #define REG_ACBBRXFIR 0x94c #define REG_ACGG2TBL 0x958 -#define REG_RXSB 0xa00 #define REG_ADCINI 0xa04 #define REG_TXSF2 0xa24 #define REG_TXSF6 0xa28 @@ -184,14 +174,12 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) #define REG_ENTXCCK 0xa80 #define REG_AGCTR_A 0xc08 #define REG_TXDFIR 0xc20 -#define REG_RXIGI_A 0xc50 #define REG_TRSW 0xca0 #define REG_RFESEL0 0xcb0 #define REG_RFESEL8 0xcb4 #define REG_RFECTL 0xcb8 #define REG_RFEINV 0xcbc #define REG_AGCTR_B 0xe08 -#define REG_RXIGI_B 0xe50 #define REG_ANTWT 0x1904 #define REG_IQKFAILMSK 0x1bf0 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 1dbe1cdbc3fd..af6b76937f1d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -2690,48 +2690,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, } } -static void rtw8822c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc); - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - /* drv_info_sz is in unit of 8-bytes */ - pkt_stat->drv_info_sz *= 8; - - /* c2h cmd pkt's rx/phy status is not interested */ - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - pkt_stat->hdr = hdr; - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); -} - static void rtw8822c_set_write_tx_power_ref(struct rtw_dev *rtwdev, u8 *tx_pwr_ref_cck, u8 *tx_pwr_ref_ofdm) @@ -4874,13 +4832,13 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8822c[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8822c[] = { trans_carddis_to_cardemu_8822c, trans_cardemu_to_act_8822c, NULL }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8822c[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8822c[] = { trans_act_to_cardemu_8822c, trans_cardemu_to_carddis_8822c, NULL @@ -4925,16 +4883,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8822c = { .n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8822c), }; -static const struct rtw_rfe_def rtw8822c_rfe_defs[] = { - [0] = RTW_DEF_RFE(8822c, 0, 0), - [1] = RTW_DEF_RFE(8822c, 0, 0), - [2] = RTW_DEF_RFE(8822c, 0, 0), - [3] = RTW_DEF_RFE(8822c, 0, 0), - [4] = RTW_DEF_RFE(8822c, 0, 0), - [5] = RTW_DEF_RFE(8822c, 0, 5), - [6] = RTW_DEF_RFE(8822c, 0, 0), -}; - static const struct rtw_hw_reg rtw8822c_dig[] = { [0] = { .addr = 0x1d70, .mask = 0x7f }, [1] = { .addr = 0x1d70, .mask = 0x7f00 }, @@ -4972,7 +4920,7 @@ static const struct rtw_rqpn rqpn_table_8822c[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; -static struct rtw_prioq_addrs prioq_addrs_8822c = { +static const struct rtw_prioq_addrs prioq_addrs_8822c = { .prio[RTW_DMA_MAPPING_EXTRA] = { .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, }, @@ -4988,10 +4936,12 @@ static struct rtw_prioq_addrs prioq_addrs_8822c = { .wsize = true, }; -static struct rtw_chip_ops rtw8822c_ops = { +static const struct rtw_chip_ops rtw8822c_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .phy_set_param = rtw8822c_phy_set_param, .read_efuse = rtw8822c_read_efuse, - .query_rx_desc = rtw8822c_query_rx_desc, + .query_phy_status = query_phy_status, .set_channel = rtw8822c_set_channel, .mac_init = rtw8822c_mac_init, .dump_fw_crash = rtw8822c_dump_fw_crash, @@ -5278,7 +5228,7 @@ static const u8 rtw8822c_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = { 18, 18, 19, 20, 21, 22, 23, 24, 24, 25 }; -static const struct rtw_pwr_track_tbl rtw8822c_rtw_pwr_track_tbl = { +static const struct rtw_pwr_track_tbl rtw8822c_pwr_track_type0_tbl = { .pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1], .pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2], .pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3], @@ -5301,7 +5251,17 @@ static const struct rtw_pwr_track_tbl rtw8822c_rtw_pwr_track_tbl = { .pwrtrk_2g_ccka_p = rtw8822c_pwrtrk_2g_cck_a_p, }; -static struct rtw_hw_reg_offset rtw8822c_edcca_th[] = { +static const struct rtw_rfe_def rtw8822c_rfe_defs[] = { + [0] = RTW_DEF_RFE(8822c, 0, 0, 0), + [1] = RTW_DEF_RFE(8822c, 0, 0, 0), + [2] = RTW_DEF_RFE(8822c, 0, 0, 0), + [3] = RTW_DEF_RFE(8822c, 0, 0, 0), + [4] = RTW_DEF_RFE(8822c, 0, 0, 0), + [5] = RTW_DEF_RFE(8822c, 0, 5, 0), + [6] = RTW_DEF_RFE(8822c, 0, 0, 0), +}; + +static const struct rtw_hw_reg_offset rtw8822c_edcca_th[] = { [EDCCA_TH_L2H_IDX] = { {.addr = 0x84c, .mask = MASKBYTE2}, .offset = 0x80 }, @@ -5371,6 +5331,9 @@ const struct rtw_chip_info rtw8822c_hw_spec = { .page_size = TX_PAGE_SIZE, .dig_min = 0x20, .usb_tx_agg_desc_num = 3, + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = false, .default_1ss_tx_path = BB_PATH_A, .path_div_supported = true, .ht_supported = true, @@ -5397,7 +5360,6 @@ const struct rtw_chip_info rtw8822c_hw_spec = { .rfe_defs_size = ARRAY_SIZE(rtw8822c_rfe_defs), .en_dis_dpd = true, .dpd_ratemask = DIS_DPD_RATEALL, - .pwr_track_tbl = &rtw8822c_rtw_pwr_track_tbl, .iqk_threshold = 8, .lck_threshold = 8, .bfer_su_max_num = 2, diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c new file mode 100644 index 000000000000..71e61b9c0bec --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c @@ -0,0 +1,1989 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include <linux/usb.h> +#include "main.h" +#include "coex.h" +#include "phy.h" +#include "rtw88xxa.h" +#include "mac.h" +#include "reg.h" +#include "sec.h" +#include "debug.h" +#include "bf.h" +#include "efuse.h" +#include "usb.h" + +void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on) +{ + if (on) { + rtw_write8(rtwdev, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); + + rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_ELDR); + rtw_write16_set(rtwdev, REG_SYS_CLKR, + BIT_LOADER_CLK_EN | BIT_ANA8M); + } else { + rtw_write8(rtwdev, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); + } +} +EXPORT_SYMBOL(rtw88xxa_efuse_grant); + +static void rtw8812a_read_amplifier_type(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + + efuse->ext_pa_2g = (efuse->pa_type_2g & BIT(5)) && + (efuse->pa_type_2g & BIT(4)); + efuse->ext_lna_2g = (efuse->lna_type_2g & BIT(7)) && + (efuse->lna_type_2g & BIT(3)); + + efuse->ext_pa_5g = (efuse->pa_type_5g & BIT(1)) && + (efuse->pa_type_5g & BIT(0)); + efuse->ext_lna_5g = (efuse->lna_type_5g & BIT(7)) && + (efuse->lna_type_5g & BIT(3)); + + /* For rtw_phy_cond2: */ + if (efuse->ext_pa_2g) { + u8 ext_type_pa_2g_a = u8_get_bits(efuse->lna_type_2g, BIT(2)); + u8 ext_type_pa_2g_b = u8_get_bits(efuse->lna_type_2g, BIT(6)); + + efuse->gpa_type = (ext_type_pa_2g_b << 2) | ext_type_pa_2g_a; + } + + if (efuse->ext_pa_5g) { + u8 ext_type_pa_5g_a = u8_get_bits(efuse->lna_type_5g, BIT(2)); + u8 ext_type_pa_5g_b = u8_get_bits(efuse->lna_type_5g, BIT(6)); + + efuse->apa_type = (ext_type_pa_5g_b << 2) | ext_type_pa_5g_a; + } + + if (efuse->ext_lna_2g) { + u8 ext_type_lna_2g_a = u8_get_bits(efuse->lna_type_2g, + BIT(1) | BIT(0)); + u8 ext_type_lna_2g_b = u8_get_bits(efuse->lna_type_2g, + BIT(5) | BIT(4)); + + efuse->glna_type = (ext_type_lna_2g_b << 2) | ext_type_lna_2g_a; + } + + if (efuse->ext_lna_5g) { + u8 ext_type_lna_5g_a = u8_get_bits(efuse->lna_type_5g, + BIT(1) | BIT(0)); + u8 ext_type_lna_5g_b = u8_get_bits(efuse->lna_type_5g, + BIT(5) | BIT(4)); + + efuse->alna_type = (ext_type_lna_5g_b << 2) | ext_type_lna_5g_a; + } +} + +static void rtw8812a_read_rfe_type(struct rtw_dev *rtwdev, + struct rtw88xxa_efuse *map) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + + if (map->rfe_option == 0xff) { + if (rtwdev->hci.type == RTW_HCI_TYPE_USB) + efuse->rfe_option = 0; + else if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE) + efuse->rfe_option = 2; + else + efuse->rfe_option = 4; + } else if (map->rfe_option & BIT(7)) { + if (efuse->ext_lna_5g) { + if (efuse->ext_pa_5g) { + if (efuse->ext_lna_2g && efuse->ext_pa_2g) + efuse->rfe_option = 3; + else + efuse->rfe_option = 0; + } else { + efuse->rfe_option = 2; + } + } else { + efuse->rfe_option = 4; + } + } else { + efuse->rfe_option = map->rfe_option & 0x3f; + + /* Due to other customer already use incorrect EFUSE map for + * their product. We need to add workaround to prevent to + * modify spec and notify all customer to revise the IC 0xca + * content. + */ + if (efuse->rfe_option == 4 && + (efuse->ext_pa_5g || efuse->ext_pa_2g || + efuse->ext_lna_5g || efuse->ext_lna_2g)) { + if (rtwdev->hci.type == RTW_HCI_TYPE_USB) + efuse->rfe_option = 0; + else if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE) + efuse->rfe_option = 2; + } + } +} + +static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_hal *hal = &rtwdev->hal; + u8 antenna = 0; + u8 wmode = 0; + u8 val8, i; + + efuse->hw_cap.bw = BIT(RTW_CHANNEL_WIDTH_20) | + BIT(RTW_CHANNEL_WIDTH_40) | + BIT(RTW_CHANNEL_WIDTH_80); + efuse->hw_cap.ptcl = EFUSE_HW_CAP_PTCL_VHT; + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) + efuse->hw_cap.nss = 1; + else + efuse->hw_cap.nss = 2; + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) + goto print_hw_cap; + + for (i = 0; i < 2; i++) { + rtw_read8_physical_efuse(rtwdev, 1019 - i, &val8); + + antenna = u8_get_bits(val8, GENMASK(7, 5)); + if (antenna) + break; + antenna = u8_get_bits(val8, GENMASK(3, 1)); + if (antenna) + break; + } + + for (i = 0; i < 2; i++) { + rtw_read8_physical_efuse(rtwdev, 1021 - i, &val8); + + wmode = u8_get_bits(val8, GENMASK(3, 2)); + if (wmode) + break; + } + + if (antenna == 1) { + rtw_info(rtwdev, "This RTL8812AU says it is 1T1R.\n"); + + efuse->hw_cap.nss = 1; + hal->rf_type = RF_1T1R; + hal->rf_path_num = 1; + hal->rf_phy_num = 1; + hal->antenna_tx = BB_PATH_A; + hal->antenna_rx = BB_PATH_A; + } else { + /* Override rtw_chip_parameter_setup(). It detects 8812au as 1T1R. */ + efuse->hw_cap.nss = 2; + hal->rf_type = RF_2T2R; + hal->rf_path_num = 2; + hal->rf_phy_num = 2; + hal->antenna_tx = BB_PATH_AB; + hal->antenna_rx = BB_PATH_AB; + + if (antenna == 2 && wmode == 2) { + rtw_info(rtwdev, "This RTL8812AU says it can't do VHT.\n"); + + /* Can't be EFUSE_HW_CAP_IGNORE and can't be + * EFUSE_HW_CAP_PTCL_VHT, so make it 1. + */ + efuse->hw_cap.ptcl = 1; + efuse->hw_cap.bw &= ~BIT(RTW_CHANNEL_WIDTH_80); + } + } + +print_hw_cap: + rtw_dbg(rtwdev, RTW_DBG_EFUSE, + "hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d\n", + efuse->hw_cap.hci, efuse->hw_cap.bw, efuse->hw_cap.ptcl, + efuse->hw_cap.ant_num, efuse->hw_cap.nss); +} + +int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw88xxa_efuse *map; + int i; + + if (chip->id == RTW_CHIP_TYPE_8812A) + rtwdev->hal.cut_version += 1; + + if (rtw_dbg_is_enabled(rtwdev, RTW_DBG_EFUSE)) + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, + log_map, chip->log_efuse_size, true); + + map = (struct rtw88xxa_efuse *)log_map; + + efuse->rf_board_option = map->rf_board_option; + efuse->crystal_cap = map->xtal_k; + if (efuse->crystal_cap == 0xff) + efuse->crystal_cap = 0x20; + efuse->pa_type_2g = map->pa_type; + efuse->pa_type_5g = map->pa_type; + efuse->lna_type_2g = map->lna_type_2g; + efuse->lna_type_5g = map->lna_type_5g; + if (chip->id == RTW_CHIP_TYPE_8812A) { + rtw8812a_read_amplifier_type(rtwdev); + rtw8812a_read_rfe_type(rtwdev, map); + + efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(1)); + } + efuse->channel_plan = map->channel_plan; + efuse->country_code[0] = map->country_code[0]; + efuse->country_code[1] = map->country_code[1]; + efuse->bt_setting = map->rf_bt_setting; + efuse->regd = map->rf_board_option & 0x7; + efuse->thermal_meter[0] = map->thermal_meter; + efuse->thermal_meter[1] = map->thermal_meter; + efuse->thermal_meter_k = map->thermal_meter; + efuse->tx_bb_swing_setting_2g = map->tx_bb_swing_setting_2g; + efuse->tx_bb_swing_setting_5g = map->tx_bb_swing_setting_5g; + + rtw88xxa_read_usb_type(rtwdev); + + if (chip->id == RTW_CHIP_TYPE_8821A) + efuse->btcoex = rtw_read32_mask(rtwdev, REG_WL_BT_PWR_CTRL, + BIT_BT_FUNC_EN); + else + efuse->btcoex = (map->rf_board_option & 0xe0) == 0x20; + efuse->share_ant = !!(efuse->bt_setting & BIT(0)); + + /* No antenna diversity because it's disabled in the vendor driver */ + efuse->ant_div_cfg = 0; + + efuse->ant_div_type = map->rf_antenna_option; + if (efuse->ant_div_type == 0xff) + efuse->ant_div_type = 0x3; + + for (i = 0; i < 4; i++) + efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i]; + + switch (rtw_hci_type(rtwdev)) { + case RTW_HCI_TYPE_USB: + if (chip->id == RTW_CHIP_TYPE_8821A) + ether_addr_copy(efuse->addr, map->rtw8821au.mac_addr); + else + ether_addr_copy(efuse->addr, map->rtw8812au.mac_addr); + break; + case RTW_HCI_TYPE_PCIE: + case RTW_HCI_TYPE_SDIO: + default: + /* unsupported now */ + return -EOPNOTSUPP; + } + + return 0; +} +EXPORT_SYMBOL(rtw88xxa_read_efuse); + +static void rtw88xxa_reset_8051(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + u8 val8; + + /* Reset MCU IO Wrapper */ + rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1)); + if (chip->id == RTW_CHIP_TYPE_8812A) + rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT(3)); + else + rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT(0)); + + val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN + 1); + rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, val8 & ~BIT(2)); + + /* Enable MCU IO Wrapper */ + rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1)); + if (chip->id == RTW_CHIP_TYPE_8812A) + rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT(3)); + else + rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT(0)); + + rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, val8 | BIT(2)); +} + +/* A lightweight deinit function */ +static void rtw88xxau_hw_reset(struct rtw_dev *rtwdev) +{ + u8 val8; + + if (!(rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_RAM_DL_SEL)) + return; + + rtw88xxa_reset_8051(rtwdev); + rtw_write8(rtwdev, REG_MCUFW_CTRL, 0x00); + + /* before BB reset should do clock gated */ + rtw_write32_set(rtwdev, REG_FPGA0_XCD_RF_PARA, BIT(6)); + + /* reset BB */ + rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1)); + + /* reset RF */ + rtw_write8(rtwdev, REG_RF_CTRL, 0); + + /* reset TRX path */ + rtw_write16(rtwdev, REG_CR, 0); + + /* reset MAC, reg0x5[1], auto FSM off */ + rtw_write8_set(rtwdev, REG_APS_FSMCO + 1, APS_FSMCO_MAC_OFF >> 8); + + /* check if reg0x5[1] auto cleared */ + if (read_poll_timeout_atomic(rtw_read8, val8, + !(val8 & (APS_FSMCO_MAC_OFF >> 8)), + 1, 5000, false, + rtwdev, REG_APS_FSMCO + 1)) + rtw_err(rtwdev, "%s: timed out waiting for 0x5[1]\n", __func__); + + /* reg0x5[0], auto FSM on */ + val8 |= APS_FSMCO_MAC_ENABLE >> 8; + rtw_write8(rtwdev, REG_APS_FSMCO + 1, val8); + + rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT(4) | BIT(7)); + rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT(4) | BIT(7)); +} + +static int rtw88xxau_init_power_on(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + u16 val16; + int ret; + + ret = rtw_pwr_seq_parser(rtwdev, chip->pwr_on_seq); + if (ret) { + rtw_err(rtwdev, "power on flow failed\n"); + return ret; + } + + rtw_write16(rtwdev, REG_CR, 0); + val16 = BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | + BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | + BIT_MAC_SEC_EN | BIT_32K_CAL_TMR_EN; + rtw_write16_set(rtwdev, REG_CR, val16); + + if (chip->id == RTW_CHIP_TYPE_8821A) { + if (rtw_read8(rtwdev, REG_SYS_CFG1 + 3) & BIT(0)) + rtw_write8_set(rtwdev, REG_LDO_SWR_CTRL, BIT(6)); + } + + return ret; +} + +static int rtw88xxa_llt_write(struct rtw_dev *rtwdev, u32 address, u32 data) +{ + u32 value = BIT_LLT_WRITE_ACCESS | (address << 8) | data; + int count = 0; + + rtw_write32(rtwdev, REG_LLT_INIT, value); + + do { + if (!rtw_read32_mask(rtwdev, REG_LLT_INIT, BIT(31) | BIT(30))) + break; + + if (count > 20) { + rtw_err(rtwdev, "Failed to poll write LLT done at %d!\n", + address); + return -EBUSY; + } + } while (++count); + + return 0; +} + +static int rtw88xxa_llt_init(struct rtw_dev *rtwdev, u32 boundary) +{ + u32 last_entry = 255; + int status = 0; + u32 i; + + for (i = 0; i < boundary - 1; i++) { + status = rtw88xxa_llt_write(rtwdev, i, i + 1); + if (status) + return status; + } + + status = rtw88xxa_llt_write(rtwdev, boundary - 1, 0xFF); + if (status) + return status; + + for (i = boundary; i < last_entry; i++) { + status = rtw88xxa_llt_write(rtwdev, i, i + 1); + if (status) + return status; + } + + status = rtw88xxa_llt_write(rtwdev, last_entry, boundary); + + return status; +} + +static void rtw88xxau_init_queue_reserved_page(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_fifo_conf *fifo = &rtwdev->fifo; + const struct rtw_page_table *pg_tbl = NULL; + u16 pubq_num; + u32 val32; + + switch (rtw_hci_type(rtwdev)) { + case RTW_HCI_TYPE_PCIE: + pg_tbl = &chip->page_table[1]; + break; + case RTW_HCI_TYPE_USB: + if (rtwdev->hci.bulkout_num == 2) + pg_tbl = &chip->page_table[2]; + else if (rtwdev->hci.bulkout_num == 3) + pg_tbl = &chip->page_table[3]; + else if (rtwdev->hci.bulkout_num == 4) + pg_tbl = &chip->page_table[4]; + break; + case RTW_HCI_TYPE_SDIO: + pg_tbl = &chip->page_table[0]; + break; + default: + break; + } + + pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - + pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; + + val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num); + rtw_write32(rtwdev, REG_RQPN_NPQ, val32); + + val32 = BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num); + rtw_write32(rtwdev, REG_RQPN, val32); +} + +static void rtw88xxau_init_tx_buffer_boundary(struct rtw_dev *rtwdev) +{ + struct rtw_fifo_conf *fifo = &rtwdev->fifo; + + rtw_write8(rtwdev, REG_BCNQ_BDNY, fifo->rsvd_boundary); + rtw_write8(rtwdev, REG_MGQ_BDNY, fifo->rsvd_boundary); + rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, fifo->rsvd_boundary); + rtw_write8(rtwdev, REG_TRXFF_BNDY, fifo->rsvd_boundary); + rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1, fifo->rsvd_boundary); +} + +static int rtw88xxau_init_queue_priority(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + u8 bulkout_num = rtwdev->hci.bulkout_num; + const struct rtw_rqpn *rqpn = NULL; + u16 txdma_pq_map; + + switch (rtw_hci_type(rtwdev)) { + case RTW_HCI_TYPE_PCIE: + rqpn = &chip->rqpn_table[1]; + break; + case RTW_HCI_TYPE_USB: + if (bulkout_num == 2) + rqpn = &chip->rqpn_table[2]; + else if (bulkout_num == 3) + rqpn = &chip->rqpn_table[3]; + else if (bulkout_num == 4) + rqpn = &chip->rqpn_table[4]; + else + return -EINVAL; + break; + case RTW_HCI_TYPE_SDIO: + rqpn = &chip->rqpn_table[0]; + break; + default: + return -EINVAL; + } + + rtwdev->fifo.rqpn = rqpn; + + txdma_pq_map = rtw_read16(rtwdev, REG_TXDMA_PQ_MAP) & 0x7; + txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi); + txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg); + txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk); + txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be); + txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi); + txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo); + rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map); + + /* Packet in Hi Queue Tx immediately (No constraint for ATIM Period). */ + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && bulkout_num == 4) + rtw_write8(rtwdev, REG_HIQ_NO_LMT_EN, 0xff); + + return 0; +} + +static void rtw88xxa_init_wmac_setting(struct rtw_dev *rtwdev) +{ + rtw_write16(rtwdev, REG_RXFLTMAP0, 0xffff); + rtw_write16(rtwdev, REG_RXFLTMAP1, 0x0400); + rtw_write16(rtwdev, REG_RXFLTMAP2, 0xffff); + + rtw_write32(rtwdev, REG_MAR, 0xffffffff); + rtw_write32(rtwdev, REG_MAR + 4, 0xffffffff); +} + +static void rtw88xxa_init_adaptive_ctrl(struct rtw_dev *rtwdev) +{ + rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, 0xffff1); + rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x3030); +} + +static void rtw88xxa_init_edca(struct rtw_dev *rtwdev) +{ + rtw_write16(rtwdev, REG_SPEC_SIFS, 0x100a); + rtw_write16(rtwdev, REG_MAC_SPEC_SIFS, 0x100a); + + rtw_write16(rtwdev, REG_SIFS, 0x100a); + rtw_write16(rtwdev, REG_SIFS + 2, 0x100a); + + rtw_write32(rtwdev, REG_EDCA_BE_PARAM, 0x005EA42B); + rtw_write32(rtwdev, REG_EDCA_BK_PARAM, 0x0000A44F); + rtw_write32(rtwdev, REG_EDCA_VI_PARAM, 0x005EA324); + rtw_write32(rtwdev, REG_EDCA_VO_PARAM, 0x002FA226); + + rtw_write8(rtwdev, REG_USTIME_TSF, 0x50); + rtw_write8(rtwdev, REG_USTIME_EDCA, 0x50); +} + +static void rtw88xxau_tx_aggregation(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + + rtw_write32_mask(rtwdev, REG_DWBCN0_CTRL, 0xf0, + chip->usb_tx_agg_desc_num); + + if (chip->id == RTW_CHIP_TYPE_8821A) + rtw_write8(rtwdev, REG_DWBCN1_CTRL, + chip->usb_tx_agg_desc_num << 1); +} + +static void rtw88xxa_init_beacon_parameters(struct rtw_dev *rtwdev) +{ + u16 val16; + + val16 = (BIT_DIS_TSF_UDT << 8) | BIT_DIS_TSF_UDT; + if (rtwdev->efuse.btcoex) + val16 |= BIT_EN_BCN_FUNCTION; + rtw_write16(rtwdev, REG_BCN_CTRL, val16); + + rtw_write32_mask(rtwdev, REG_TBTT_PROHIBIT, 0xfffff, WLAN_TBTT_TIME); + rtw_write8(rtwdev, REG_DRVERLYINT, 0x05); + rtw_write8(rtwdev, REG_BCNDMATIM, WLAN_BCN_DMA_TIME); + rtw_write16(rtwdev, REG_BCNTCFG, 0x4413); +} + +static void rtw88xxa_phy_bb_config(struct rtw_dev *rtwdev) +{ + u8 val8, crystal_cap; + + /* power on BB/RF domain */ + val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN); + val8 |= BIT_FEN_USBA; + rtw_write8(rtwdev, REG_SYS_FUNC_EN, val8); + + /* toggle BB reset */ + val8 |= BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST; + rtw_write8(rtwdev, REG_SYS_FUNC_EN, val8); + + rtw_write8(rtwdev, REG_RF_CTRL, + BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB); + rtw_write8(rtwdev, REG_RF_B_CTRL, + BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB); + + rtw_load_table(rtwdev, rtwdev->chip->bb_tbl); + rtw_load_table(rtwdev, rtwdev->chip->agc_tbl); + + crystal_cap = rtwdev->efuse.crystal_cap & 0x3F; + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) + rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x7FF80000, + crystal_cap | (crystal_cap << 6)); + else + rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x00FFF000, + crystal_cap | (crystal_cap << 6)); +} + +static void rtw88xxa_phy_rf_config(struct rtw_dev *rtwdev) +{ + u8 rf_path; + + for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++) + rtw_load_table(rtwdev, rtwdev->chip->rf_tbl[rf_path]); +} + +static void rtw8812a_config_1t(struct rtw_dev *rtwdev) +{ + /* BB OFDM RX Path_A */ + rtw_write32_mask(rtwdev, REG_RXPSEL, 0xff, 0x11); + + /* BB OFDM TX Path_A */ + rtw_write32_mask(rtwdev, REG_TXPSEL, MASKLWORD, 0x1111); + + /* BB CCK R/Rx Path_A */ + rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0c000000, 0x0); + + /* MCS support */ + rtw_write32_mask(rtwdev, REG_RX_MCS_LIMIT, 0xc0000060, 0x4); + + /* RF Path_B HSSI OFF */ + rtw_write32_mask(rtwdev, REG_3WIRE_SWB, 0xf, 0x4); + + /* RF Path_B Power Down */ + rtw_write32_mask(rtwdev, REG_LSSI_WRITE_B, MASKDWORD, 0); + + /* ADDA Path_B OFF */ + rtw_write32_mask(rtwdev, REG_AFE_PWR1_B, MASKDWORD, 0); + rtw_write32_mask(rtwdev, REG_AFE_PWR2_B, MASKDWORD, 0); +} + +static const u32 rtw88xxa_txscale_tbl[] = { + 0x081, 0x088, 0x090, 0x099, 0x0a2, 0x0ac, 0x0b6, 0x0c0, 0x0cc, 0x0d8, + 0x0e5, 0x0f2, 0x101, 0x110, 0x120, 0x131, 0x143, 0x156, 0x16a, 0x180, + 0x197, 0x1af, 0x1c8, 0x1e3, 0x200, 0x21e, 0x23e, 0x261, 0x285, 0x2ab, + 0x2d3, 0x2fe, 0x32b, 0x35c, 0x38e, 0x3c4, 0x3fe +}; + +static u32 rtw88xxa_get_bb_swing(struct rtw_dev *rtwdev, u8 band, u8 path) +{ + static const u32 swing2setting[4] = {0x200, 0x16a, 0x101, 0x0b6}; + struct rtw_efuse *efuse = &rtwdev->efuse; + u8 tx_bb_swing; + + if (band == RTW_BAND_2G) + tx_bb_swing = efuse->tx_bb_swing_setting_2g; + else + tx_bb_swing = efuse->tx_bb_swing_setting_5g; + + if (path == RF_PATH_B) + tx_bb_swing >>= 2; + tx_bb_swing &= 0x3; + + return swing2setting[tx_bb_swing]; +} + +static u8 rtw88xxa_get_swing_index(struct rtw_dev *rtwdev) +{ + u32 swing, table_value; + u8 i; + + swing = rtw88xxa_get_bb_swing(rtwdev, rtwdev->hal.current_band_type, + RF_PATH_A); + + for (i = 0; i < ARRAY_SIZE(rtw88xxa_txscale_tbl); i++) { + table_value = rtw88xxa_txscale_tbl[i]; + if (swing == table_value) + return i; + } + + return 24; +} + +static void rtw88xxa_pwrtrack_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 path; + + dm_info->default_ofdm_index = rtw88xxa_get_swing_index(rtwdev); + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) + dm_info->default_cck_index = 0; + else + dm_info->default_cck_index = 24; + + for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) { + ewma_thermal_init(&dm_info->avg_thermal[path]); + dm_info->delta_power_index[path] = 0; + dm_info->delta_power_index_last[path] = 0; + } + + dm_info->pwr_trk_triggered = false; + dm_info->pwr_trk_init_trigger = true; + dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; +} + +void rtw88xxa_power_off(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd *const *enter_lps_flow) +{ + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); + enum usb_device_speed speed = rtwusb->udev->speed; + u16 ori_fsmc0; + u8 reg_cr; + + reg_cr = rtw_read8(rtwdev, REG_CR); + + /* Already powered off */ + if (reg_cr == 0 || reg_cr == 0xEA) + return; + + rtw_hci_stop(rtwdev); + + if (!rtwdev->efuse.btcoex) + rtw_write16_clr(rtwdev, REG_GPIO_MUXCFG, BIT_EN_SIC); + + /* set Reg 0xf008[3:4] to 2'11 to enable U1/U2 Mode in USB3.0. */ + if (speed == USB_SPEED_SUPER) + rtw_write8_set(rtwdev, REG_USB_MOD, 0x18); + + rtw_write32(rtwdev, REG_HISR0, 0xffffffff); + rtw_write32(rtwdev, REG_HISR1, 0xffffffff); + rtw_write32(rtwdev, REG_HIMR0, 0); + rtw_write32(rtwdev, REG_HIMR1, 0); + + if (rtwdev->efuse.btcoex) + rtw_coex_power_off_setting(rtwdev); + + ori_fsmc0 = rtw_read16(rtwdev, REG_APS_FSMCO); + rtw_write16(rtwdev, REG_APS_FSMCO, ori_fsmc0 & ~APS_FSMCO_HW_POWERDOWN); + + /* Stop Tx Report Timer. */ + rtw_write8_clr(rtwdev, REG_TX_RPT_CTRL, BIT(1)); + + /* Stop Rx */ + rtw_write8(rtwdev, REG_CR, 0); + + rtw_pwr_seq_parser(rtwdev, enter_lps_flow); + + if (rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_RAM_DL_SEL) + rtw88xxa_reset_8051(rtwdev); + + rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT(2)); + rtw_write8(rtwdev, REG_MCUFW_CTRL, 0); + + rtw_pwr_seq_parser(rtwdev, rtwdev->chip->pwr_off_seq); + + if (ori_fsmc0 & APS_FSMCO_HW_POWERDOWN) + rtw_write16_set(rtwdev, REG_APS_FSMCO, APS_FSMCO_HW_POWERDOWN); + + clear_bit(RTW_FLAG_POWERON, rtwdev->flags); +} +EXPORT_SYMBOL(rtw88xxa_power_off); + +static void rtw88xxa_set_channel_bb_swing(struct rtw_dev *rtwdev, u8 band) +{ + rtw_write32_mask(rtwdev, REG_TXSCALE_A, BB_SWING_MASK, + rtw88xxa_get_bb_swing(rtwdev, band, RF_PATH_A)); + rtw_write32_mask(rtwdev, REG_TXSCALE_B, BB_SWING_MASK, + rtw88xxa_get_bb_swing(rtwdev, band, RF_PATH_B)); + rtw88xxa_pwrtrack_init(rtwdev); +} + +static void rtw8821a_set_ext_band_switch(struct rtw_dev *rtwdev, u8 band) +{ + rtw_write32_mask(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN, 0); + rtw_write32_mask(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL, 1); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0xf, 7); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0xf0, 7); + + if (band == RTW_BAND_2G) + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(29) | BIT(28), 1); + else + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(29) | BIT(28), 2); +} + +static void rtw8821a_phy_set_rfe_reg_24g(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + + /* Turn off RF PA and LNA */ + + /* 0xCB0[15:12] = 0x7 (LNA_On)*/ + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF000, 0x7); + /* 0xCB0[7:4] = 0x7 (PAPE_A)*/ + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF0, 0x7); + + if (efuse->ext_lna_2g) { + /* Turn on 2.4G External LNA */ + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 1); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x2); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x2); + } else { + /* Bypass 2.4G External LNA */ + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 0); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x7); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x7); + } +} + +static void rtw8821a_phy_set_rfe_reg_5g(struct rtw_dev *rtwdev) +{ + /* Turn ON RF PA and LNA */ + + /* 0xCB0[15:12] = 0x7 (LNA_On)*/ + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF000, 0x5); + /* 0xCB0[7:4] = 0x7 (PAPE_A)*/ + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF0, 0x4); + + /* Bypass 2.4G External LNA */ + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 0); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x7); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x7); +} + +static void rtw8812a_phy_set_rfe_reg_24g(struct rtw_dev *rtwdev) +{ + switch (rtwdev->efuse.rfe_option) { + case 0: + case 2: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + break; + case 1: + if (rtwdev->efuse.btcoex) { + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xffffff, 0x777777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0x33f00000, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + } else { + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + } + break; + case 3: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x54337770); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x54337770); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_ANTSEL_SW, 0x00000303, 0x1); + break; + case 4: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x001); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x001); + break; + case 5: + rtw_write8(rtwdev, REG_RFE_PINMUX_A + 2, 0x77); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write8_clr(rtwdev, REG_RFE_INV_A + 3, BIT(0)); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + break; + case 6: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x07772770); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x07772770); + rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077); + rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077); + break; + default: + break; + } +} + +static void rtw8812a_phy_set_rfe_reg_5g(struct rtw_dev *rtwdev) +{ + switch (rtwdev->efuse.rfe_option) { + case 0: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + break; + case 1: + if (rtwdev->efuse.btcoex) { + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xffffff, 0x337717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0x33f00000, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + } else { + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + } + break; + case 2: + case 4: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + break; + case 3: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x54337717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x54337717); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_ANTSEL_SW, 0x00000303, 0x1); + break; + case 5: + rtw_write8(rtwdev, REG_RFE_PINMUX_A + 2, 0x33); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337777); + rtw_write8_set(rtwdev, REG_RFE_INV_A + 3, BIT(0)); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + break; + case 6: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x07737717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x07737717); + rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077); + rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077); + break; + default: + break; + } +} + +static void rtw88xxa_switch_band(struct rtw_dev *rtwdev, u8 new_band, u8 bw) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + u16 basic_rates, reg_41a; + + /* 8811au one antenna module doesn't support antenna div, so driver must + * control antenna band, otherwise one of the band will have issue + */ + if (chip->id == RTW_CHIP_TYPE_8821A && !rtwdev->efuse.btcoex && + rtwdev->efuse.ant_div_cfg == 0) + rtw8821a_set_ext_band_switch(rtwdev, new_band); + + if (new_band == RTW_BAND_2G) { + rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST); + + if (chip->id == RTW_CHIP_TYPE_8821A) { + rtw8821a_phy_set_rfe_reg_24g(rtwdev); + + rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 0); + } else { + rtw_write32_mask(rtwdev, REG_BWINDICATION, 0x3, 0x1); + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(17, 13), 0x17); + + if (bw == RTW_CHANNEL_WIDTH_20 && + rtwdev->hal.rf_type == RF_1T1R && + !rtwdev->efuse.ext_lna_2g) + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x02); + else + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x04); + + rtw_write32_mask(rtwdev, REG_CCASEL, 0x3, 0); + + rtw8812a_phy_set_rfe_reg_24g(rtwdev); + } + + rtw_write32_mask(rtwdev, REG_TXPSEL, 0xf0, 0x1); + rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0f000000, 0x1); + + basic_rates = BIT(DESC_RATE1M) | BIT(DESC_RATE2M) | + BIT(DESC_RATE5_5M) | BIT(DESC_RATE11M) | + BIT(DESC_RATE6M) | BIT(DESC_RATE12M) | + BIT(DESC_RATE24M); + rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, basic_rates); + + rtw_write8_clr(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN); + } else { /* RTW_BAND_5G */ + if (chip->id == RTW_CHIP_TYPE_8821A) + rtw8821a_phy_set_rfe_reg_5g(rtwdev); + + rtw_write8_set(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN); + + read_poll_timeout_atomic(rtw_read16, reg_41a, (reg_41a & 0x30) == 0x30, + 50, 2500, false, rtwdev, REG_TXPKT_EMPTY); + + rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST); + + if (chip->id == RTW_CHIP_TYPE_8821A) { + rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 1); + } else { + rtw_write32_mask(rtwdev, REG_BWINDICATION, 0x3, 0x2); + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(17, 13), 0x15); + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x04); + + rtw_write32_mask(rtwdev, REG_CCASEL, 0x3, 1); + + rtw8812a_phy_set_rfe_reg_5g(rtwdev); + } + + rtw_write32_mask(rtwdev, REG_TXPSEL, 0xf0, 0); + rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0f000000, 0xf); + + basic_rates = BIT(DESC_RATE6M) | BIT(DESC_RATE12M) | + BIT(DESC_RATE24M); + rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, basic_rates); + } + + rtw88xxa_set_channel_bb_swing(rtwdev, new_band); +} + +int rtw88xxa_power_on(struct rtw_dev *rtwdev) +{ + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); + const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_hal *hal = &rtwdev->hal; + int ret; + + if (test_bit(RTW_FLAG_POWERON, rtwdev->flags)) + return 0; + + /* Override rtw_chip_efuse_info_setup() */ + if (chip->id == RTW_CHIP_TYPE_8821A) + efuse->btcoex = rtw_read32_mask(rtwdev, REG_WL_BT_PWR_CTRL, + BIT_BT_FUNC_EN); + + /* Override rtw_chip_efuse_info_setup() */ + if (chip->id == RTW_CHIP_TYPE_8812A) + rtw8812a_read_amplifier_type(rtwdev); + + ret = rtw_hci_setup(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to setup hci\n"); + goto err; + } + + /* Revise for U2/U3 switch we can not update RF-A/B reset. + * Reset after MAC power on to prevent RF R/W error. + * Is it a right method? + */ + if (chip->id == RTW_CHIP_TYPE_8812A) { + rtw_write8(rtwdev, REG_RF_CTRL, 5); + rtw_write8(rtwdev, REG_RF_CTRL, 7); + rtw_write8(rtwdev, REG_RF_B_CTRL, 5); + rtw_write8(rtwdev, REG_RF_B_CTRL, 7); + } + + /* If HW didn't go through a complete de-initial procedure, + * it probably occurs some problem for double initial + * procedure. + */ + rtw88xxau_hw_reset(rtwdev); + + ret = rtw88xxau_init_power_on(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to power on\n"); + goto err; + } + + ret = rtw_set_trx_fifo_info(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to set trx fifo info\n"); + goto err; + } + + ret = rtw88xxa_llt_init(rtwdev, rtwdev->fifo.rsvd_boundary); + if (ret) { + rtw_err(rtwdev, "failed to init llt\n"); + goto err; + } + + rtw_write32_set(rtwdev, REG_TXDMA_OFFSET_CHK, BIT_DROP_DATA_EN); + + ret = rtw_wait_firmware_completion(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to wait firmware completion\n"); + goto err_off; + } + + ret = rtw_download_firmware(rtwdev, &rtwdev->fw); + if (ret) { + rtw_err(rtwdev, "failed to download firmware\n"); + goto err_off; + } + + rtw_write8(rtwdev, REG_HMETFR, 0xf); + + rtw_load_table(rtwdev, chip->mac_tbl); + + rtw88xxau_init_queue_reserved_page(rtwdev); + rtw88xxau_init_tx_buffer_boundary(rtwdev); + rtw88xxau_init_queue_priority(rtwdev); + + rtw_write16(rtwdev, REG_TRXFF_BNDY + 2, + chip->rxff_size - REPORT_BUF - 1); + + if (chip->id == RTW_CHIP_TYPE_8812A) + rtw_write8(rtwdev, REG_PBP, + u8_encode_bits(PBP_512, PBP_TX_MASK) | + u8_encode_bits(PBP_64, PBP_RX_MASK)); + + rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE); + + rtw_write32(rtwdev, REG_HIMR0, 0); + rtw_write32(rtwdev, REG_HIMR1, 0); + + rtw_write32_mask(rtwdev, REG_CR, 0x30000, 0x2); + + rtw88xxa_init_wmac_setting(rtwdev); + rtw88xxa_init_adaptive_ctrl(rtwdev); + rtw88xxa_init_edca(rtwdev); + + rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7)); + rtw_write8(rtwdev, REG_ACKTO, 0x80); + + rtw88xxau_tx_aggregation(rtwdev); + + rtw88xxa_init_beacon_parameters(rtwdev); + rtw_write8(rtwdev, REG_BCN_MAX_ERR, 0xff); + + rtw_hci_interface_cfg(rtwdev); + + /* usb3 rx interval */ + rtw_write8(rtwdev, REG_USB3_RXITV, 0x01); + + /* burst length=4, set 0x3400 for burst length=2 */ + rtw_write16(rtwdev, REG_RXDMA_STATUS, 0x7400); + rtw_write8(rtwdev, REG_RXDMA_STATUS + 1, 0xf5); + + /* 0x456 = 0x70, sugguested by Zhilin */ + if (chip->id == RTW_CHIP_TYPE_8821A) + rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0x5e); + else + rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0x70); + + rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, 0xffffffff); + rtw_write8(rtwdev, REG_USTIME_TSF, 0x50); + rtw_write8(rtwdev, REG_USTIME_EDCA, 0x50); + + if (rtwusb->udev->speed == USB_SPEED_SUPER) + /* Disable U1/U2 Mode to avoid 2.5G spur in USB3.0. */ + rtw_write8_clr(rtwdev, REG_USB_MOD, BIT(4) | BIT(3)); + + rtw_write8_set(rtwdev, REG_SINGLE_AMPDU_CTRL, BIT_EN_SINGLE_APMDU); + + /* for VHT packet length 11K */ + rtw_write8(rtwdev, REG_RX_PKT_LIMIT, 0x18); + + rtw_write8(rtwdev, REG_PIFS, 0x00); + + if (chip->id == RTW_CHIP_TYPE_8821A) { + /* 0x0a0a too small, it can't pass AC logo. change to 0x1f1f */ + rtw_write16(rtwdev, REG_MAX_AGGR_NUM, 0x1f1f); + rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL, 0x80); + rtw_write32(rtwdev, REG_FAST_EDCA_CTRL, 0x03087777); + } else { + rtw_write16(rtwdev, REG_MAX_AGGR_NUM, 0x1f1f); + rtw_write8_clr(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7)); + } + + /* to prevent mac is reseted by bus. */ + rtw_write8_set(rtwdev, REG_RSV_CTRL, BIT(5) | BIT(6)); + + /* ARFB table 9 for 11ac 5G 2SS */ + rtw_write32(rtwdev, REG_ARFR0, 0x00000010); + rtw_write32(rtwdev, REG_ARFRH0, 0xfffff000); + + /* ARFB table 10 for 11ac 5G 1SS */ + rtw_write32(rtwdev, REG_ARFR1_V1, 0x00000010); + rtw_write32(rtwdev, REG_ARFRH1_V1, 0x003ff000); + + /* ARFB table 11 for 11ac 24G 1SS */ + rtw_write32(rtwdev, REG_ARFR2_V1, 0x00000015); + rtw_write32(rtwdev, REG_ARFRH2_V1, 0x003ff000); + + /* ARFB table 12 for 11ac 24G 2SS */ + rtw_write32(rtwdev, REG_ARFR3_V1, 0x00000015); + rtw_write32(rtwdev, REG_ARFRH3_V1, 0xffcff000); + + rtw_write8_set(rtwdev, REG_CR, BIT_MACTXEN | BIT_MACRXEN); + + rtw88xxa_phy_bb_config(rtwdev); + rtw88xxa_phy_rf_config(rtwdev); + + if (chip->id == RTW_CHIP_TYPE_8812A && hal->rf_path_num == 1) + rtw8812a_config_1t(rtwdev); + + rtw88xxa_switch_band(rtwdev, RTW_BAND_2G, RTW_CHANNEL_WIDTH_20); + + rtw_write32(rtwdev, RTW_SEC_CMD_REG, BIT(31) | BIT(30)); + + rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0xff); + rtw_write32(rtwdev, REG_BAR_MODE_CTRL, 0x0201ffff); + rtw_write8(rtwdev, REG_NAV_CTRL + 2, 0); + + rtw_write8_clr(rtwdev, REG_GPIO_MUXCFG, BIT(5)); + + rtw_phy_init(rtwdev); + + rtw88xxa_pwrtrack_init(rtwdev); + + /* 0x4c6[3] 1: RTS BW = Data BW + * 0: RTS BW depends on CCA / secondary CCA result. + */ + rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT(3)); + + /* enable Tx report. */ + rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, 0x0f); + + /* Pretx_en, for WEP/TKIP SEC */ + rtw_write8(rtwdev, REG_EARLY_MODE_CONTROL + 3, 0x01); + + rtw_write16(rtwdev, REG_TX_RPT_TIME, 0x3df0); + + /* Reset USB mode switch setting */ + rtw_write8(rtwdev, REG_SYS_SDIO_CTRL, 0x0); + rtw_write8(rtwdev, REG_ACLK_MON, 0x0); + + rtw_write8(rtwdev, REG_USB_HRPWM, 0); + + /* ack for xmit mgmt frames. */ + rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(12)); + + hal->cck_high_power = rtw_read32_mask(rtwdev, REG_CCK_RPT_FORMAT, + BIT_CCK_RPT_FORMAT); + + ret = rtw_hci_start(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to start hci\n"); + goto err_off; + } + + if (efuse->btcoex) { + rtw_coex_power_on_setting(rtwdev); + rtw_coex_init_hw_config(rtwdev, false); + } + + set_bit(RTW_FLAG_POWERON, rtwdev->flags); + + return 0; + +err_off: + chip->ops->power_off(rtwdev); + +err: + return ret; +} +EXPORT_SYMBOL(rtw88xxa_power_on); + +u32 rtw88xxa_phy_read_rf(struct rtw_dev *rtwdev, + enum rtw_rf_path rf_path, u32 addr, u32 mask) +{ + static const u32 pi_addr[2] = { REG_3WIRE_SWA, REG_3WIRE_SWB }; + static const u32 read_addr[2][2] = { + { REG_SI_READ_A, REG_SI_READ_B }, + { REG_PI_READ_A, REG_PI_READ_B } + }; + const struct rtw_chip_info *chip = rtwdev->chip; + const struct rtw_hal *hal = &rtwdev->hal; + bool set_cca, pi_mode; + u32 val; + + if (rf_path >= hal->rf_phy_num) { + rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path); + return INV_RF_DATA; + } + + /* CCA off to avoid reading the wrong value. + * Toggling CCA would affect RF 0x0, skip it. + */ + set_cca = addr != 0x0 && chip->id == RTW_CHIP_TYPE_8812A && + hal->cut_version != RTW_CHIP_VER_CUT_C; + + if (set_cca) + rtw_write32_set(rtwdev, REG_CCA2ND, BIT(3)); + + addr &= 0xff; + + pi_mode = rtw_read32_mask(rtwdev, pi_addr[rf_path], 0x4); + + rtw_write32_mask(rtwdev, REG_HSSI_READ, MASKBYTE0, addr); + + if (chip->id == RTW_CHIP_TYPE_8821A || + hal->cut_version == RTW_CHIP_VER_CUT_C) + udelay(20); + + val = rtw_read32_mask(rtwdev, read_addr[pi_mode][rf_path], mask); + + /* CCA on */ + if (set_cca) + rtw_write32_clr(rtwdev, REG_CCA2ND, BIT(3)); + + return val; +} +EXPORT_SYMBOL(rtw88xxa_phy_read_rf); + +static void rtw8812a_phy_fix_spur(struct rtw_dev *rtwdev, u8 channel, u8 bw) +{ + /* C cut Item12 ADC FIFO CLOCK */ + if (rtwdev->hal.cut_version == RTW_CHIP_VER_CUT_C) { + if (bw == RTW_CHANNEL_WIDTH_40 && channel == 11) + rtw_write32_mask(rtwdev, REG_ADCCLK, 0xC00, 0x3); + else + rtw_write32_mask(rtwdev, REG_ADCCLK, 0xC00, 0x2); + + /* A workaround to resolve 2480Mhz spur by setting ADC clock + * as 160M. + */ + if (bw == RTW_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14)) { + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x3); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1); + } else if (bw == RTW_CHANNEL_WIDTH_40 && channel == 11) { + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1); + } else if (bw != RTW_CHANNEL_WIDTH_80) { + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x2); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0); + } + } else { + /* A workaround to resolve 2480Mhz spur by setting ADC clock + * as 160M. + */ + if (bw == RTW_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14)) + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x3); + else if (channel <= 14) /* 2.4G only */ + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x2); + } +} + +static void rtw88xxa_switch_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw) +{ + struct rtw_hal *hal = &rtwdev->hal; + u32 fc_area, rf_mod_ag; + u8 path; + + switch (channel) { + case 36 ... 48: + fc_area = 0x494; + break; + case 50 ... 64: + fc_area = 0x453; + break; + case 100 ... 116: + fc_area = 0x452; + break; + default: + if (channel >= 118) + fc_area = 0x412; + else + fc_area = 0x96a; + break; + } + + rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, fc_area); + + for (path = 0; path < hal->rf_path_num; path++) { + switch (channel) { + case 36 ... 64: + rf_mod_ag = 0x101; + break; + case 100 ... 140: + rf_mod_ag = 0x301; + break; + default: + if (channel > 140) + rf_mod_ag = 0x501; + else + rf_mod_ag = 0x000; + break; + } + + rtw_write_rf(rtwdev, path, RF_CFGCH, + RF18_RFSI_MASK | RF18_BAND_MASK, rf_mod_ag); + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) + rtw8812a_phy_fix_spur(rtwdev, channel, bw); + + rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_CHANNEL_MASK, channel); + } +} + +static void rtw88xxa_set_reg_bw(struct rtw_dev *rtwdev, u8 bw) +{ + u16 val16 = rtw_read16(rtwdev, REG_WMAC_TRXPTCL_CTL); + + val16 &= ~BIT_RFMOD; + if (bw == RTW_CHANNEL_WIDTH_80) + val16 |= BIT_RFMOD_80M; + else if (bw == RTW_CHANNEL_WIDTH_40) + val16 |= BIT_RFMOD_40M; + + rtw_write16(rtwdev, REG_WMAC_TRXPTCL_CTL, val16); +} + +static void rtw88xxa_post_set_bw_mode(struct rtw_dev *rtwdev, u8 channel, + u8 bw, u8 primary_chan_idx) +{ + struct rtw_hal *hal = &rtwdev->hal; + u8 txsc40 = 0, txsc20, txsc; + u8 reg_837, l1pkval; + + rtw88xxa_set_reg_bw(rtwdev, bw); + + txsc20 = primary_chan_idx; + if (bw == RTW_CHANNEL_WIDTH_80) { + if (txsc20 == RTW_SC_20_UPPER || txsc20 == RTW_SC_20_UPMOST) + txsc40 = RTW_SC_40_UPPER; + else + txsc40 = RTW_SC_40_LOWER; + } + + txsc = BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40); + rtw_write8(rtwdev, REG_DATA_SC, txsc); + + reg_837 = rtw_read8(rtwdev, REG_BWINDICATION + 3); + + switch (bw) { + default: + case RTW_CHANNEL_WIDTH_20: + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300200); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0); + + if (hal->rf_type == RF_2T2R) + rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, 7); + else + rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, 8); + + break; + case RTW_CHANNEL_WIDTH_40: + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300201); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0); + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x3C, txsc); + rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf0000000, txsc); + + if (reg_837 & BIT(2)) { + l1pkval = 6; + } else { + if (hal->rf_type == RF_2T2R) + l1pkval = 7; + else + l1pkval = 8; + } + + rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, l1pkval); + + if (txsc == RTW_SC_20_UPPER) + rtw_write32_set(rtwdev, REG_RXSB, BIT(4)); + else + rtw_write32_clr(rtwdev, REG_RXSB, BIT(4)); + + break; + case RTW_CHANNEL_WIDTH_80: + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300202); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1); + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x3C, txsc); + rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf0000000, txsc); + + if (reg_837 & BIT(2)) { + l1pkval = 5; + } else { + if (hal->rf_type == RF_2T2R) + l1pkval = 6; + else + l1pkval = 7; + } + + rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, l1pkval); + + break; + } +} + +static void rtw88xxa_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) +{ + u8 path; + + for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) { + switch (bw) { + case RTW_CHANNEL_WIDTH_5: + case RTW_CHANNEL_WIDTH_10: + case RTW_CHANNEL_WIDTH_20: + default: + rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 3); + break; + case RTW_CHANNEL_WIDTH_40: + rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 1); + break; + case RTW_CHANNEL_WIDTH_80: + rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 0); + break; + } + } +} + +void rtw88xxa_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw, + u8 primary_chan_idx) +{ + u8 old_band, new_band; + + if (rtw_read8(rtwdev, REG_CCK_CHECK) & BIT_CHECK_CCK_EN) + old_band = RTW_BAND_5G; + else + old_band = RTW_BAND_2G; + + if (channel > 14) + new_band = RTW_BAND_5G; + else + new_band = RTW_BAND_2G; + + if (new_band != old_band) + rtw88xxa_switch_band(rtwdev, new_band, bw); + + rtw88xxa_switch_channel(rtwdev, channel, bw); + + rtw88xxa_post_set_bw_mode(rtwdev, channel, bw, primary_chan_idx); + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) + rtw8812a_phy_fix_spur(rtwdev, channel, bw); + + rtw88xxa_set_channel_rf(rtwdev, channel, bw); +} +EXPORT_SYMBOL(rtw88xxa_set_channel); + +void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat, + s8 (*cck_rx_pwr)(u8 lna_idx, u8 vga_idx)) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_jaguar_phy_status_rpt *rpt; + u8 gain[RTW_RF_PATH_MAX], rssi, i; + s8 rx_pwr_db, power_a, power_b; + const s8 min_rx_power = -120; + u8 lna_idx, vga_idx; + + rpt = (struct rtw_jaguar_phy_status_rpt *)phy_status; + + if (pkt_stat->rate <= DESC_RATE11M) { + lna_idx = le32_get_bits(rpt->w1, RTW_JGRPHY_W1_AGC_RPT_LNA_IDX); + vga_idx = le32_get_bits(rpt->w1, RTW_JGRPHY_W1_AGC_RPT_VGA_IDX); + + rx_pwr_db = cck_rx_pwr(lna_idx, vga_idx); + + pkt_stat->rx_power[RF_PATH_A] = rx_pwr_db; + pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1); + dm_info->rssi[RF_PATH_A] = pkt_stat->rssi; + pkt_stat->bw = RTW_CHANNEL_WIDTH_20; + pkt_stat->signal_power = rx_pwr_db; + } else { /* OFDM rate */ + gain[RF_PATH_A] = le32_get_bits(rpt->w0, RTW_JGRPHY_W0_GAIN_A); + gain[RF_PATH_B] = le32_get_bits(rpt->w0, RTW_JGRPHY_W0_GAIN_B); + + for (i = RF_PATH_A; i < rtwdev->hal.rf_path_num; i++) { + pkt_stat->rx_power[i] = gain[i] - 110; + rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[i], 1); + dm_info->rssi[i] = rssi; + } + + pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, + rtwdev->hal.rf_path_num); + + power_a = pkt_stat->rx_power[RF_PATH_A]; + power_b = pkt_stat->rx_power[RF_PATH_B]; + if (rtwdev->hal.rf_path_num == 1) + power_b = power_a; + + pkt_stat->signal_power = max3(power_a, power_b, min_rx_power); + } +} +EXPORT_SYMBOL(rtw88xxa_query_phy_status); + +static void +rtw88xxa_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, + u8 rs, u32 *phy_pwr_idx) +{ + static const u32 offset_txagc[2] = { + REG_TX_AGC_A_CCK_11_CCK_1, REG_TX_AGC_B_CCK_11_CCK_1 + }; + u8 rate, rate_idx, pwr_index, shift; + struct rtw_hal *hal = &rtwdev->hal; + bool write_1ss_mcs9; + u32 mask; + int j; + + for (j = 0; j < rtw_rate_size[rs]; j++) { + rate = rtw_rate_section[rs][j]; + + pwr_index = hal->tx_pwr_tbl[path][rate]; + + shift = rate & 0x3; + *phy_pwr_idx |= ((u32)pwr_index << (shift * 8)); + + write_1ss_mcs9 = rate == DESC_RATEVHT1SS_MCS9 && + hal->rf_path_num == 1; + + if (write_1ss_mcs9) + mask = MASKLWORD; + else + mask = MASKDWORD; + + if (shift == 0x3 || write_1ss_mcs9) { + rate_idx = rate & 0xfc; + if (rate >= DESC_RATEVHT1SS_MCS0) + rate_idx -= 0x10; + + rtw_write32_mask(rtwdev, offset_txagc[path] + rate_idx, + mask, *phy_pwr_idx); + + *phy_pwr_idx = 0; + } + } +} + +static void rtw88xxa_tx_power_training(struct rtw_dev *rtwdev, u8 bw, + u8 channel, u8 path) +{ + static const u32 write_offset[] = { + REG_TX_PWR_TRAINING_A, REG_TX_PWR_TRAINING_B, + }; + u32 power_level, write_data; + u8 i; + + power_level = rtwdev->hal.tx_pwr_tbl[path][DESC_RATEMCS7]; + write_data = 0; + + for (i = 0; i < 3; i++) { + if (i == 0) + power_level -= 10; + else if (i == 1) + power_level -= 8; + else + power_level -= 6; + + write_data |= max_t(u32, power_level, 2) << (i * 8); + } + + rtw_write32_mask(rtwdev, write_offset[path], 0xffffff, write_data); +} + +void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev) +{ + struct rtw_hal *hal = &rtwdev->hal; + u32 phy_pwr_idx = 0; + int rs, path; + + for (path = 0; path < hal->rf_path_num; path++) { + for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) { + if (hal->rf_path_num == 1 && + (rs == RTW_RATE_SECTION_HT_2S || + rs == RTW_RATE_SECTION_VHT_2S)) + continue; + + if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags) && + rs > RTW_RATE_SECTION_OFDM) + continue; + + if (hal->current_band_type == RTW_BAND_5G && + rs == RTW_RATE_SECTION_CCK) + continue; + + rtw88xxa_set_tx_power_index_by_rate(rtwdev, path, rs, + &phy_pwr_idx); + } + + rtw88xxa_tx_power_training(rtwdev, hal->current_band_width, + hal->current_channel, path); + } +} +EXPORT_SYMBOL(rtw88xxa_set_tx_power_index); + +void rtw88xxa_false_alarm_statistics(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u32 cck_fa_cnt, ofdm_fa_cnt; + u32 crc32_cnt, cca32_cnt; + u32 cck_enable; + + cck_enable = rtw_read32(rtwdev, REG_RXPSEL) & BIT(28); + cck_fa_cnt = rtw_read16(rtwdev, REG_FA_CCK); + ofdm_fa_cnt = rtw_read16(rtwdev, REG_FA_OFDM); + + dm_info->cck_fa_cnt = cck_fa_cnt; + dm_info->ofdm_fa_cnt = ofdm_fa_cnt; + dm_info->total_fa_cnt = ofdm_fa_cnt; + if (cck_enable) + dm_info->total_fa_cnt += cck_fa_cnt; + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_CCK); + dm_info->cck_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD); + dm_info->cck_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_OFDM); + dm_info->ofdm_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD); + dm_info->ofdm_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_HT); + dm_info->ht_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD); + dm_info->ht_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_VHT); + dm_info->vht_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD); + dm_info->vht_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD); + + cca32_cnt = rtw_read32(rtwdev, REG_CCA_OFDM); + dm_info->ofdm_cca_cnt = u32_get_bits(cca32_cnt, MASKHWORD); + dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt; + if (cck_enable) { + cca32_cnt = rtw_read32(rtwdev, REG_CCA_CCK); + dm_info->cck_cca_cnt = u32_get_bits(cca32_cnt, MASKLWORD); + dm_info->total_cca_cnt += dm_info->cck_cca_cnt; + } + + rtw_write32_set(rtwdev, REG_FAS, BIT(17)); + rtw_write32_clr(rtwdev, REG_FAS, BIT(17)); + rtw_write32_clr(rtwdev, REG_CCK0_FAREPORT, BIT(15)); + rtw_write32_set(rtwdev, REG_CCK0_FAREPORT, BIT(15)); + rtw_write32_set(rtwdev, REG_CNTRST, BIT(0)); + rtw_write32_clr(rtwdev, REG_CNTRST, BIT(0)); +} +EXPORT_SYMBOL(rtw88xxa_false_alarm_statistics); + +void rtw88xxa_iqk_backup_mac_bb(struct rtw_dev *rtwdev, + u32 *macbb_backup, + const u32 *backup_macbb_reg, + u32 macbb_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* save MACBB default value */ + for (i = 0; i < macbb_num; i++) + macbb_backup[i] = rtw_read32(rtwdev, backup_macbb_reg[i]); +} +EXPORT_SYMBOL(rtw88xxa_iqk_backup_mac_bb); + +void rtw88xxa_iqk_backup_afe(struct rtw_dev *rtwdev, u32 *afe_backup, + const u32 *backup_afe_reg, u32 afe_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Save AFE Parameters */ + for (i = 0; i < afe_num; i++) + afe_backup[i] = rtw_read32(rtwdev, backup_afe_reg[i]); +} +EXPORT_SYMBOL(rtw88xxa_iqk_backup_afe); + +void rtw88xxa_iqk_restore_mac_bb(struct rtw_dev *rtwdev, + u32 *macbb_backup, + const u32 *backup_macbb_reg, + u32 macbb_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Reload MacBB Parameters */ + for (i = 0; i < macbb_num; i++) + rtw_write32(rtwdev, backup_macbb_reg[i], macbb_backup[i]); +} +EXPORT_SYMBOL(rtw88xxa_iqk_restore_mac_bb); + +void rtw88xxa_iqk_configure_mac(struct rtw_dev *rtwdev) +{ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + rtw_write8(rtwdev, REG_TXPAUSE, 0x3f); + rtw_write32_mask(rtwdev, REG_BCN_CTRL, + (BIT_EN_BCN_FUNCTION << 8) | BIT_EN_BCN_FUNCTION, 0x0); + + /* RX ante off */ + rtw_write8(rtwdev, REG_RXPSEL, 0x00); + + /* CCA off */ + rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf, 0xc); + + /* CCK RX path off */ + rtw_write8(rtwdev, REG_CCK_RX + 3, 0xf); +} +EXPORT_SYMBOL(rtw88xxa_iqk_configure_mac); + +bool rtw88xxa_iqk_finish(int average, int threshold, + int *x_temp, int *y_temp, int *x, int *y, + bool break_inner, bool break_outer) +{ + bool finish = false; + int i, ii, dx, dy; + + for (i = 0; i < average; i++) { + for (ii = i + 1; ii < average; ii++) { + dx = abs_diff(x_temp[i] >> 21, x_temp[ii] >> 21); + dy = abs_diff(y_temp[i] >> 21, y_temp[ii] >> 21); + + if (dx < threshold && dy < threshold) { + *x = ((x_temp[i] >> 21) + (x_temp[ii] >> 21)); + *y = ((y_temp[i] >> 21) + (y_temp[ii] >> 21)); + + *x /= 2; + *y /= 2; + + finish = true; + + if (break_inner) + break; + } + } + + if (finish && break_outer) + break; + } + + return finish; +} +EXPORT_SYMBOL(rtw88xxa_iqk_finish); + +static void rtw88xxa_pwrtrack_set(struct rtw_dev *rtwdev, u8 tx_rate, u8 path) +{ + static const u32 reg_txscale[2] = { REG_TXSCALE_A, REG_TXSCALE_B }; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 cck_swing_idx, ofdm_swing_idx; + u8 pwr_tracking_limit; + + switch (tx_rate) { + case DESC_RATE1M ... DESC_RATE11M: + pwr_tracking_limit = 32; + break; + case DESC_RATE6M ... DESC_RATE48M: + case DESC_RATEMCS3 ... DESC_RATEMCS4: + case DESC_RATEMCS11 ... DESC_RATEMCS12: + case DESC_RATEVHT1SS_MCS3 ... DESC_RATEVHT1SS_MCS4: + case DESC_RATEVHT2SS_MCS3 ... DESC_RATEVHT2SS_MCS4: + pwr_tracking_limit = 30; + break; + case DESC_RATE54M: + case DESC_RATEMCS5 ... DESC_RATEMCS7: + case DESC_RATEMCS13 ... DESC_RATEMCS15: + case DESC_RATEVHT1SS_MCS5 ... DESC_RATEVHT1SS_MCS6: + case DESC_RATEVHT2SS_MCS5 ... DESC_RATEVHT2SS_MCS6: + pwr_tracking_limit = 28; + break; + case DESC_RATEMCS0 ... DESC_RATEMCS2: + case DESC_RATEMCS8 ... DESC_RATEMCS10: + case DESC_RATEVHT1SS_MCS0 ... DESC_RATEVHT1SS_MCS2: + case DESC_RATEVHT2SS_MCS0 ... DESC_RATEVHT2SS_MCS2: + pwr_tracking_limit = 34; + break; + case DESC_RATEVHT1SS_MCS7: + case DESC_RATEVHT2SS_MCS7: + pwr_tracking_limit = 26; + break; + default: + case DESC_RATEVHT1SS_MCS8: + case DESC_RATEVHT2SS_MCS8: + pwr_tracking_limit = 24; + break; + case DESC_RATEVHT1SS_MCS9: + case DESC_RATEVHT2SS_MCS9: + pwr_tracking_limit = 22; + break; + } + + cck_swing_idx = dm_info->delta_power_index[path] + dm_info->default_cck_index; + ofdm_swing_idx = dm_info->delta_power_index[path] + dm_info->default_ofdm_index; + + if (ofdm_swing_idx > pwr_tracking_limit) { + if (path == RF_PATH_A) + dm_info->txagc_remnant_cck = cck_swing_idx - pwr_tracking_limit; + dm_info->txagc_remnant_ofdm[path] = ofdm_swing_idx - pwr_tracking_limit; + + ofdm_swing_idx = pwr_tracking_limit; + } else if (ofdm_swing_idx == 0) { + if (path == RF_PATH_A) + dm_info->txagc_remnant_cck = cck_swing_idx; + dm_info->txagc_remnant_ofdm[path] = ofdm_swing_idx; + } else { + if (path == RF_PATH_A) + dm_info->txagc_remnant_cck = 0; + dm_info->txagc_remnant_ofdm[path] = 0; + } + + rtw_write32_mask(rtwdev, reg_txscale[path], GENMASK(31, 21), + rtw88xxa_txscale_tbl[ofdm_swing_idx]); +} + +void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev, + void (*do_lck)(struct rtw_dev *rtwdev), + void (*do_iqk)(struct rtw_dev *rtwdev)) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_hal *hal = &rtwdev->hal; + struct rtw_swing_table swing_table; + s8 remnant_pre[RTW_RF_PATH_MAX]; + u8 thermal_value, delta, path; + bool need_iqk; + + rtw_phy_config_swing_table(rtwdev, &swing_table); + + if (rtwdev->efuse.thermal_meter[0] == 0xff) { + pr_err_once("efuse thermal meter is 0xff\n"); + return; + } + + thermal_value = rtw_read_rf(rtwdev, RF_PATH_A, RF_T_METER, 0xfc00); + + rtw_phy_pwrtrack_avg(rtwdev, thermal_value, RF_PATH_A); + + need_iqk = rtw_phy_pwrtrack_need_iqk(rtwdev); + + if (need_iqk && do_lck) + do_lck(rtwdev); + + if (dm_info->pwr_trk_init_trigger) + dm_info->pwr_trk_init_trigger = false; + else if (!rtw_phy_pwrtrack_thermal_changed(rtwdev, thermal_value, + RF_PATH_A)) + goto iqk; + + delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A); + + for (path = RF_PATH_A; path < hal->rf_path_num; path++) { + remnant_pre[path] = dm_info->txagc_remnant_ofdm[path]; + + dm_info->delta_power_index[path] = + rtw_phy_pwrtrack_get_pwridx(rtwdev, &swing_table, path, + RF_PATH_A, delta); + + if (dm_info->delta_power_index[path] != + dm_info->delta_power_index_last[path]) { + dm_info->delta_power_index_last[path] = + dm_info->delta_power_index[path]; + + rtw88xxa_pwrtrack_set(rtwdev, dm_info->tx_rate, path); + } + } + + for (path = RF_PATH_A; path < hal->rf_path_num; path++) { + if (remnant_pre[path] != dm_info->txagc_remnant_ofdm[path]) { + rtw_phy_set_tx_power_level(rtwdev, + hal->current_channel); + break; + } + } + +iqk: + if (need_iqk) + do_iqk(rtwdev); +} +EXPORT_SYMBOL(rtw88xxa_phy_pwrtrack); + +void rtw88xxa_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl) +{ + static const u8 pd[CCK_PD_LV_MAX] = {0x40, 0x83, 0xcd, 0xdd, 0xed}; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + /* Override rtw_phy_cck_pd_lv_link(). It implements something + * like type 2/3/4. We need type 1 here. + */ + if (rtw_is_assoc(rtwdev)) { + if (dm_info->min_rssi > 60) { + new_lvl = CCK_PD_LV3; + } else if (dm_info->min_rssi > 35) { + new_lvl = CCK_PD_LV2; + } else if (dm_info->min_rssi > 20) { + if (dm_info->cck_fa_avg > 500) + new_lvl = CCK_PD_LV2; + else if (dm_info->cck_fa_avg < 250) + new_lvl = CCK_PD_LV1; + else + return; + } else { + new_lvl = CCK_PD_LV1; + } + } + + rtw_dbg(rtwdev, RTW_DBG_PHY, "lv: (%d) -> (%d)\n", + dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A], new_lvl); + + if (dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] == new_lvl) + return; + + dm_info->cck_fa_avg = CCK_FA_AVG_RESET; + dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] = new_lvl; + + rtw_write8(rtwdev, REG_CCK_PD_TH, pd[new_lvl]); +} +EXPORT_SYMBOL(rtw88xxa_phy_cck_pd_set); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a/8812a common code"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h new file mode 100644 index 000000000000..09a45c1a4129 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW88XXA_H__ +#define __RTW88XXA_H__ + +#include <asm/byteorder.h> +#include "reg.h" + +struct rtw8821au_efuse { + u8 res4[48]; /* 0xd0 */ + u8 vid[2]; /* 0x100 */ + u8 pid[2]; + u8 res8[3]; + u8 mac_addr[ETH_ALEN]; /* 0x107 */ + u8 res9[243]; +} __packed; + +struct rtw8812au_efuse { + u8 vid[2]; /* 0xd0 */ + u8 pid[2]; /* 0xd2 */ + u8 res0[3]; + u8 mac_addr[ETH_ALEN]; /* 0xd7 */ + u8 res1[291]; +} __packed; + +struct rtw88xxa_efuse { + __le16 rtl_id; + u8 res0[6]; /* 0x02 */ + u8 usb_mode; /* 0x08 */ + u8 res1[7]; /* 0x09 */ + + /* power index for four RF paths */ + struct rtw_txpwr_idx txpwr_idx_table[4]; + + u8 channel_plan; /* 0xb8 */ + u8 xtal_k; + u8 thermal_meter; + u8 iqk_lck; + u8 pa_type; /* 0xbc */ + u8 lna_type_2g; /* 0xbd */ + u8 res2; + u8 lna_type_5g; /* 0xbf */ + u8 res3; + u8 rf_board_option; /* 0xc1 */ + u8 rf_feature_option; + u8 rf_bt_setting; + u8 eeprom_version; + u8 eeprom_customer_id; /* 0xc5 */ + u8 tx_bb_swing_setting_2g; + u8 tx_bb_swing_setting_5g; + u8 tx_pwr_calibrate_rate; + u8 rf_antenna_option; /* 0xc9 */ + u8 rfe_option; + u8 country_code[2]; + u8 res4[3]; + union { + struct rtw8821au_efuse rtw8821au; + struct rtw8812au_efuse rtw8812au; + }; +} __packed; + +static_assert(sizeof(struct rtw88xxa_efuse) == 512); + +#define WLAN_BCN_DMA_TIME 0x02 +#define WLAN_TBTT_PROHIBIT 0x04 +#define WLAN_TBTT_HOLD_TIME 0x064 +#define WLAN_TBTT_TIME (WLAN_TBTT_PROHIBIT |\ + (WLAN_TBTT_HOLD_TIME << BIT_SHIFT_TBTT_HOLD_TIME_AP)) + +struct rtw_jaguar_phy_status_rpt { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; +} __packed; + +#define RTW_JGRPHY_W0_GAIN_A GENMASK(6, 0) +#define RTW_JGRPHY_W0_TRSW_A BIT(7) +#define RTW_JGRPHY_W0_GAIN_B GENMASK(14, 8) +#define RTW_JGRPHY_W0_TRSW_B BIT(15) +#define RTW_JGRPHY_W0_CHL_NUM GENMASK(25, 16) +#define RTW_JGRPHY_W0_SUB_CHNL GENMASK(29, 26) +#define RTW_JGRPHY_W0_R_RFMOD GENMASK(31, 30) + +/* CCK: */ +#define RTW_JGRPHY_W1_SIG_QUAL GENMASK(7, 0) +#define RTW_JGRPHY_W1_AGC_RPT_VGA_IDX GENMASK(12, 8) +#define RTW_JGRPHY_W1_AGC_RPT_LNA_IDX GENMASK(15, 13) +#define RTW_JGRPHY_W1_BB_POWER GENMASK(23, 16) +/* OFDM: */ +#define RTW_JGRPHY_W1_PWDB_ALL GENMASK(7, 0) +#define RTW_JGRPHY_W1_CFO_SHORT_A GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W1_CFO_SHORT_B GENMASK(23, 16) /* s8 */ +#define RTW_JGRPHY_W1_BT_RF_CH_MSB GENMASK(31, 30) + +#define RTW_JGRPHY_W2_ANT_DIV_SW_A BIT(0) +#define RTW_JGRPHY_W2_ANT_DIV_SW_B BIT(1) +#define RTW_JGRPHY_W2_BT_RF_CH_LSB GENMASK(7, 2) +#define RTW_JGRPHY_W2_CFO_TAIL_A GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W2_CFO_TAIL_B GENMASK(23, 16) /* s8 */ +#define RTW_JGRPHY_W2_PCTS_MSK_RPT_0 GENMASK(31, 24) + +#define RTW_JGRPHY_W3_PCTS_MSK_RPT_1 GENMASK(7, 0) +/* Stream 1 and 2 RX EVM: */ +#define RTW_JGRPHY_W3_RXEVM_1 GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W3_RXEVM_2 GENMASK(23, 16) /* s8 */ +#define RTW_JGRPHY_W3_RXSNR_A GENMASK(31, 24) /* s8 */ + +#define RTW_JGRPHY_W4_RXSNR_B GENMASK(7, 0) /* s8 */ +#define RTW_JGRPHY_W4_PCTS_MSK_RPT_2 GENMASK(21, 8) +#define RTW_JGRPHY_W4_PCTS_RPT_VALID BIT(22) +#define RTW_JGRPHY_W4_RXEVM_3 GENMASK(31, 24) /* s8 */ + +#define RTW_JGRPHY_W5_RXEVM_4 GENMASK(7, 0) /* s8 */ +/* 8812a, stream 1 and 2 CSI: */ +#define RTW_JGRPHY_W5_CSI_CURRENT_1 GENMASK(15, 8) +#define RTW_JGRPHY_W5_CSI_CURRENT_2 GENMASK(23, 16) +/* 8814a: */ +#define RTW_JGRPHY_W5_RXSNR_C GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W5_RXSNR_D GENMASK(23, 16) /* s8 */ +#define RTW_JGRPHY_W5_GAIN_C GENMASK(30, 24) +#define RTW_JGRPHY_W5_TRSW_C BIT(31) + +#define RTW_JGRPHY_W6_GAIN_D GENMASK(6, 0) +#define RTW_JGRPHY_W6_TRSW_D BIT(7) +#define RTW_JGRPHY_W6_SIGEVM GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W6_ANTIDX_ANTC GENMASK(18, 16) +#define RTW_JGRPHY_W6_ANTIDX_ANTD GENMASK(21, 19) +#define RTW_JGRPHY_W6_DPDT_CTRL_KEEP BIT(22) +#define RTW_JGRPHY_W6_GNT_BT_KEEP BIT(23) +#define RTW_JGRPHY_W6_ANTIDX_ANTA GENMASK(26, 24) +#define RTW_JGRPHY_W6_ANTIDX_ANTB GENMASK(29, 27) +#define RTW_JGRPHY_W6_HW_ANTSW_OCCUR GENMASK(31, 30) + +#define RF18_BW_MASK (BIT(11) | BIT(10)) + +void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on); +int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map); +void rtw88xxa_power_off(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd *const *enter_lps_flow); +int rtw88xxa_power_on(struct rtw_dev *rtwdev); +u32 rtw88xxa_phy_read_rf(struct rtw_dev *rtwdev, + enum rtw_rf_path rf_path, u32 addr, u32 mask); +void rtw88xxa_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw, + u8 primary_chan_idx); +void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat, + s8 (*cck_rx_pwr)(u8 lna_idx, u8 vga_idx)); +void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev); +void rtw88xxa_false_alarm_statistics(struct rtw_dev *rtwdev); +void rtw88xxa_iqk_backup_mac_bb(struct rtw_dev *rtwdev, + u32 *macbb_backup, + const u32 *backup_macbb_reg, + u32 macbb_num); +void rtw88xxa_iqk_backup_afe(struct rtw_dev *rtwdev, u32 *afe_backup, + const u32 *backup_afe_reg, u32 afe_num); +void rtw88xxa_iqk_restore_mac_bb(struct rtw_dev *rtwdev, + u32 *macbb_backup, + const u32 *backup_macbb_reg, + u32 macbb_num); +void rtw88xxa_iqk_configure_mac(struct rtw_dev *rtwdev); +bool rtw88xxa_iqk_finish(int average, int threshold, + int *x_temp, int *y_temp, int *x, int *y, + bool break_inner, bool break_outer); +void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev, + void (*do_lck)(struct rtw_dev *rtwdev), + void (*do_iqk)(struct rtw_dev *rtwdev)); +void rtw88xxa_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl); + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c index 66f9419588cf..90fc8a5fa89e 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -187,11 +187,10 @@ fill_rx_status: } EXPORT_SYMBOL(rtw_update_rx_freq_from_ie); -void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *rx_status, - u8 *phy_status) +static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rx_status) { struct ieee80211_hw *hw = rtwdev->hw; u8 path; @@ -235,12 +234,75 @@ void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, else rx_status->bw = RATE_INFO_BW_20; - rx_status->signal = pkt_stat->signal_power; - for (path = 0; path < rtwdev->hal.rf_path_num; path++) { - rx_status->chains |= BIT(path); - rx_status->chain_signal[path] = pkt_stat->rx_power[path]; + if (pkt_stat->phy_status) { + rx_status->signal = pkt_stat->signal_power; + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { + rx_status->chains |= BIT(path); + rx_status->chain_signal[path] = pkt_stat->rx_power[path]; + } + } else { + rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; } rtw_rx_addr_match(rtwdev, pkt_stat, hdr); + + /* Rtl8723cs driver checks for size < 14 or size > 8192 and + * simply drops the packet. + */ + if (rtwdev->chip->id == RTW_CHIP_TYPE_8703B && pkt_stat->pkt_len == 0) { + rx_status->flag |= RX_FLAG_NO_PSDU; + rtw_dbg(rtwdev, RTW_DBG_RX, "zero length packet"); + } +} + +void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_rx_status *rx_status) +{ + u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; + struct rtw_rx_desc *rx_desc = rx_desc8; + struct ieee80211_hdr *hdr; + u32 enc_type, swdec; + void *phy_status; + + memset(pkt_stat, 0, sizeof(*pkt_stat)); + + pkt_stat->pkt_len = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_PKT_LEN); + pkt_stat->crc_err = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_CRC32); + pkt_stat->icv_err = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_ICV_ERR); + pkt_stat->drv_info_sz = le32_get_bits(rx_desc->w0, + RTW_RX_DESC_W0_DRV_INFO_SIZE); + enc_type = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_ENC_TYPE); + pkt_stat->shift = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_SHIFT); + pkt_stat->phy_status = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_PHYST); + swdec = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_SWDEC); + pkt_stat->decrypted = !swdec && enc_type != RX_DESC_ENC_NONE; + + pkt_stat->cam_id = le32_get_bits(rx_desc->w1, RTW_RX_DESC_W1_MACID); + + pkt_stat->is_c2h = le32_get_bits(rx_desc->w2, RTW_RX_DESC_W2_C2H); + pkt_stat->ppdu_cnt = le32_get_bits(rx_desc->w2, RTW_RX_DESC_W2_PPDU_CNT); + + pkt_stat->rate = le32_get_bits(rx_desc->w3, RTW_RX_DESC_W3_RX_RATE); + + pkt_stat->bw = le32_get_bits(rx_desc->w4, RTW_RX_DESC_W4_BW); + + pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL); + + /* drv_info_sz is in unit of 8-bytes */ + pkt_stat->drv_info_sz *= 8; + + /* c2h cmd pkt's rx/phy status is not interested */ + if (pkt_stat->is_c2h) + return; + + phy_status = rx_desc8 + desc_sz + pkt_stat->shift; + hdr = phy_status + pkt_stat->drv_info_sz; + pkt_stat->hdr = hdr; + + if (pkt_stat->phy_status) + rtwdev->chip->ops->query_phy_status(rtwdev, phy_status, pkt_stat); + + rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status); } -EXPORT_SYMBOL(rtw_rx_fill_rx_status); +EXPORT_SYMBOL(rtw_rx_query_rx_desc); diff --git a/drivers/net/wireless/realtek/rtw88/rx.h b/drivers/net/wireless/realtek/rtw88/rx.h index 9f0019112987..6b7dee245c0a 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.h +++ b/drivers/net/wireless/realtek/rtw88/rx.h @@ -14,42 +14,40 @@ enum rtw_rx_desc_enc { RX_DESC_ENC_WEP104 = 5, }; -#define GET_RX_DESC_PHYST(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(26)) -#define GET_RX_DESC_ICV_ERR(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(15)) -#define GET_RX_DESC_CRC32(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(14)) -#define GET_RX_DESC_SWDEC(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(27)) -#define GET_RX_DESC_C2H(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x02), BIT(28)) -#define GET_RX_DESC_PKT_LEN(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(13, 0)) -#define GET_RX_DESC_DRV_INFO_SIZE(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(19, 16)) -#define GET_RX_DESC_SHIFT(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(25, 24)) -#define GET_RX_DESC_ENC_TYPE(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(22, 20)) -#define GET_RX_DESC_RX_RATE(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x03), GENMASK(6, 0)) -#define GET_RX_DESC_MACID(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x01), GENMASK(6, 0)) -#define GET_RX_DESC_PPDU_CNT(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x02), GENMASK(30, 29)) -#define GET_RX_DESC_TSFL(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x05), GENMASK(31, 0)) -#define GET_RX_DESC_BW(rxdesc) \ - (le32_get_bits(*((__le32 *)(rxdesc) + 0x04), GENMASK(5, 4))) +struct rtw_rx_desc { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; +} __packed; + +#define RTW_RX_DESC_W0_PKT_LEN GENMASK(13, 0) +#define RTW_RX_DESC_W0_CRC32 BIT(14) +#define RTW_RX_DESC_W0_ICV_ERR BIT(15) +#define RTW_RX_DESC_W0_DRV_INFO_SIZE GENMASK(19, 16) +#define RTW_RX_DESC_W0_ENC_TYPE GENMASK(22, 20) +#define RTW_RX_DESC_W0_SHIFT GENMASK(25, 24) +#define RTW_RX_DESC_W0_PHYST BIT(26) +#define RTW_RX_DESC_W0_SWDEC BIT(27) + +#define RTW_RX_DESC_W1_MACID GENMASK(6, 0) + +#define RTW_RX_DESC_W2_C2H BIT(28) +#define RTW_RX_DESC_W2_PPDU_CNT GENMASK(30, 29) + +#define RTW_RX_DESC_W3_RX_RATE GENMASK(6, 0) + +#define RTW_RX_DESC_W4_BW GENMASK(5, 4) + +#define RTW_RX_DESC_W5_TSFL GENMASK(31, 0) void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, struct sk_buff *skb); -void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *rx_status, - u8 *phy_status); +void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_rx_status *rx_status); void rtw_update_rx_freq_from_ie(struct rtw_dev *rtwdev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status, struct rtw_rx_pkt_stat *pkt_stat); diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index 21d0754dd7f6..799230eb5f16 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -864,7 +864,7 @@ static void rtw_sdio_tx_skb_prepare(struct rtw_dev *rtwdev, pkt_info->qsel = rtw_sdio_get_tx_qsel(rtwdev, skb, queue); - rtw_tx_fill_tx_desc(pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb); rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, pkt_desc); } @@ -981,8 +981,7 @@ static void rtw_sdio_rxfifo_recv(struct rtw_dev *rtwdev, u32 rx_len) while (true) { rx_desc = skb->data; - chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, - &rx_status); + rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status); pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + pkt_stat.shift; @@ -1297,12 +1296,12 @@ static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev) struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; int i; - for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) - skb_queue_purge(&rtwsdio->tx_queue[i]); - flush_workqueue(rtwsdio->txwq); destroy_workqueue(rtwsdio->txwq); kfree(rtwsdio->tx_handler_data); + + for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) + ieee80211_purge_tx_queue(rtwdev->hw, &rtwsdio->tx_queue[i]); } int rtw_sdio_probe(struct sdio_func *sdio_func, diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index dae7ca148865..6ed470dd6f22 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -32,7 +32,8 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, } } -void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) +void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) { struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; bool more_data = false; @@ -67,6 +68,9 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) tx_desc->w4 = le32_encode_bits(pkt_info->rate, RTW_TX_DESC_W4_DATARATE); + if (rtwdev->chip->old_datarate_fb_limit) + tx_desc->w4 |= le32_encode_bits(0x1f, RTW_TX_DESC_W4_DATARATE_FB_LIMIT); + tx_desc->w5 = le32_encode_bits(pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) | le32_encode_bits(pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) | le32_encode_bits(pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) | diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 3d544fd7f60f..d34cdeca16f1 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -44,6 +44,7 @@ struct rtw_tx_desc { #define RTW_TX_DESC_W3_NAVUSEHDR BIT(15) #define RTW_TX_DESC_W3_MAX_AGG_NUM GENMASK(21, 17) #define RTW_TX_DESC_W4_DATARATE GENMASK(6, 0) +#define RTW_TX_DESC_W4_DATARATE_FB_LIMIT GENMASK(12, 8) #define RTW_TX_DESC_W4_RTSRATE GENMASK(28, 24) #define RTW_TX_DESC_W5_DATA_SHORT BIT(4) #define RTW_TX_DESC_W5_DATA_BW GENMASK(6, 5) @@ -94,7 +95,8 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, struct ieee80211_sta *sta, struct sk_buff *skb); -void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb); +void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb); void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn); void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src); void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index b17a429bcd29..8d6db68246f1 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -423,10 +423,11 @@ static void rtw_usb_tx_handler(struct work_struct *work) static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb) { + struct rtw_dev *rtwdev = rtwusb->rtwdev; int i; for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) - skb_queue_purge(&rtwusb->tx_queue[i]); + ieee80211_purge_tx_queue(rtwdev->hw, &rtwusb->tx_queue[i]); } static void rtw_usb_write_port_complete(struct urb *urb) @@ -457,7 +458,7 @@ static int rtw_usb_write_data(struct rtw_dev *rtwdev, skb_put_data(skb, buf, size); skb_push(skb, chip->tx_pkt_desc_sz); memset(skb->data, 0, chip->tx_pkt_desc_sz); - rtw_tx_fill_tx_desc(pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb); rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); ret = rtw_usb_write_port(rtwdev, qsel, skb, @@ -477,6 +478,7 @@ static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, pkt_info.tx_pkt_size = size; pkt_info.qsel = TX_DESC_QSEL_BEACON; pkt_info.offset = chip->tx_pkt_desc_sz; + pkt_info.ls = true; return rtw_usb_write_data(rtwdev, &pkt_info, buf); } @@ -524,7 +526,7 @@ static int rtw_usb_tx_write(struct rtw_dev *rtwdev, pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, chip->tx_pkt_desc_sz); ep = qsel_to_ep(rtwusb, pkt_info->qsel); - rtw_tx_fill_tx_desc(pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb); rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); tx_data = rtw_usb_get_tx_data(skb); tx_data->sn = pkt_info->sn; @@ -570,8 +572,8 @@ static void rtw_usb_rx_handler(struct work_struct *work) do { rx_desc = skb->data; - chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, - &rx_status); + rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, + &rx_status); pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + pkt_stat.shift; @@ -888,9 +890,9 @@ static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev) { struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); - rtw_usb_tx_queue_purge(rtwusb); flush_workqueue(rtwusb->txwq); destroy_workqueue(rtwusb->txwq); + rtw_usb_tx_queue_purge(rtwusb); } static int rtw_usb_intf_init(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index 4476fc7e53db..8ef59994c0db 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -211,25 +211,17 @@ static int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam, return 0; } -static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - const struct rtw89_sec_cam_entry *sec_cam, - bool inform_fw) +static int __rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + const struct rtw89_sec_cam_entry *sec_cam, + bool inform_fw) { - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); - struct rtw89_vif *rtwvif; struct rtw89_addr_cam_entry *addr_cam; unsigned int i; int ret = 0; - if (!vif) { - rtw89_err(rtwdev, "No iface for deleting sec cam\n"); - return -EINVAL; - } - - rtwvif = (struct rtw89_vif *)vif->drv_priv; - addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + addr_cam = rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); for_each_set_bit(i, addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM) { if (addr_cam->sec_ent[i] != sec_cam->sec_cam_idx) @@ -239,11 +231,11 @@ static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, } if (inform_fw) { - ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link); if (ret) rtw89_err(rtwdev, "failed to update dctl cam del key: %d\n", ret); - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret); } @@ -251,25 +243,17 @@ static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, return ret; } -static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - struct rtw89_sec_cam_entry *sec_cam) +static int __rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct ieee80211_key_conf *key, + struct rtw89_sec_cam_entry *sec_cam) { - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); - struct rtw89_vif *rtwvif; struct rtw89_addr_cam_entry *addr_cam; u8 key_idx = 0; int ret; - if (!vif) { - rtw89_err(rtwdev, "No iface for adding sec cam\n"); - return -EINVAL; - } - - rtwvif = (struct rtw89_vif *)vif->drv_priv; - addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + addr_cam = rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || key->cipher == WLAN_CIPHER_SUITE_WEP104) @@ -285,13 +269,13 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, addr_cam->sec_ent_keyid[key_idx] = key->keyidx; addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx; set_bit(key_idx, addr_cam->sec_cam_map); - ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n", ret); return ret; } - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n", ret); @@ -302,6 +286,92 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, return 0; } +static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + const struct rtw89_sec_cam_entry *sec_cam, + bool inform_fw) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_sta_link *rtwsta_link; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + int ret; + + if (!vif) { + rtw89_err(rtwdev, "No iface for deleting sec cam\n"); + return -EINVAL; + } + + rtwvif = vif_to_rtwvif(vif); + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + rtwsta_link = rtwsta ? rtwsta->links[link_id] : NULL; + if (rtwsta && !rtwsta_link) + continue; + + ret = __rtw89_cam_detach_sec_cam(rtwdev, rtwvif_link, rtwsta_link, + sec_cam, inform_fw); + if (ret) + return ret; + } + + return 0; +} + +static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + struct rtw89_sec_cam_entry *sec_cam) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_sta_link *rtwsta_link; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + int key_link_id; + int ret; + + if (!vif) { + rtw89_err(rtwdev, "No iface for adding sec cam\n"); + return -EINVAL; + } + + rtwvif = vif_to_rtwvif(vif); + + key_link_id = ieee80211_vif_is_mld(vif) ? key->link_id : 0; + if (key_link_id >= 0) { + rtwvif_link = rtwvif->links[key_link_id]; + rtwsta_link = rtwsta ? rtwsta->links[key_link_id] : NULL; + + if (!rtwvif_link || (rtwsta && !rtwsta_link)) { + rtw89_err(rtwdev, "No drv link for adding sec cam\n"); + return -ENOLINK; + } + + return __rtw89_cam_attach_sec_cam(rtwdev, rtwvif_link, + rtwsta_link, key, sec_cam); + } + + /* key_link_id < 0: MLD pairwise key */ + if (!rtwsta) { + rtw89_err(rtwdev, "No sta for adding MLD pairwise sec cam\n"); + return -EINVAL; + } + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = __rtw89_cam_attach_sec_cam(rtwdev, rtwvif_link, + rtwsta_link, key, sec_cam); + if (ret) + return ret; + } + + return 0; +} + static int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -485,10 +555,10 @@ void rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev, clear_bit(bssid_cam->bssid_cam_idx, cam_info->bssid_cam_map); } -void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam; - struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; + struct rtw89_addr_cam_entry *addr_cam = &rtwvif_link->addr_cam; + struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam; rtw89_cam_deinit_addr_cam(rtwdev, addr_cam); rtw89_cam_deinit_bssid_cam(rtwdev, bssid_cam); @@ -593,7 +663,7 @@ static int rtw89_cam_get_avail_bssid_cam(struct rtw89_dev *rtwdev, } int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct rtw89_bssid_cam_entry *bssid_cam, const u8 *bssid) { @@ -613,7 +683,7 @@ int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, } bssid_cam->bssid_cam_idx = bssid_cam_idx; - bssid_cam->phy_idx = rtwvif->phy_idx; + bssid_cam->phy_idx = rtwvif_link->phy_idx; bssid_cam->len = BSSID_CAM_ENT_SIZE; bssid_cam->offset = 0; bssid_cam->valid = true; @@ -622,20 +692,21 @@ int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, return 0; } -void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; + struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam; - ether_addr_copy(bssid_cam->bssid, rtwvif->bssid); + ether_addr_copy(bssid_cam->bssid, rtwvif_link->bssid); } -int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam; - struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; + struct rtw89_addr_cam_entry *addr_cam = &rtwvif_link->addr_cam; + struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam; int ret; - ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, rtwvif->bssid); + ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif_link, bssid_cam, + rtwvif_link->bssid); if (ret) { rtw89_err(rtwdev, "failed to init bssid cam\n"); return ret; @@ -651,19 +722,27 @@ int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) } int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, u8 *cmd) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, u8 *cmd) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta); - u8 bss_color = vif->bss_conf.he_bss_color.color; + struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif_link, + rtwsta_link); + struct ieee80211_bss_conf *bss_conf; + u8 bss_color; u8 bss_mask; - if (vif->bss_conf.nontransmitted) + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + bss_color = bss_conf->he_bss_color.color; + + if (bss_conf->nontransmitted) bss_mask = RTW89_BSSID_MATCH_5_BYTES; else bss_mask = RTW89_BSSID_MATCH_ALL; + rcu_read_unlock(); + FWCMD_SET_ADDR_BSSID_IDX(cmd, bssid_cam->bssid_cam_idx); FWCMD_SET_ADDR_BSSID_OFFSET(cmd, bssid_cam->offset); FWCMD_SET_ADDR_BSSID_LEN(cmd, bssid_cam->len); @@ -694,19 +773,30 @@ static u8 rtw89_cam_addr_hash(u8 start, const u8 *addr) } void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr, u8 *cmd) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); - struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta); - const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif->mac_addr; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_addr_cam_entry *addr_cam = + rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); + struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link); + struct ieee80211_link_sta *link_sta; + const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif_link->mac_addr; u8 sma_hash, tma_hash, addr_msk_start; u8 sma_start = 0; u8 tma_start = 0; - u8 *tma = sta ? sta->addr : rtwvif->bssid; + const u8 *tma; + + rcu_read_lock(); + + if (sta) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + tma = link_sta->addr; + } else { + tma = rtwvif_link->bssid; + } if (addr_cam->addr_mask != 0) { addr_msk_start = __ffs(addr_cam->addr_mask); @@ -723,10 +813,10 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_LEN(cmd, addr_cam->len); FWCMD_SET_ADDR_VALID(cmd, addr_cam->valid); - FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif->net_type); - FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif->bcn_hit_cond); - FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif->hit_rule); - FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif->phy_idx); + FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif_link->net_type); + FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif_link->bcn_hit_cond); + FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif_link->hit_rule); + FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif_link->phy_idx); FWCMD_SET_ADDR_ADDR_MASK(cmd, addr_cam->addr_mask); FWCMD_SET_ADDR_MASK_SEL(cmd, addr_cam->mask_sel); FWCMD_SET_ADDR_SMA_HASH(cmd, sma_hash); @@ -748,20 +838,21 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_TMA4(cmd, tma[4]); FWCMD_SET_ADDR_TMA5(cmd, tma[5]); - FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif->port); - FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif->port); - FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif->trigger); - FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif->lsig_txop); - FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif->tgt_ind); - FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind); - FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id); - if (rtwvif->net_type == RTW89_NET_TYPE_INFRA) + FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif_link->port); + FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif_link->port); + FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif_link->trigger); + FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif_link->lsig_txop); + FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif_link->tgt_ind); + FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif_link->frm_tgt_ind); + FWCMD_SET_ADDR_MACID(cmd, rtwsta_link ? rtwsta_link->mac_id : + rtwvif_link->mac_id); + if (rtwvif_link->net_type == RTW89_NET_TYPE_INFRA) FWCMD_SET_ADDR_AID12(cmd, vif->cfg.aid & 0xfff); - else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + else if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0); - FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern); - FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif->wowlan_uc); - FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif->wowlan_magic); + FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif_link->wowlan_pattern); + FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif_link->wowlan_uc); + FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif_link->wowlan_magic); FWCMD_SET_ADDR_WAPI(cmd, addr_cam->wapi); FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, addr_cam->sec_ent_mode); FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, addr_cam->sec_ent_keyid[0]); @@ -780,18 +871,22 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_SEC_ENT4(cmd, addr_cam->sec_ent[4]); FWCMD_SET_ADDR_SEC_ENT5(cmd, addr_cam->sec_ent[5]); FWCMD_SET_ADDR_SEC_ENT6(cmd, addr_cam->sec_ent[6]); + + rcu_read_unlock(); } void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v1 *h2c) { - struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + struct rtw89_addr_cam_entry *addr_cam = + rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv; - h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id, + h2c->c0 = le32_encode_bits(rtwsta_link ? rtwsta_link->mac_id : + rtwvif_link->mac_id, DCTLINFO_V1_C0_MACID) | le32_encode_bits(1, DCTLINFO_V1_C0_OP); @@ -862,18 +957,28 @@ void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, } void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v2 *h2c) { - struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link); + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif_link->rtwvif); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_addr_cam_entry *addr_cam = + rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); + bool is_mld = sta ? sta->mlo : ieee80211_vif_is_mld(vif); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv; + u8 *mld_sma, *mld_tma, *mld_bssid; - h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id, + h2c->c0 = le32_encode_bits(rtwsta_link ? rtwsta_link->mac_id : + rtwvif_link->mac_id, DCTLINFO_V2_C0_MACID) | le32_encode_bits(1, DCTLINFO_V2_C0_OP); + h2c->w2 = le32_encode_bits(is_mld, DCTLINFO_V2_W2_IS_MLD); + h2c->m2 = cpu_to_le32(DCTLINFO_V2_W2_IS_MLD); + h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0], DCTLINFO_V2_W4_SEC_ENT0_KEYID) | le32_encode_bits(addr_cam->sec_ent_keyid[1], @@ -939,4 +1044,47 @@ void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, DCTLINFO_V2_W4_SEC_KEY_ID); h2c->m4 |= cpu_to_le32(DCTLINFO_V2_W4_SEC_KEY_ID); } + + if (!is_mld) + return; + + if (rtwvif_link->net_type == RTW89_NET_TYPE_INFRA) { + mld_sma = rtwvif->mac_addr; + mld_tma = vif->cfg.ap_addr; + mld_bssid = vif->cfg.ap_addr; + } else if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE && sta) { + mld_sma = rtwvif->mac_addr; + mld_tma = sta->addr; + mld_bssid = rtwvif->mac_addr; + } else { + return; + } + + h2c->w8 = le32_encode_bits(mld_sma[0], DCTLINFO_V2_W8_MLD_SMA_0) | + le32_encode_bits(mld_sma[1], DCTLINFO_V2_W8_MLD_SMA_1) | + le32_encode_bits(mld_sma[2], DCTLINFO_V2_W8_MLD_SMA_2) | + le32_encode_bits(mld_sma[3], DCTLINFO_V2_W8_MLD_SMA_3); + h2c->m8 = cpu_to_le32(DCTLINFO_V2_W8_ALL); + + h2c->w9 = le32_encode_bits(mld_sma[4], DCTLINFO_V2_W9_MLD_SMA_4) | + le32_encode_bits(mld_sma[5], DCTLINFO_V2_W9_MLD_SMA_5) | + le32_encode_bits(mld_tma[0], DCTLINFO_V2_W9_MLD_TMA_0) | + le32_encode_bits(mld_tma[1], DCTLINFO_V2_W9_MLD_TMA_1); + h2c->m9 = cpu_to_le32(DCTLINFO_V2_W9_ALL); + + h2c->w10 = le32_encode_bits(mld_tma[2], DCTLINFO_V2_W10_MLD_TMA_2) | + le32_encode_bits(mld_tma[3], DCTLINFO_V2_W10_MLD_TMA_3) | + le32_encode_bits(mld_tma[4], DCTLINFO_V2_W10_MLD_TMA_4) | + le32_encode_bits(mld_tma[5], DCTLINFO_V2_W10_MLD_TMA_5); + h2c->m10 = cpu_to_le32(DCTLINFO_V2_W10_ALL); + + h2c->w11 = le32_encode_bits(mld_bssid[0], DCTLINFO_V2_W11_MLD_BSSID_0) | + le32_encode_bits(mld_bssid[1], DCTLINFO_V2_W11_MLD_BSSID_1) | + le32_encode_bits(mld_bssid[2], DCTLINFO_V2_W11_MLD_BSSID_2) | + le32_encode_bits(mld_bssid[3], DCTLINFO_V2_W11_MLD_BSSID_3); + h2c->m11 = cpu_to_le32(DCTLINFO_V2_W11_ALL); + + h2c->w12 = le32_encode_bits(mld_bssid[4], DCTLINFO_V2_W12_MLD_BSSID_4) | + le32_encode_bits(mld_bssid[5], DCTLINFO_V2_W12_MLD_BSSID_5); + h2c->m12 = cpu_to_le32(DCTLINFO_V2_W12_ALL); } diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h index 5d7b624c2dd4..3134ebf08825 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.h +++ b/drivers/net/wireless/realtek/rtw89/cam.h @@ -514,46 +514,58 @@ struct rtw89_h2c_dctlinfo_ud_v2 { #define DCTLINFO_V2_W7_SEC_ENT7 GENMASK(23, 16) #define DCTLINFO_V2_W7_SEC_ENT8 GENMASK(31, 24) #define DCTLINFO_V2_W7_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W8_MLD_SMA_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W8_MLD_SMA_0 GENMASK(7, 0) +#define DCTLINFO_V2_W8_MLD_SMA_1 GENMASK(15, 8) +#define DCTLINFO_V2_W8_MLD_SMA_2 GENMASK(23, 16) +#define DCTLINFO_V2_W8_MLD_SMA_3 GENMASK(31, 24) #define DCTLINFO_V2_W8_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W9_MLD_SMA_H_V1 GENMASK(15, 0) -#define DCTLINFO_V2_W9_MLD_TMA_L_V1 GENMASK(31, 16) +#define DCTLINFO_V2_W9_MLD_SMA_4 GENMASK(7, 0) +#define DCTLINFO_V2_W9_MLD_SMA_5 GENMASK(15, 8) +#define DCTLINFO_V2_W9_MLD_TMA_0 GENMASK(23, 16) +#define DCTLINFO_V2_W9_MLD_TMA_1 GENMASK(31, 24) #define DCTLINFO_V2_W9_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W10_MLD_TMA_H_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W10_MLD_TMA_2 GENMASK(7, 0) +#define DCTLINFO_V2_W10_MLD_TMA_3 GENMASK(15, 8) +#define DCTLINFO_V2_W10_MLD_TMA_4 GENMASK(23, 16) +#define DCTLINFO_V2_W10_MLD_TMA_5 GENMASK(31, 24) #define DCTLINFO_V2_W10_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W11_MLD_TA_BSSID_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W11_MLD_BSSID_0 GENMASK(7, 0) +#define DCTLINFO_V2_W11_MLD_BSSID_1 GENMASK(15, 8) +#define DCTLINFO_V2_W11_MLD_BSSID_2 GENMASK(23, 16) +#define DCTLINFO_V2_W11_MLD_BSSID_3 GENMASK(31, 24) #define DCTLINFO_V2_W11_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W12_MLD_TA_BSSID_H_V1 GENMASK(15, 0) +#define DCTLINFO_V2_W12_MLD_BSSID_4 GENMASK(7, 0) +#define DCTLINFO_V2_W12_MLD_BSSID_5 GENMASK(15, 8) #define DCTLINFO_V2_W12_ALL GENMASK(15, 0) -int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); -void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); +int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); +void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, struct rtw89_addr_cam_entry *addr_cam, const struct rtw89_bssid_cam_entry *bssid_cam); void rtw89_cam_deinit_addr_cam(struct rtw89_dev *rtwdev, struct rtw89_addr_cam_entry *addr_cam); int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct rtw89_bssid_cam_entry *bssid_cam, const u8 *bssid); void rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev, struct rtw89_bssid_cam_entry *bssid_cam); void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *vif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *vif, + struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr, u8 *cmd); void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v1 *h2c); void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v2 *h2c); int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, u8 *cmd); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, u8 *cmd); int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -564,6 +576,6 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, struct ieee80211_key_conf *key, bool inform_fw); void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); void rtw89_cam_reset_keys(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 7070c85e2c28..fb9449930c40 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -10,6 +10,10 @@ #include "ps.h" #include "util.h" +static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx idx1, + enum rtw89_chanctx_idx idx2); + static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band, u8 center_chan) { @@ -226,14 +230,30 @@ static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev) void rtw89_entity_init(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; hal->entity_pause = false; bitmap_zero(hal->entity_map, NUM_OF_RTW89_CHANCTX); bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); atomic_set(&hal->roc_chanctx_idx, RTW89_CHANCTX_IDLE); + + INIT_LIST_HEAD(&mgnt->active_list); + rtw89_config_default_chandef(rtwdev); } +static bool rtw89_vif_is_active_role(struct rtw89_vif *rtwvif) +{ + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + if (rtwvif_link->chanctx_assigned) + return true; + + return false; +} + static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, struct rtw89_entity_weight *w) { @@ -255,11 +275,147 @@ static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, } rtw89_for_each_rtwvif(rtwdev, rtwvif) { - if (rtwvif->chanctx_assigned) + if (rtw89_vif_is_active_role(rtwvif)) w->active_roles++; } } +static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_vif_link *cur; + + if (unlikely(!rtwvif_link->chanctx_assigned)) + return; + + cur = rtw89_vif_get_link_inst(rtwvif, 0); + if (!cur || !cur->chanctx_assigned) + return; + + if (cur == rtwvif_link) + return; + + rtw89_swap_chanctx(rtwdev, rtwvif_link->chanctx_idx, cur->chanctx_idx); +} + +const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, + const char *caller_message, + u8 link_index) +{ + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; + enum rtw89_chanctx_idx chanctx_idx; + enum rtw89_chanctx_idx roc_idx; + enum rtw89_entity_mode mode; + u8 role_index; + + lockdep_assert_held(&rtwdev->mutex); + + if (unlikely(link_index >= __RTW89_MLD_MAX_LINK_NUM)) { + WARN(1, "link index %u is invalid (max link inst num: %d)\n", + link_index, __RTW89_MLD_MAX_LINK_NUM); + goto dflt; + } + + mode = rtw89_get_entity_mode(rtwdev); + switch (mode) { + case RTW89_ENTITY_MODE_SCC_OR_SMLD: + case RTW89_ENTITY_MODE_MCC: + role_index = 0; + break; + case RTW89_ENTITY_MODE_MCC_PREPARE: + role_index = 1; + break; + default: + WARN(1, "Invalid ent mode: %d\n", mode); + goto dflt; + } + + chanctx_idx = mgnt->chanctx_tbl[role_index][link_index]; + if (chanctx_idx == RTW89_CHANCTX_IDLE) + goto dflt; + + roc_idx = atomic_read(&hal->roc_chanctx_idx); + if (roc_idx != RTW89_CHANCTX_IDLE) { + /* ROC is ongoing (given ROC runs on RTW89_ROC_BY_LINK_INDEX). + * If @link_index is the same as RTW89_ROC_BY_LINK_INDEX, get + * the ongoing ROC chanctx. + */ + if (link_index == RTW89_ROC_BY_LINK_INDEX) + chanctx_idx = roc_idx; + } + + return rtw89_chan_get(rtwdev, chanctx_idx); + +dflt: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "%s (%s): prefetch NULL on link index %u\n", + __func__, caller_message ?: "", link_index); + + return rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); +} +EXPORT_SYMBOL(__rtw89_mgnt_chan_get); + +static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; + struct rtw89_vif_link *link; + struct rtw89_vif *role; + u8 pos = 0; + int i, j; + + lockdep_assert_held(&rtwdev->mutex); + + for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) + mgnt->active_roles[i] = NULL; + + for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) { + for (j = 0; j < __RTW89_MLD_MAX_LINK_NUM; j++) + mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE; + } + + /* To be consistent with legacy behavior, expect the first active role + * which uses RTW89_CHANCTX_0 to put at position 0, and make its first + * link instance take RTW89_CHANCTX_0. (normalizing) + */ + list_for_each_entry(role, &mgnt->active_list, mgnt_entry) { + for (i = 0; i < role->links_inst_valid_num; i++) { + link = rtw89_vif_get_link_inst(role, i); + if (!link || !link->chanctx_assigned) + continue; + + if (link->chanctx_idx == RTW89_CHANCTX_0) { + rtw89_normalize_link_chanctx(rtwdev, link); + + list_del(&role->mgnt_entry); + list_add(&role->mgnt_entry, &mgnt->active_list); + break; + } + } + } + + list_for_each_entry(role, &mgnt->active_list, mgnt_entry) { + if (unlikely(pos >= RTW89_MAX_INTERFACE_NUM)) { + rtw89_warn(rtwdev, + "%s: active roles are over max iface num\n", + __func__); + break; + } + + for (i = 0; i < role->links_inst_valid_num; i++) { + link = rtw89_vif_get_link_inst(role, i); + if (!link || !link->chanctx_assigned) + continue; + + mgnt->chanctx_tbl[pos][i] = link->chanctx_idx; + } + + mgnt->active_roles[pos++] = role; + } +} + enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) { DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_CHANCTX) = {}; @@ -286,9 +442,14 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) set_bit(RTW89_CHANCTX_0, recalc_map); fallthrough; case 1: - mode = RTW89_ENTITY_MODE_SCC; + mode = RTW89_ENTITY_MODE_SCC_OR_SMLD; break; case 2 ... NUM_OF_RTW89_CHANCTX: + if (w.active_roles == 1) { + mode = RTW89_ENTITY_MODE_SCC_OR_SMLD; + break; + } + if (w.active_roles != NUM_OF_RTW89_MCC_ROLES) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, "unhandled ent: %d chanctxs %d roles\n", @@ -315,6 +476,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) rtw89_assign_entity_chan(rtwdev, idx, &chan); } + rtw89_entity_recalc_mgnt_roles(rtwdev); + if (hal->entity_pause) return rtw89_get_entity_mode(rtwdev); @@ -387,9 +550,9 @@ int rtw89_iterate_mcc_roles(struct rtw89_dev *rtwdev, static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role, u64 tsf) { - struct rtw89_vif *rtwvif = role->rtwvif; + struct rtw89_vif_link *rtwvif_link = role->rtwvif_link; u32 bcn_intvl_us = ieee80211_tu_to_usec(role->beacon_interval); - u64 sync_tsf = READ_ONCE(rtwvif->sync_bcn_tsf); + u64 sync_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); u32 remainder; if (tsf < sync_tsf) { @@ -413,8 +576,8 @@ static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux int ret; req.group = mcc->group; - req.macid_x = ref->rtwvif->mac_id; - req.macid_y = aux->rtwvif->mac_id; + req.macid_x = ref->rtwvif_link->mac_id; + req.macid_y = aux->rtwvif_link->mac_id; ret = rtw89_fw_h2c_mcc_req_tsf(rtwdev, &req, &rpt); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, @@ -440,10 +603,10 @@ static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES); arg.num = 2; - arg.infos[0].band = ref->rtwvif->mac_idx; - arg.infos[0].port = ref->rtwvif->port; - arg.infos[1].band = aux->rtwvif->mac_idx; - arg.infos[1].port = aux->rtwvif->port; + arg.infos[0].band = ref->rtwvif_link->mac_idx; + arg.infos[0].port = ref->rtwvif_link->port; + arg.infos[1].band = aux->rtwvif_link->mac_idx; + arg.infos[1].port = aux->rtwvif_link->port; ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, &arg, &rpt); if (ret) { @@ -522,23 +685,31 @@ out: static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_mcc_role *mcc_role = data; - struct rtw89_vif *target = mcc_role->rtwvif; + struct rtw89_vif *target = mcc_role->rtwvif_link->rtwvif; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_sta_link *rtwsta_link; if (rtwvif != target) return; - rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta->mac_id); + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) { + rtw89_err(rtwdev, "mcc sta macid: find no link on HW-0\n"); + return; + } + + rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta_link->mac_id); } static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *mcc_role) { - struct rtw89_vif *rtwvif = mcc_role->rtwvif; + struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link; - rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif->mac_id); + rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif_link->mac_id); ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_mcc_role_macid_sta_iter, mcc_role); @@ -564,8 +735,9 @@ static void rtw89_mcc_fill_role_policy(struct rtw89_dev *rtwdev, static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *mcc_role) { - struct ieee80211_vif *vif = rtwvif_to_vif(mcc_role->rtwvif); + struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link; struct ieee80211_p2p_noa_desc *noa_desc; + struct ieee80211_bss_conf *bss_conf; u32 bcn_intvl_us = ieee80211_tu_to_usec(mcc_role->beacon_interval); u32 max_toa_us, max_tob_us, max_dur_us; u32 start_time, interval, duration; @@ -576,13 +748,18 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev, if (!mcc_role->is_go && !mcc_role->is_gc) return; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + /* find the first periodic NoA */ for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) { - noa_desc = &vif->bss_conf.p2p_noa_attr.desc[i]; + noa_desc = &bss_conf->p2p_noa_attr.desc[i]; if (noa_desc->count == 255) goto fill; } + rcu_read_unlock(); return; fill: @@ -590,6 +767,8 @@ fill: interval = le32_to_cpu(noa_desc->interval); duration = le32_to_cpu(noa_desc->duration); + rcu_read_unlock(); + if (interval != bcn_intvl_us) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC role limit: mismatch interval: %d vs. %d\n", @@ -597,7 +776,7 @@ fill: return; } - ret = rtw89_mac_port_get_tsf(rtwdev, mcc_role->rtwvif, &tsf); + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret); return; @@ -632,15 +811,21 @@ fill: } static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct rtw89_mcc_role *role) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf; const struct rtw89_chan *chan; memset(role, 0, sizeof(*role)); - role->rtwvif = rtwvif; - role->beacon_interval = vif->bss_conf.beacon_int; + role->rtwvif_link = rtwvif_link; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + role->beacon_interval = bss_conf->beacon_int; + + rcu_read_unlock(); if (!role->beacon_interval) { rtw89_warn(rtwdev, @@ -650,10 +835,10 @@ static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev, role->duration = role->beacon_interval / 2; - chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); role->is_2ghz = chan->band_type == RTW89_BAND_2G; - role->is_go = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_GO; - role->is_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; + role->is_go = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_GO; + role->is_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; rtw89_mcc_fill_role_macid_bitmap(rtwdev, role); rtw89_mcc_fill_role_policy(rtwdev, role); @@ -678,10 +863,11 @@ static void rtw89_mcc_fill_bt_role(struct rtw89_dev *rtwdev) } struct rtw89_mcc_fill_role_selector { - struct rtw89_vif *bind_vif[NUM_OF_RTW89_CHANCTX]; + struct rtw89_vif_link *bind_vif[NUM_OF_RTW89_CHANCTX]; }; static_assert((u8)NUM_OF_RTW89_CHANCTX >= NUM_OF_RTW89_MCC_ROLES); +static_assert(RTW89_MAX_INTERFACE_NUM >= NUM_OF_RTW89_MCC_ROLES); static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *mcc_role, @@ -689,7 +875,7 @@ static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev, void *data) { struct rtw89_mcc_fill_role_selector *sel = data; - struct rtw89_vif *role_vif = sel->bind_vif[ordered_idx]; + struct rtw89_vif_link *role_vif = sel->bind_vif[ordered_idx]; int ret; if (!role_vif) { @@ -711,22 +897,26 @@ static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev, static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev) { + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; struct rtw89_mcc_fill_role_selector sel = {}; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; int ret; + int i; - rtw89_for_each_rtwvif(rtwdev, rtwvif) { - if (!rtwvif->chanctx_assigned) - continue; + for (i = 0; i < NUM_OF_RTW89_MCC_ROLES; i++) { + rtwvif = mgnt->active_roles[i]; + if (!rtwvif) + break; - if (sel.bind_vif[rtwvif->chanctx_idx]) { - rtw89_warn(rtwdev, - "MCC skip extra vif <macid %d> on chanctx[%d]\n", - rtwvif->mac_id, rtwvif->chanctx_idx); + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "mcc fill roles: find no link on HW-0\n"); continue; } - sel.bind_vif[rtwvif->chanctx_idx] = rtwvif; + sel.bind_vif[i] = rtwvif_link; } ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel); @@ -754,13 +944,13 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, memset(&pattern->courtesy, 0, sizeof(pattern->courtesy)); if (pattern->tob_aux <= 0 || pattern->toa_aux <= 0) { - pattern->courtesy.macid_tgt = aux->rtwvif->mac_id; - pattern->courtesy.macid_src = ref->rtwvif->mac_id; + pattern->courtesy.macid_tgt = aux->rtwvif_link->mac_id; + pattern->courtesy.macid_src = ref->rtwvif_link->mac_id; pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT; pattern->courtesy.enable = true; } else if (pattern->tob_ref <= 0 || pattern->toa_ref <= 0) { - pattern->courtesy.macid_tgt = ref->rtwvif->mac_id; - pattern->courtesy.macid_src = aux->rtwvif->mac_id; + pattern->courtesy.macid_tgt = ref->rtwvif_link->mac_id; + pattern->courtesy.macid_src = aux->rtwvif_link->mac_id; pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT; pattern->courtesy.enable = true; } @@ -1263,7 +1453,7 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev, u64 tsf_src; int ret; - ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif, &tsf_src); + ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif_link, &tsf_src); if (ret) { rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret); return; @@ -1280,12 +1470,12 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev, div_u64_rem(tbtt_tgt, bcn_intvl_src_us, &remainder); tsf_ofst_tgt = bcn_intvl_src_us - remainder; - config->sync.macid_tgt = tgt->rtwvif->mac_id; - config->sync.band_tgt = tgt->rtwvif->mac_idx; - config->sync.port_tgt = tgt->rtwvif->port; - config->sync.macid_src = src->rtwvif->mac_id; - config->sync.band_src = src->rtwvif->mac_idx; - config->sync.port_src = src->rtwvif->port; + config->sync.macid_tgt = tgt->rtwvif_link->mac_id; + config->sync.band_tgt = tgt->rtwvif_link->mac_idx; + config->sync.port_tgt = tgt->rtwvif_link->port; + config->sync.macid_src = src->rtwvif_link->mac_id; + config->sync.band_src = src->rtwvif_link->mac_idx; + config->sync.port_src = src->rtwvif_link->port; config->sync.offset = tsf_ofst_tgt / 1024; config->sync.enable = true; @@ -1294,7 +1484,7 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev, config->sync.macid_tgt, config->sync.macid_src, config->sync.offset); - rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif, src->rtwvif, + rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif_link, src->rtwvif_link, config->sync.offset); } @@ -1305,13 +1495,13 @@ static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev) struct rtw89_mcc_config *config = &mcc->config; u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval); u32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref); - struct rtw89_vif *rtwvif = ref->rtwvif; + struct rtw89_vif_link *rtwvif_link = ref->rtwvif_link; u64 tsf, start_tsf; u32 cur_tbtt_ofst; u64 min_time; int ret; - ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, &tsf); + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret); return ret; @@ -1390,13 +1580,13 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro const struct rtw89_chan *chan; int ret; - chan = rtw89_chan_get(rtwdev, role->rtwvif->chanctx_idx); + chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx); req.central_ch_seg0 = chan->channel; req.primary_ch = chan->primary_channel; req.bandwidth = chan->band_width; req.ch_band_type = chan->band_type; - req.macid = role->rtwvif->mac_id; + req.macid = role->rtwvif_link->mac_id; req.group = mcc->group; req.c2h_rpt = policy->c2h_rpt; req.tx_null_early = policy->tx_null_early; @@ -1421,7 +1611,7 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro } ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group, - role->rtwvif->mac_id, + role->rtwvif_link->mac_id, role->macid_bitmap); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, @@ -1448,7 +1638,7 @@ void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role, slot_arg->duration = role->duration; slot_arg->role_num = 1; - chan = rtw89_chan_get(rtwdev, role->rtwvif->chanctx_idx); + chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx); slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI; slot_arg->roles[0].is_master = role == ref; @@ -1458,7 +1648,7 @@ void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role, slot_arg->roles[0].primary_ch = chan->primary_channel; slot_arg->roles[0].en_tx_null = !policy->dis_tx_null; slot_arg->roles[0].null_early = policy->tx_null_early; - slot_arg->roles[0].macid = role->rtwvif->mac_id; + slot_arg->roles[0].macid = role->rtwvif_link->mac_id; slot_arg->roles[0].macid_main_bitmap = rtw89_mcc_role_fw_macid_bitmap_to_u32(role); } @@ -1569,7 +1759,7 @@ static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace) } } - req.macid = ref->rtwvif->mac_id; + req.macid = ref->rtwvif_link->mac_id; req.tsf_high = config->start_tsf >> 32; req.tsf_low = config->start_tsf; @@ -1598,7 +1788,7 @@ static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev, if (!courtesy->enable) return; - if (courtesy->macid_src == ref->rtwvif->mac_id) { + if (courtesy->macid_src == ref->rtwvif_link->mac_id) { slot_arg_src = &arg->slots[ref->slot_idx]; slot_idx_tgt = aux->slot_idx; } else { @@ -1717,9 +1907,9 @@ static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_chang struct rtw89_fw_mcc_duration req = { .group = mcc->group, .btc_in_group = false, - .start_macid = ref->rtwvif->mac_id, - .macid_x = ref->rtwvif->mac_id, - .macid_y = aux->rtwvif->mac_id, + .start_macid = ref->rtwvif_link->mac_id, + .macid_x = ref->rtwvif_link->mac_id, + .macid_y = aux->rtwvif_link->mac_id, .duration_x = ref->duration, .duration_y = aux->duration, .start_tsf_high = config->start_tsf >> 32, @@ -1813,18 +2003,18 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) struct ieee80211_p2p_noa_desc noa_desc = {}; u64 start_time = config->start_tsf; u32 interval = config->mcc_interval; - struct rtw89_vif *rtwvif_go; + struct rtw89_vif_link *rtwvif_go; u32 duration; if (mcc->mode != RTW89_MCC_MODE_GO_STA) return; if (ref->is_go) { - rtwvif_go = ref->rtwvif; + rtwvif_go = ref->rtwvif_link; start_time += ieee80211_tu_to_usec(ref->duration); duration = config->mcc_interval - ref->duration; } else if (aux->is_go) { - rtwvif_go = aux->rtwvif; + rtwvif_go = aux->rtwvif_link; start_time += ieee80211_tu_to_usec(pattern->tob_ref) + ieee80211_tu_to_usec(config->beacon_offset) + ieee80211_tu_to_usec(pattern->toa_aux); @@ -1865,9 +2055,9 @@ static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev) return; if (ref->is_go) - rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif, true); + rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, true); else if (aux->is_go) - rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif, true); + rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, true); rtw89_mcc_handle_beacon_noa(rtwdev, true); } @@ -1882,9 +2072,9 @@ static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev) return; if (ref->is_go) - rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif, false); + rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, false); else if (aux->is_go) - rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif, false); + rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, false); rtw89_mcc_handle_beacon_noa(rtwdev, false); } @@ -1942,7 +2132,7 @@ struct rtw89_mcc_stop_sel { static void rtw89_mcc_stop_sel_fill(struct rtw89_mcc_stop_sel *sel, const struct rtw89_mcc_role *mcc_role) { - sel->mac_id = mcc_role->rtwvif->mac_id; + sel->mac_id = mcc_role->rtwvif_link->mac_id; sel->slot_idx = mcc_role->slot_idx; } @@ -1953,7 +2143,7 @@ static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev, { struct rtw89_mcc_stop_sel *sel = data; - if (!mcc_role->rtwvif->chanctx_assigned) + if (!mcc_role->rtwvif_link->chanctx_assigned) return 0; rtw89_mcc_stop_sel_fill(sel, mcc_role); @@ -2081,7 +2271,7 @@ static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev, int ret; ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group, - upd->rtwvif->mac_id, + upd->rtwvif_link->mac_id, upd->macid_bitmap); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, @@ -2106,7 +2296,7 @@ static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev, int i; arg.sch_idx = mcc->group; - arg.macid = upd->rtwvif->mac_id; + arg.macid = upd->rtwvif_link->mac_id; for (i = 0; i < 32; i++) { if (add & BIT(i)) { @@ -2144,7 +2334,7 @@ static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev, void *data) { struct rtw89_mcc_role upd = { - .rtwvif = mcc_role->rtwvif, + .rtwvif_link = mcc_role->rtwvif_link, }; int ret; @@ -2370,6 +2560,24 @@ void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev) rtw89_queue_chanctx_work(rtwdev); } +static void __rtw89_swap_chanctx(struct rtw89_vif *rtwvif, + enum rtw89_chanctx_idx idx1, + enum rtw89_chanctx_idx idx2) +{ + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + if (!rtwvif_link->chanctx_assigned) + continue; + + if (rtwvif_link->chanctx_idx == idx1) + rtwvif_link->chanctx_idx = idx2; + else if (rtwvif_link->chanctx_idx == idx2) + rtwvif_link->chanctx_idx = idx1; + } +} + static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx1, enum rtw89_chanctx_idx idx2) @@ -2386,14 +2594,8 @@ static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev, swap(hal->chanctx[idx1], hal->chanctx[idx2]); - rtw89_for_each_rtwvif(rtwdev, rtwvif) { - if (!rtwvif->chanctx_assigned) - continue; - if (rtwvif->chanctx_idx == idx1) - rtwvif->chanctx_idx = idx2; - else if (rtwvif->chanctx_idx == idx2) - rtwvif->chanctx_idx = idx1; - } + rtw89_for_each_rtwvif(rtwdev, rtwvif) + __rtw89_swap_chanctx(rtwvif, idx1, idx2); cur = atomic_read(&hal->roc_chanctx_idx); if (cur == idx1) @@ -2444,16 +2646,22 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, } int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx) { struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; struct rtw89_entity_weight w = {}; - rtwvif->chanctx_idx = cfg->idx; - rtwvif->chanctx_assigned = true; + rtwvif_link->chanctx_idx = cfg->idx; + rtwvif_link->chanctx_assigned = true; cfg->ref_count++; + if (list_empty(&rtwvif->mgnt_entry)) + list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list); + if (cfg->idx == RTW89_CHANCTX_0) goto out; @@ -2469,20 +2677,24 @@ out: } void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx) { struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_hal *hal = &rtwdev->hal; enum rtw89_chanctx_idx roll; enum rtw89_entity_mode cur; enum rtw89_entity_mode new; int ret; - rtwvif->chanctx_idx = RTW89_CHANCTX_0; - rtwvif->chanctx_assigned = false; + rtwvif_link->chanctx_idx = RTW89_CHANCTX_0; + rtwvif_link->chanctx_assigned = false; cfg->ref_count--; + if (!rtw89_vif_is_active_role(rtwvif)) + list_del_init(&rtwvif->mgnt_entry); + if (cfg->ref_count != 0) goto out; diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index c6d31984e575..2eb31dff2083 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -43,18 +43,21 @@ struct rtw89_entity_weight { unsigned int active_roles; }; -static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev) +static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) { struct rtw89_hal *hal = &rtwdev->hal; - return READ_ONCE(hal->entity_active); + return READ_ONCE(hal->entity_active[phy_idx]); } -static inline void rtw89_set_entity_state(struct rtw89_dev *rtwdev, bool active) +static inline void rtw89_set_entity_state(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + bool active) { struct rtw89_hal *hal = &rtwdev->hal; - WRITE_ONCE(hal->entity_active, active); + WRITE_ONCE(hal->entity_active[phy_idx], active); } static inline @@ -98,6 +101,14 @@ void rtw89_chanctx_track(struct rtw89_dev *rtwdev); void rtw89_chanctx_pause(struct rtw89_dev *rtwdev, enum rtw89_chanctx_pause_reasons rsn); void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev); + +const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, + const char *caller_message, + u8 link_index); + +#define rtw89_mgnt_chan_get(rtwdev, link_index) \ + __rtw89_mgnt_chan_get(rtwdev, __func__, link_index) + int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx); void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, @@ -106,10 +117,10 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx, u32 changed); int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx); void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx); #endif diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 8d27374db83c..68316d44b204 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -125,6 +125,9 @@ static const u32 cxtbl[] = { 0xfafaaafa, /* 23 */ 0xfafffaff, /* 24 */ 0xea6a5a5a, /* 25 */ + 0xfaff5aff, /* 26 */ + 0xffffdfff, /* 27 */ + 0xe6555555, /* 28 */ }; static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { @@ -134,77 +137,88 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, - .fwevntrptl = 1, .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, + .max_role_num = 6, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0), .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, - .fwevntrptl = 1, .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_type = 1, .info_buf = 1800, + .max_role_num = 6, }, {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, + .max_role_num = 6, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, + .max_role_num = 6, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, + .max_role_num = 6, }, {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1024, + .max_role_num = 5, }, /* keep it to be the last as default entry */ @@ -213,7 +227,8 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1024, + .max_role_num = 5, }, }; @@ -224,7 +239,7 @@ static const union rtw89_btc_wl_state_map btc_scanning_map = { .scan = 1, .connecting = 1, .roaming = 1, - .transacting = 1, + .dbccing = 1, ._4way = 1, }, }; @@ -2492,6 +2507,8 @@ static void btc_fw_set_monreg(struct rtw89_dev *rtwdev) if (ver->fcxmreg == 7) { sz = struct_size(v7, regs, n); v7 = kmalloc(sz, GFP_KERNEL); + if (!v7) + return; v7->type = RPT_EN_MREG; v7->fver = ver->fcxmreg; v7->len = n; @@ -2506,6 +2523,8 @@ static void btc_fw_set_monreg(struct rtw89_dev *rtwdev) } else { sz = struct_size(v1, regs, n); v1 = kmalloc(sz, GFP_KERNEL); + if (!v1) + return; v1->fver = ver->fcxmreg; v1->reg_num = n; memcpy(v1->regs, chip->mon_reg, flex_array_size(v1, regs, n)); @@ -3017,7 +3036,7 @@ static void _update_btc_state_map(struct rtw89_dev *rtwdev) struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; if (wl->status.map.connecting || wl->status.map._4way || - wl->status.map.roaming) { + wl->status.map.roaming || wl->status.map.dbccing) { cx->state_map = BTC_WLINKING; } else if (wl->status.map.scan) { /* wl scan */ if (bt_linfo->status.map.inq_pag) @@ -3680,6 +3699,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_fbtc_tdma *t = &dm->tdma; struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &btc->cx.wl.role_info_v1; + struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt.link_info.hid_desc; struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt.link_info.hfp_desc; struct rtw89_btc_wl_info *wl = &btc->cx.wl; @@ -3721,8 +3741,6 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) tbl_w1 = cxtbl[16]; } - btc->bt_req_en = false; - switch (type) { case BTC_CXP_USERDEF0: btc->update_policy_force = true; @@ -3744,6 +3762,10 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) case BTC_CXP_OFF_WL: _slot_set_tbl(btc, CXST_OFF, cxtbl[1]); break; + case BTC_CXP_OFF_WL2: + _slot_set_tbl(btc, CXST_OFF, cxtbl[1]); + _slot_set_type(btc, CXST_OFF, SLOT_ISO); + break; case BTC_CXP_OFF_EQ0: _slot_set_tbl(btc, CXST_OFF, cxtbl[0]); _slot_set_type(btc, CXST_OFF, SLOT_ISO); @@ -3757,6 +3779,12 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) case BTC_CXP_OFF_EQ3: _slot_set_tbl(btc, CXST_OFF, cxtbl[24]); break; + case BTC_CXP_OFF_EQ4: + _slot_set_tbl(btc, CXST_OFF, cxtbl[26]); + break; + case BTC_CXP_OFF_EQ5: + _slot_set_tbl(btc, CXST_OFF, cxtbl[27]); + break; case BTC_CXP_OFF_BWB0: _slot_set_tbl(btc, CXST_OFF, cxtbl[5]); break; @@ -3788,7 +3816,6 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) } break; case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */ - btc->bt_req_en = true; _write_scbd(rtwdev, BTC_WSCB_TDMA, true); *t = t_def[CXTD_OFF_EXT]; @@ -3831,9 +3858,12 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype); break; case BTC_CXP_OFFE_2GBWMIXB: - _slot_set(btc, CXST_E2G, 0, 0x55555555, SLOT_MIX); + if (a2dp->exist) + _slot_set(btc, CXST_E2G, 0, cxtbl[2], SLOT_MIX); + else + _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_MIX); _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, - cpu_to_le32(0x55555555), s_def[CXST_EBT].cxtype); + s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); break; case BTC_CXP_OFFE_WL: /* for 4-way */ _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_MIX); @@ -3842,6 +3872,8 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) default: break; } + _slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur, + s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype); _slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur, s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype); break; @@ -4246,6 +4278,7 @@ static void _set_ant_v0(struct rtw89_dev *rtwdev, bool force_exec, _set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE); break; case BTC_ANT_WRFK: + case BTC_ANT_WRFK2: rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL); _set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO); _set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE); @@ -4623,12 +4656,21 @@ static void _action_bt_a2dpsink(struct rtw89_dev *rtwdev) static void _action_bt_pan(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info; + struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc; + struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc; _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); switch (btc->cx.state_map) { case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN */ - _set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN); + if (a2dp.active || !pan.exist) { + btc->dm.slot_dur[CXST_W1] = 80; + btc->dm.slot_dur[CXST_B1] = 20; + _set_policy(rtwdev, BTC_CXP_PFIX_TDW1B1, BTC_ACT_BT_PAN); + } else { + _set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN); + } break; case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN */ _set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN); @@ -4814,8 +4856,16 @@ static void _action_wl_rfk(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): band = %d\n", __func__, rfk.band); - _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK); - _set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK); + btc->dm.tdma_instant_excute = 1; + + if (rfk.state == BTC_WRFK_ONESHOT_START || + btc->ant_type == BTC_ANT_SHARED) { + _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK2); + _set_policy(rtwdev, BTC_CXP_OFF_WL2, BTC_ACT_WL_RFK); + } else { + _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK); + _set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK); + } } static void _set_btg_ctrl(struct rtw89_dev *rtwdev) @@ -4855,6 +4905,8 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) if (rtwdev->dbcc_en) { if (ver->fwlrole == 0) { + wl_rinfo.dbcc_2g_phy = RTW89_PHY_MAX; + for (i = 0; i < RTW89_PHY_MAX; i++) { if (wl_dinfo->real_band[i] == RTW89_BAND_2G) wl_rinfo.dbcc_2g_phy = i; @@ -4989,18 +5041,16 @@ struct rtw89_txtime_data { bool reenable; }; -static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) +static void __rtw89_tx_time_iter(struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct rtw89_txtime_data *iter_data) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_txtime_data *iter_data = - (struct rtw89_txtime_data *)data; struct rtw89_dev *rtwdev = iter_data->rtwdev; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_wl_info *wl = &cx->wl; struct rtw89_btc_wl_link_info *plink = NULL; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u32 tx_time = iter_data->tx_time; u8 tx_retry = iter_data->tx_retry; u16 enable = iter_data->enable; @@ -5023,8 +5073,8 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) /* backup the original tx time before tx-limit on */ if (reenable) { - rtw89_mac_get_tx_time(rtwdev, rtwsta, &plink->tx_time); - rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta, &plink->tx_retry); + rtw89_mac_get_tx_time(rtwdev, rtwsta_link, &plink->tx_time); + rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta_link, &plink->tx_retry); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reenable, tx_time=%d tx_retry= %d\n", __func__, plink->tx_time, plink->tx_retry); @@ -5032,22 +5082,37 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) /* restore the original tx time if no tx-limit */ if (!enable) { - rtw89_mac_set_tx_time(rtwdev, rtwsta, true, plink->tx_time); - rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, true, + rtw89_mac_set_tx_time(rtwdev, rtwsta_link, true, plink->tx_time); + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, true, plink->tx_retry); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): restore, tx_time=%d tx_retry= %d\n", __func__, plink->tx_time, plink->tx_retry); } else { - rtw89_mac_set_tx_time(rtwdev, rtwsta, false, tx_time); - rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, false, tx_retry); + rtw89_mac_set_tx_time(rtwdev, rtwsta_link, false, tx_time); + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, tx_retry); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): set, tx_time=%d tx_retry= %d\n", __func__, tx_time, tx_retry); } } +static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_txtime_data *iter_data = + (struct rtw89_txtime_data *)data; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + __rtw89_tx_time_iter(rtwvif_link, rtwsta_link, iter_data); + } +} + static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -5231,8 +5296,14 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc; struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc; struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc; + struct rtw89_btc_dm *dm = &btc->dm; u8 profile_map = 0; + if (dm->freerun_chk) { + _action_freerun(rtwdev); + return; + } + if (bt_linfo->hfp_desc.exist) profile_map |= BTC_BT_HFP; @@ -5247,30 +5318,20 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) switch (profile_map) { case BTC_BT_NOPROFILE: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); - else if (pan.active) + if (pan.active) _action_bt_pan(rtwdev); else _action_bt_idle(rtwdev); break; case BTC_BT_HFP: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); - else - _action_bt_hfp(rtwdev); + _action_bt_hfp(rtwdev); break; case BTC_BT_HFP | BTC_BT_HID: case BTC_BT_HID: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); - else - _action_bt_hid(rtwdev); + _action_bt_hid(rtwdev); break; case BTC_BT_A2DP: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); - else if (a2dp.sink) + if (a2dp.sink) _action_bt_a2dpsink(rtwdev); else if (bt_linfo->multi_link.now && !hid.pair_cnt) _action_bt_a2dp_pan(rtwdev); @@ -5283,13 +5344,18 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) case BTC_BT_A2DP | BTC_BT_HFP: case BTC_BT_A2DP | BTC_BT_HID: case BTC_BT_A2DP | BTC_BT_HFP | BTC_BT_HID: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); + if (a2dp.sink) + _action_bt_a2dpsink(rtwdev); + else if (pan.active) + _action_bt_a2dp_pan_hid(rtwdev); else _action_bt_a2dp_hid(rtwdev); break; case BTC_BT_A2DP | BTC_BT_PAN: - _action_bt_a2dp_pan(rtwdev); + if (a2dp.sink) + _action_bt_a2dpsink(rtwdev); + else + _action_bt_a2dp_pan(rtwdev); break; case BTC_BT_PAN | BTC_BT_HFP: case BTC_BT_PAN | BTC_BT_HID: @@ -5299,7 +5365,10 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HID: case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HFP: default: - _action_bt_a2dp_pan_hid(rtwdev); + if (a2dp.sink) + _action_bt_a2dpsink(rtwdev); + else + _action_bt_a2dp_pan_hid(rtwdev); break; } } @@ -5319,7 +5388,7 @@ static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev) policy_type = BTC_CXP_OFFE_WL; else if (btc->cx.wl.status.val & btc_scanning_map.val) policy_type = BTC_CXP_OFFE_2GBWMIXB; - else if (btc->cx.bt.link_info.profile_cnt.now == 0) + else if (btc->cx.bt.link_info.status.map.connect == 0) policy_type = BTC_CXP_OFFE_2GISOB; else policy_type = BTC_CXP_OFFE_2GBWISOB; @@ -6893,6 +6962,8 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) bt->scan_rx_low_pri = false; igno_bt = false; + dm->freerun_chk = _check_freerun(rtwdev); /* check if meet freerun */ + if (always_freerun) { _action_freerun(rtwdev); igno_bt = true; @@ -6931,18 +7002,9 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) goto exit; } - if (cx->state_map == BTC_WLINKING) { - if (mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_2G_STA || - mode == BTC_WLINK_5G) { - _action_wl_scan(rtwdev); - bt->scan_rx_low_pri = false; - goto exit; - } - } - - if (wl->status.map.scan) { + if (wl->status.val & btc_scanning_map.val) { _action_wl_scan(rtwdev); - bt->scan_rx_low_pri = false; + bt->scan_rx_low_pri = true; goto exit; } @@ -7178,10 +7240,6 @@ void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band) btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++; - wl->scan_info.band[phy_idx] = band; - wl->scan_info.phy_map |= BIT(phy_idx); - _fw_set_drv_info(rtwdev, CXDRVINFO_SCAN); - if (rtwdev->dbcc_en) { wl->dbcc_info.scan_band[phy_idx] = band; _update_dbcc_band(rtwdev, phy_idx); @@ -7376,13 +7434,7 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) "[BTC], %s(): bt_info[2]=0x%02x\n", __func__, bt->raw_info[2]); - /* reset to mo-connect before update */ - b->status.val = BTC_BLINK_NOCONNECT; b->profile_cnt.last = b->profile_cnt.now; - b->relink.last = b->relink.now; - a2dp->exist_last = a2dp->exist; - b->multi_link.last = b->multi_link.now; - bt->inq_pag.last = bt->inq_pag.now; b->profile_cnt.now = 0; hid->type = 0; @@ -7401,7 +7453,8 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) b->profile_cnt.now += (u8)hid->exist; a2dp->exist = btinfo.lb2.a2dp; b->profile_cnt.now += (u8)a2dp->exist; - pan->active = btinfo.lb2.pan; + pan->exist = btinfo.lb2.pan; + b->profile_cnt.now += (u8)pan->exist; btc->dm.trx_info.bt_profile = u32_get_bits(btinfo.val, BT_PROFILE_PROTOCOL_MASK); /* parse raw info low-Byte3 */ @@ -7425,8 +7478,14 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) /* parse raw info high-Byte1 */ btinfo.val = bt->raw_info[BTC_BTINFO_H1]; b->status.map.ble_connect = btinfo.hb1.ble_connect; - if (btinfo.hb1.ble_connect) - hid->type |= (hid->exist ? BTC_HID_BLE : BTC_HID_RCU); + if (btinfo.hb1.ble_connect) { + if (hid->exist) + hid->type |= BTC_HID_BLE; + else if (btinfo.hb1.voice) + hid->type |= BTC_HID_RCU_VOICE; + else + hid->type |= BTC_HID_RCU; + } cx->cnt_bt[BTC_BCNT_REINIT] += !!(btinfo.hb1.reinit && !bt->reinit); bt->reinit = btinfo.hb1.reinit; @@ -7438,7 +7497,6 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) if (bt->igno_wl && !cx->wl.status.map.rf_off) _set_bt_ignore_wlan_act(rtwdev, false); - hid->type |= (btinfo.hb1.voice ? BTC_HID_RCU_VOICE : 0); bt->ble_scan_en = btinfo.hb1.ble_scan; cx->cnt_bt[BTC_BCNT_ROLESW] += !!(btinfo.hb1.role_sw && !b->role_sw); @@ -7448,8 +7506,7 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) /* parse raw info high-Byte2 */ btinfo.val = bt->raw_info[BTC_BTINFO_H2]; - pan->exist = btinfo.hb2.pan_active; - b->profile_cnt.now += (u8)pan->exist; + pan->active = !!btinfo.hb2.pan_active; cx->cnt_bt[BTC_BCNT_AFH] += !!(btinfo.hb2.afh_update && !b->afh_update); b->afh_update = btinfo.hb2.afh_update; @@ -7457,8 +7514,9 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) b->slave_role = btinfo.hb2.slave; hid->slot_info = btinfo.hb2.hid_slot; hid->pair_cnt = btinfo.hb2.hid_cnt; - hid->type |= (hid->slot_info == BTC_HID_218 ? - BTC_HID_218 : BTC_HID_418); + if (!b->status.map.ble_connect || hid->pair_cnt > 1) + hid->type |= (hid->slot_info == BTC_HID_218 ? + BTC_HID_218 : BTC_HID_418); /* parse raw info high-Byte3 */ btinfo.val = bt->raw_info[BTC_BTINFO_H3]; a2dp->bitpool = btinfo.hb3.a2dp_bitpool; @@ -7481,13 +7539,16 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) _run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO); } -void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, enum btc_role_state state) +void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + enum btc_role_state state) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); + rtwvif_link->chanctx_idx); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct ieee80211_bss_conf *bss_conf; + struct ieee80211_link_sta *link_sta; struct rtw89_btc *btc = &rtwdev->btc; const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; @@ -7495,51 +7556,59 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif struct rtw89_btc_wl_link_info *wlinfo = NULL; u8 mode = 0, rlink_id, link_mode_ori, pta_req_mac_ori, wa_type; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], role is STA=%d\n", vif->type == NL80211_IFTYPE_STATION); - rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif->port); + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif_link->port); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n", chan->band_type, chan->channel, chan->band_width); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n", state == BTC_ROLE_MSTS_STA_CONN_END); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], bcn_period=%d dtim_period=%d\n", - vif->bss_conf.beacon_int, vif->bss_conf.dtim_period); + bss_conf->beacon_int, bss_conf->dtim_period); + + if (rtwsta_link) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); - if (rtwsta) { rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n", - rtwsta->mac_id); + rtwsta_link->mac_id); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA support HE=%d VHT=%d HT=%d\n", - sta->deflink.he_cap.has_he, - sta->deflink.vht_cap.vht_supported, - sta->deflink.ht_cap.ht_supported); - if (sta->deflink.he_cap.has_he) + link_sta->he_cap.has_he, + link_sta->vht_cap.vht_supported, + link_sta->ht_cap.ht_supported); + if (link_sta->he_cap.has_he) mode |= BIT(BTC_WL_MODE_HE); - if (sta->deflink.vht_cap.vht_supported) + if (link_sta->vht_cap.vht_supported) mode |= BIT(BTC_WL_MODE_VHT); - if (sta->deflink.ht_cap.ht_supported) + if (link_sta->ht_cap.ht_supported) mode |= BIT(BTC_WL_MODE_HT); r.mode = mode; } - if (rtwvif->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX) + if (rtwvif_link->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX) { + rcu_read_unlock(); return; + } rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], wifi_role=%d\n", rtwvif->wifi_role); + "[BTC], wifi_role=%d\n", rtwvif_link->wifi_role); - r.role = rtwvif->wifi_role; - r.phy = rtwvif->phy_idx; - r.pid = rtwvif->port; + r.role = rtwvif_link->wifi_role; + r.phy = rtwvif_link->phy_idx; + r.pid = rtwvif_link->port; r.active = true; r.connected = MLME_LINKED; - r.bcn_period = vif->bss_conf.beacon_int; - r.dtim_period = vif->bss_conf.dtim_period; + r.bcn_period = bss_conf->beacon_int; + r.dtim_period = bss_conf->dtim_period; r.band = chan->band_type; r.ch = chan->channel; r.bw = chan->band_width; @@ -7547,10 +7616,12 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif r.chdef.center_ch = chan->channel; r.chdef.bw = chan->band_width; r.chdef.chan = chan->primary_channel; - ether_addr_copy(r.mac_addr, rtwvif->mac_addr); + ether_addr_copy(r.mac_addr, rtwvif_link->mac_addr); - if (rtwsta && vif->type == NL80211_IFTYPE_STATION) - r.mac_id = rtwsta->mac_id; + rcu_read_unlock(); + + if (rtwsta_link && vif->type == NL80211_IFTYPE_STATION) + r.mac_id = rtwsta_link->mac_id; btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++; @@ -7781,26 +7852,26 @@ struct rtw89_btc_wl_sta_iter_data { bool is_traffic_change; }; -static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) +static +void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct rtw89_btc_wl_sta_iter_data *iter_data) { - struct rtw89_btc_wl_sta_iter_data *iter_data = - (struct rtw89_btc_wl_sta_iter_data *)data; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_dev *rtwdev = iter_data->rtwdev; struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_link_info *link_info = NULL; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; struct rtw89_traffic_stats *link_info_t = NULL; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_traffic_stats *stats = &rtwvif->stats; const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc_wl_role_info *r; struct rtw89_btc_wl_role_info_v1 *r1; u32 last_tx_rate, last_rx_rate; u16 last_tx_lvl, last_rx_lvl; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u8 rssi; u8 busy = 0; u8 dir = 0; @@ -7808,11 +7879,11 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) u8 i = 0; bool is_sta_change = false, is_traffic_change = false; - rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR; + rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR; rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi); link_info = &wl->link_info[port]; - link_info->stat.traffic = rtwvif->stats; + link_info->stat.traffic = *stats; link_info_t = &link_info->stat.traffic; if (link_info->connected == MLME_NO_LINK) { @@ -7860,19 +7931,19 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) iter_data->busy_all |= busy; iter_data->dir_all |= BIT(dir); - if (rtwsta->rx_hw_rate <= RTW89_HW_RATE_CCK2 && + if (rtwsta_link->rx_hw_rate <= RTW89_HW_RATE_CCK2 && last_rx_rate > RTW89_HW_RATE_CCK2 && link_info_t->rx_tfc_lv > RTW89_TFC_IDLE) link_info->rx_rate_drop_cnt++; - if (last_tx_rate != rtwsta->ra_report.hw_rate || - last_rx_rate != rtwsta->rx_hw_rate || + if (last_tx_rate != rtwsta_link->ra_report.hw_rate || + last_rx_rate != rtwsta_link->rx_hw_rate || last_tx_lvl != link_info_t->tx_tfc_lv || last_rx_lvl != link_info_t->rx_tfc_lv) is_traffic_change = true; - link_info_t->tx_rate = rtwsta->ra_report.hw_rate; - link_info_t->rx_rate = rtwsta->rx_hw_rate; + link_info_t->tx_rate = rtwsta_link->ra_report.hw_rate; + link_info_t->rx_rate = rtwsta_link->rx_hw_rate; if (link_info->role == RTW89_WIFI_ROLE_STATION || link_info->role == RTW89_WIFI_ROLE_P2P_CLIENT) { @@ -7884,19 +7955,19 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) r = &wl->role_info; r->active_role[port].tx_lvl = stats->tx_tfc_lv; r->active_role[port].rx_lvl = stats->rx_tfc_lv; - r->active_role[port].tx_rate = rtwsta->ra_report.hw_rate; - r->active_role[port].rx_rate = rtwsta->rx_hw_rate; + r->active_role[port].tx_rate = rtwsta_link->ra_report.hw_rate; + r->active_role[port].rx_rate = rtwsta_link->rx_hw_rate; } else if (ver->fwlrole == 1) { r1 = &wl->role_info_v1; r1->active_role_v1[port].tx_lvl = stats->tx_tfc_lv; r1->active_role_v1[port].rx_lvl = stats->rx_tfc_lv; - r1->active_role_v1[port].tx_rate = rtwsta->ra_report.hw_rate; - r1->active_role_v1[port].rx_rate = rtwsta->rx_hw_rate; + r1->active_role_v1[port].tx_rate = rtwsta_link->ra_report.hw_rate; + r1->active_role_v1[port].rx_rate = rtwsta_link->rx_hw_rate; } else if (ver->fwlrole == 2) { dm->trx_info.tx_lvl = stats->tx_tfc_lv; dm->trx_info.rx_lvl = stats->rx_tfc_lv; - dm->trx_info.tx_rate = rtwsta->ra_report.hw_rate; - dm->trx_info.rx_rate = rtwsta->rx_hw_rate; + dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate; + dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate; } dm->trx_info.tx_tp = link_info_t->tx_throughput; @@ -7916,6 +7987,21 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) iter_data->is_traffic_change = true; } +static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_btc_wl_sta_iter_data *iter_data = + (struct rtw89_btc_wl_sta_iter_data *)data; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + __rtw89_btc_ntfy_wl_sta_iter(rtwvif_link, rtwsta_link, iter_data); + } +} + #define BTC_NHM_CHK_INTVL 20 void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev) @@ -7965,6 +8051,53 @@ void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev) } } +static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func) +{ + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; + + switch (func) { + case BTF_EVNT_RPT: + case BTF_EVNT_BT_INFO: + case BTF_EVNT_BT_SCBD: + case BTF_EVNT_BT_REG: + case BTF_EVNT_CX_RUNINFO: + case BTF_EVNT_BT_PSD: + return func; + case BTF_EVNT_BT_DEV_INFO: + if (ver->fwc2hfunc == 0) + return BTF_EVNT_BUF_OVERFLOW; + else + return BTF_EVNT_BT_DEV_INFO; + case BTF_EVNT_BT_LEAUDIO_INFO: + if (ver->fwc2hfunc == 0) + return BTF_EVNT_C2H_LOOPBACK; + else if (ver->fwc2hfunc == 1) + return BTF_EVNT_BUF_OVERFLOW; + else if (ver->fwc2hfunc == 2) + return func; + else + return BTF_EVNT_MAX; + case BTF_EVNT_BUF_OVERFLOW: + if (ver->fwc2hfunc == 0) + return BTF_EVNT_MAX; + else if (ver->fwc2hfunc == 1) + return BTF_EVNT_C2H_LOOPBACK; + else if (ver->fwc2hfunc == 2) + return func; + else + return BTF_EVNT_MAX; + case BTF_EVNT_C2H_LOOPBACK: + if (ver->fwc2hfunc == 2) + return func; + else + return BTF_EVNT_MAX; + case BTF_EVNT_MAX: + default: + return BTF_EVNT_MAX; + } +} + void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func) { @@ -7981,10 +8114,14 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (class != BTFC_FW_EVENT) return; + func = rtw89_btc_c2h_get_index_by_ver(rtwdev, func); + switch (func) { - case BTF_EVNT_RPT: case BTF_EVNT_BUF_OVERFLOW: pfwinfo->event[func]++; + break; + case BTF_EVNT_RPT: + pfwinfo->event[func]++; /* Don't need rtw89_leave_ps_mode() */ btc_fw_event(rtwdev, func, buf, len); break; diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index de53b56632f7..dbdb56e063ef 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -271,8 +271,10 @@ void rtw89_btc_ntfy_eapol_packet_work(struct work_struct *work); void rtw89_btc_ntfy_arp_packet_work(struct work_struct *work); void rtw89_btc_ntfy_dhcp_packet_work(struct work_struct *work); void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work); -void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, enum btc_role_state state); +void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + enum btc_role_state state); void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state); void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map, enum btc_wl_rfk_type type, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 4553810634c6..e5b2968c1431 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -192,13 +192,13 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = { { .limits = rtw89_iface_limits, .n_limits = ARRAY_SIZE(rtw89_iface_limits), - .max_interfaces = 2, + .max_interfaces = RTW89_MAX_INTERFACE_NUM, .num_different_channels = 1, }, { .limits = rtw89_iface_limits_mcc, .n_limits = ARRAY_SIZE(rtw89_iface_limits_mcc), - .max_interfaces = 2, + .max_interfaces = RTW89_MAX_INTERFACE_NUM, .num_different_channels = 2, }, }; @@ -341,83 +341,47 @@ void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef, rtw89_chan_create(chan, center_chan, channel->hw_value, band, bandwidth); } -void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev) +static void __rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) { - struct rtw89_hal *hal = &rtwdev->hal; const struct rtw89_chip_info *chip = rtwdev->chip; - const struct rtw89_chan *chan; - enum rtw89_chanctx_idx chanctx_idx; - enum rtw89_chanctx_idx roc_idx; - enum rtw89_phy_idx phy_idx; - enum rtw89_entity_mode mode; bool entity_active; - entity_active = rtw89_get_entity_state(rtwdev); + entity_active = rtw89_get_entity_state(rtwdev, phy_idx); if (!entity_active) return; - mode = rtw89_get_entity_mode(rtwdev); - switch (mode) { - case RTW89_ENTITY_MODE_SCC: - case RTW89_ENTITY_MODE_MCC: - chanctx_idx = RTW89_CHANCTX_0; - break; - case RTW89_ENTITY_MODE_MCC_PREPARE: - chanctx_idx = RTW89_CHANCTX_1; - break; - default: - WARN(1, "Invalid ent mode: %d\n", mode); - return; - } + chip->ops->set_txpwr(rtwdev, chan, phy_idx); +} - roc_idx = atomic_read(&hal->roc_chanctx_idx); - if (roc_idx != RTW89_CHANCTX_IDLE) - chanctx_idx = roc_idx; +void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chan *chan; - phy_idx = RTW89_PHY_0; - chan = rtw89_chan_get(rtwdev, chanctx_idx); - chip->ops->set_txpwr(rtwdev, chan, phy_idx); + chan = rtw89_mgnt_chan_get(rtwdev, 0); + __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_0); + + if (!rtwdev->support_mlo) + return; + + chan = rtw89_mgnt_chan_get(rtwdev, 1); + __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_1); } -int rtw89_set_channel(struct rtw89_dev *rtwdev) +static void __rtw89_set_channel(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_mac_idx mac_idx, + enum rtw89_phy_idx phy_idx) { - struct rtw89_hal *hal = &rtwdev->hal; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_chan_rcd *chan_rcd; - const struct rtw89_chan *chan; - enum rtw89_chanctx_idx chanctx_idx; - enum rtw89_chanctx_idx roc_idx; - enum rtw89_mac_idx mac_idx; - enum rtw89_phy_idx phy_idx; struct rtw89_channel_help_params bak; - enum rtw89_entity_mode mode; bool entity_active; - entity_active = rtw89_get_entity_state(rtwdev); - - mode = rtw89_entity_recalc(rtwdev); - switch (mode) { - case RTW89_ENTITY_MODE_SCC: - case RTW89_ENTITY_MODE_MCC: - chanctx_idx = RTW89_CHANCTX_0; - break; - case RTW89_ENTITY_MODE_MCC_PREPARE: - chanctx_idx = RTW89_CHANCTX_1; - break; - default: - WARN(1, "Invalid ent mode: %d\n", mode); - return -EINVAL; - } - - roc_idx = atomic_read(&hal->roc_chanctx_idx); - if (roc_idx != RTW89_CHANCTX_IDLE) - chanctx_idx = roc_idx; + entity_active = rtw89_get_entity_state(rtwdev, phy_idx); - mac_idx = RTW89_MAC_0; - phy_idx = RTW89_PHY_0; - - chan = rtw89_chan_get(rtwdev, chanctx_idx); - chan_rcd = rtw89_chan_rcd_get(rtwdev, chanctx_idx); + chan_rcd = rtw89_chan_rcd_get_by_chan(chan); rtw89_chip_set_channel_prepare(rtwdev, &bak, chan, mac_idx, phy_idx); @@ -432,17 +396,30 @@ int rtw89_set_channel(struct rtw89_dev *rtwdev) rtw89_chip_rfk_band_changed(rtwdev, phy_idx, chan); } - rtw89_set_entity_state(rtwdev, true); - return 0; + rtw89_set_entity_state(rtwdev, phy_idx, true); } -void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_chan *chan) +int rtw89_set_channel(struct rtw89_dev *rtwdev) { - const struct cfg80211_chan_def *chandef; + const struct rtw89_chan *chan; + enum rtw89_entity_mode mode; + + mode = rtw89_entity_recalc(rtwdev); + if (mode < 0 || mode >= NUM_OF_RTW89_ENTITY_MODE) { + WARN(1, "Invalid ent mode: %d\n", mode); + return -EINVAL; + } + + chan = rtw89_mgnt_chan_get(rtwdev, 0); + __rtw89_set_channel(rtwdev, chan, RTW89_MAC_0, RTW89_PHY_0); + + if (!rtwdev->support_mlo) + return 0; + + chan = rtw89_mgnt_chan_get(rtwdev, 1); + __rtw89_set_channel(rtwdev, chan, RTW89_MAC_1, RTW89_PHY_1); - chandef = rtw89_chandef_get(rtwdev, rtwvif->chanctx_idx); - rtw89_get_channel_params(chandef, chan); + return 0; } static enum rtw89_core_tx_type @@ -463,8 +440,9 @@ rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req, enum btc_pkt_type pkt_type) { - struct ieee80211_sta *sta = tx_req->sta; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct ieee80211_link_sta *link_sta; struct sk_buff *skb = tx_req->skb; struct rtw89_sta *rtwsta; u8 ampdu_num; @@ -478,21 +456,26 @@ rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev, if (!(IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU)) return; - if (!sta) { + if (!rtwsta_link) { rtw89_warn(rtwdev, "cannot set ampdu info without sta\n"); return; } tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; - rtwsta = (struct rtw89_sta *)sta->drv_priv; + rtwsta = rtwsta_link->rtwsta; + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); ampdu_num = (u8)((rtwsta->ampdu_params[tid].agg_num ? rtwsta->ampdu_params[tid].agg_num : - 4 << sta->deflink.ht_cap.ampdu_factor) - 1); + 4 << link_sta->ht_cap.ampdu_factor) - 1); desc_info->agg_en = true; - desc_info->ampdu_density = sta->deflink.ht_cap.ampdu_density; + desc_info->ampdu_density = link_sta->ht_cap.ampdu_density; desc_info->ampdu_num = ampdu_num; + + rcu_read_unlock(); } static void @@ -569,9 +552,13 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan) { struct sk_buff *skb = tx_req->skb; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = tx_info->control.vif; + struct ieee80211_bss_conf *bss_conf; u16 lowest_rate; + u16 rate; if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE || (vif && vif->p2p)) @@ -581,25 +568,35 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev, else lowest_rate = RTW89_HW_RATE_OFDM6; - if (!vif || !vif->bss_conf.basic_rates || !tx_req->sta) + if (!rtwvif_link) return lowest_rate; - return __ffs(vif->bss_conf.basic_rates) + lowest_rate; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + if (!bss_conf->basic_rates || !rtwsta_link) { + rate = lowest_rate; + goto out; + } + + rate = __ffs(bss_conf->basic_rates) + lowest_rate; + +out: + rcu_read_unlock(); + + return rate; } static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { - struct ieee80211_vif *vif = tx_req->vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_sta *rtwsta; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; - if (!sta) - return rtwvif->mac_id; + if (!rtwsta_link) + return rtwvif_link->mac_id; - rtwsta = (struct rtw89_sta *)sta->drv_priv; - return rtwsta->mac_id; + return rtwsta_link->mac_id; } static void rtw89_core_tx_update_llc_hdr(struct rtw89_dev *rtwdev, @@ -618,11 +615,10 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { const struct rtw89_chip_info *chip = rtwdev->chip; - struct ieee80211_vif *vif = tx_req->vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); struct sk_buff *skb = tx_req->skb; u8 qsel, ch_dma; @@ -631,7 +627,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, desc_info->qsel = qsel; desc_info->ch_dma = ch_dma; - desc_info->port = desc_info->hiq ? rtwvif->port : 0; + desc_info->port = desc_info->hiq ? rtwvif_link->port : 0; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->hw_ssn_sel = RTW89_MGMT_HW_SSN_SEL; desc_info->hw_seq_mode = RTW89_MGMT_HW_SEQ_MODE; @@ -701,18 +697,28 @@ __rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req, enum btc_pkt_type pkt_type) { - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct sk_buff *skb = tx_req->skb; struct ieee80211_hdr *hdr = (void *)skb->data; + struct ieee80211_link_sta *link_sta; __le16 fc = hdr->frame_control; /* AP IOT issue with EAPoL, ARP and DHCP */ if (pkt_type < PACKET_MAX) return false; - if (!sta || !sta->deflink.he_cap.has_he) + if (!rtwsta_link) + return false; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + if (!link_sta->he_cap.has_he) { + rcu_read_unlock(); return false; + } + + rcu_read_unlock(); if (!ieee80211_is_data_qos(fc)) return false; @@ -720,7 +726,7 @@ __rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev, if (skb_headroom(skb) < IEEE80211_HT_CTL_LEN) return false; - if (rtwsta && rtwsta->ra_report.might_fallback_legacy) + if (rtwsta_link && rtwsta_link->ra_report.might_fallback_legacy) return false; return true; @@ -730,8 +736,7 @@ static void __rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct sk_buff *skb = tx_req->skb; struct ieee80211_hdr *hdr = (void *)skb->data; __le16 fc = hdr->frame_control; @@ -747,7 +752,7 @@ __rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev, hdr = data; htc = data + hdr_len; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_ORDER); - *htc = rtwsta->htc_template ? rtwsta->htc_template : + *htc = rtwsta_link->htc_template ? rtwsta_link->htc_template : le32_encode_bits(RTW89_HTC_VARIANT_HE, RTW89_HTC_MASK_VARIANT) | le32_encode_bits(RTW89_HTC_VARIANT_HE_CID_CAS, RTW89_HTC_MASK_CTL_ID); @@ -761,8 +766,7 @@ rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev, enum btc_pkt_type pkt_type) { struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; - struct ieee80211_vif *vif = tx_req->vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; if (!__rtw89_core_tx_check_he_qos_htc(rtwdev, tx_req, pkt_type)) goto desc_bk; @@ -773,23 +777,25 @@ rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev, desc_info->a_ctrl_bsr = true; desc_bk: - if (!rtwvif || rtwvif->last_a_ctrl == desc_info->a_ctrl_bsr) + if (!rtwvif_link || rtwvif_link->last_a_ctrl == desc_info->a_ctrl_bsr) return; - rtwvif->last_a_ctrl = desc_info->a_ctrl_bsr; + rtwvif_link->last_a_ctrl = desc_info->a_ctrl_bsr; desc_info->bk = true; } static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { - struct ieee80211_vif *vif = tx_req->vif; - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern; - enum rtw89_chanctx_idx idx = rtwvif->chanctx_idx; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern; + enum rtw89_chanctx_idx idx = rtwvif_link->chanctx_idx; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, idx); + struct ieee80211_link_sta *link_sta; u16 lowest_rate; + u16 rate; if (rate_pattern->enable) return rate_pattern->rate; @@ -801,20 +807,31 @@ static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev, else lowest_rate = RTW89_HW_RATE_OFDM6; - if (!sta || !sta->deflink.supp_rates[chan->band_type]) + if (!rtwsta_link) return lowest_rate; - return __ffs(sta->deflink.supp_rates[chan->band_type]) + lowest_rate; + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + if (!link_sta->supp_rates[chan->band_type]) { + rate = lowest_rate; + goto out; + } + + rate = __ffs(link_sta->supp_rates[chan->band_type]) + lowest_rate; + +out: + rcu_read_unlock(); + + return rate; } static void rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { - struct ieee80211_vif *vif = tx_req->vif; - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; struct sk_buff *skb = tx_req->skb; u8 tid, tid_indicate; @@ -829,10 +846,10 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, desc_info->tid_indicate = tid_indicate; desc_info->qsel = qsel; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); - desc_info->port = desc_info->hiq ? rtwvif->port : 0; - desc_info->er_cap = rtwsta ? rtwsta->er_cap : false; - desc_info->stbc = rtwsta ? rtwsta->ra.stbc_cap : false; - desc_info->ldpc = rtwsta ? rtwsta->ra.ldpc_cap : false; + desc_info->port = desc_info->hiq ? rtwvif_link->port : 0; + desc_info->er_cap = rtwsta_link ? rtwsta_link->er_cap : false; + desc_info->stbc = rtwsta_link ? rtwsta_link->ra.stbc_cap : false; + desc_info->ldpc = rtwsta_link ? rtwsta_link->ra.ldpc_cap : false; /* enable wd_info for AMPDU */ desc_info->en_wd_info = true; @@ -907,8 +924,10 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, struct sk_buff *skb = tx_req->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (void *)skb->data; + struct rtw89_addr_cam_entry *addr_cam; enum rtw89_core_tx_type tx_type; enum btc_pkt_type pkt_type; + bool upd_wlan_hdr = false; bool is_bmc; u16 seq; @@ -916,6 +935,11 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, if (tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD) { tx_type = rtw89_core_get_tx_type(rtwdev, skb); tx_req->tx_type = tx_type; + + addr_cam = rtw89_get_addr_cam_of(tx_req->rtwvif_link, + tx_req->rtwsta_link); + if (addr_cam->valid) + upd_wlan_hdr = true; } is_bmc = (is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1)); @@ -925,6 +949,7 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, desc_info->is_bmc = is_bmc; desc_info->wd_page = true; desc_info->hiq = info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM; + desc_info->upd_wlan_hdr = upd_wlan_hdr; switch (tx_req->tx_type) { case RTW89_CORE_TX_TYPE_MGMT: @@ -1027,13 +1052,34 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev, int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel) { + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); struct rtw89_core_tx_request tx_req = {0}; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_sta_link *rtwsta_link = NULL; + struct rtw89_vif_link *rtwvif_link; int ret; + /* By default, driver writes tx via the link on HW-0. And then, + * according to links' status, HW can change tx to another link. + */ + + if (rtwsta) { + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) { + rtw89_err(rtwdev, "tx: find no sta link on HW-0\n"); + return -ENOLINK; + } + } + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "tx: find no vif link on HW-0\n"); + return -ENOLINK; + } + tx_req.skb = skb; - tx_req.sta = sta; - tx_req.vif = vif; + tx_req.rtwvif_link = rtwvif_link; + tx_req.rtwsta_link = rtwsta_link; rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true); rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true); @@ -1302,6 +1348,13 @@ static __le32 rtw89_build_txwd_body5_v2(struct rtw89_tx_desc_info *desc_info) return cpu_to_le32(dword); } +static __le32 rtw89_build_txwd_body6_v2(struct rtw89_tx_desc_info *desc_info) +{ + u32 dword = FIELD_PREP(BE_TXD_BODY6_UPD_WLAN_HDR, desc_info->upd_wlan_hdr); + + return cpu_to_le32(dword); +} + static __le32 rtw89_build_txwd_body7_v2(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(BE_TXD_BODY7_USERATE_SEL, desc_info->use_rate) | @@ -1365,6 +1418,7 @@ void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev, txwd_body->dword4 = rtw89_build_txwd_body4_v2(desc_info); txwd_body->dword5 = rtw89_build_txwd_body5_v2(desc_info); } + txwd_body->dword6 = rtw89_build_txwd_body6_v2(desc_info); txwd_body->dword7 = rtw89_build_txwd_body7_v2(desc_info); if (!desc_info->en_wd_info) @@ -1514,16 +1568,24 @@ static u8 rtw89_get_data_rate_nss(struct rtw89_dev *rtwdev, u16 data_rate) static void rtw89_core_rx_process_phy_ppdu_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; struct rtw89_rx_phy_ppdu *phy_ppdu = (struct rtw89_rx_phy_ppdu *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct rtw89_dev *rtwdev = rtwsta->rtwdev; struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_sta_link *rtwsta_link; u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; u8 ant_pos = U8_MAX; u8 evm_pos = 0; int i; - if (rtwsta->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self) + /* FIXME: For single link, taking link on HW-0 here is okay. But, when + * enabling multiple active links, we should determine the right link. + */ + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) + return; + + if (rtwsta_link->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self) return; if (hal->ant_diversity && hal->antenna_rx) { @@ -1531,22 +1593,24 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, evm_pos = ant_pos; } - ewma_rssi_add(&rtwsta->avg_rssi, phy_ppdu->rssi_avg); + ewma_rssi_add(&rtwsta_link->avg_rssi, phy_ppdu->rssi_avg); if (ant_pos < ant_num) { - ewma_rssi_add(&rtwsta->rssi[ant_pos], phy_ppdu->rssi[0]); + ewma_rssi_add(&rtwsta_link->rssi[ant_pos], phy_ppdu->rssi[0]); } else { for (i = 0; i < rtwdev->chip->rf_path_num; i++) - ewma_rssi_add(&rtwsta->rssi[i], phy_ppdu->rssi[i]); + ewma_rssi_add(&rtwsta_link->rssi[i], phy_ppdu->rssi[i]); } if (phy_ppdu->ofdm.has && (phy_ppdu->has_data || phy_ppdu->has_bcn)) { - ewma_snr_add(&rtwsta->avg_snr, phy_ppdu->ofdm.avg_snr); + ewma_snr_add(&rtwsta_link->avg_snr, phy_ppdu->ofdm.avg_snr); if (rtw89_get_data_rate_nss(rtwdev, phy_ppdu->rate) == 1) { - ewma_evm_add(&rtwsta->evm_1ss, phy_ppdu->ofdm.evm_min); + ewma_evm_add(&rtwsta_link->evm_1ss, phy_ppdu->ofdm.evm_min); } else { - ewma_evm_add(&rtwsta->evm_min[evm_pos], phy_ppdu->ofdm.evm_min); - ewma_evm_add(&rtwsta->evm_max[evm_pos], phy_ppdu->ofdm.evm_max); + ewma_evm_add(&rtwsta_link->evm_min[evm_pos], + phy_ppdu->ofdm.evm_min); + ewma_evm_add(&rtwsta_link->evm_max[evm_pos], + phy_ppdu->ofdm.evm_max); } } } @@ -1795,32 +1859,58 @@ static void rtw89_core_rx_process_phy_sts(struct rtw89_dev *rtwdev, phy_ppdu); } -static u8 rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev *rtwdev, - u8 desc_info_gi, - bool rx_status, bool eht) +static u8 rtw89_rxdesc_to_nl_he_gi(struct rtw89_dev *rtwdev, + u8 desc_info_gi, + bool rx_status) { switch (desc_info_gi) { case RTW89_GILTF_SGI_4XHE08: case RTW89_GILTF_2XHE08: case RTW89_GILTF_1XHE08: - return eht ? NL80211_RATE_INFO_EHT_GI_0_8 : - NL80211_RATE_INFO_HE_GI_0_8; + return NL80211_RATE_INFO_HE_GI_0_8; case RTW89_GILTF_2XHE16: case RTW89_GILTF_1XHE16: - return eht ? NL80211_RATE_INFO_EHT_GI_1_6 : - NL80211_RATE_INFO_HE_GI_1_6; + return NL80211_RATE_INFO_HE_GI_1_6; case RTW89_GILTF_LGI_4XHE32: - return eht ? NL80211_RATE_INFO_EHT_GI_3_2 : - NL80211_RATE_INFO_HE_GI_3_2; + return NL80211_RATE_INFO_HE_GI_3_2; default: rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info_gi); if (rx_status) - return eht ? NL80211_RATE_INFO_EHT_GI_3_2 : - NL80211_RATE_INFO_HE_GI_3_2; + return NL80211_RATE_INFO_HE_GI_3_2; return U8_MAX; } } +static u8 rtw89_rxdesc_to_nl_eht_gi(struct rtw89_dev *rtwdev, + u8 desc_info_gi, + bool rx_status) +{ + switch (desc_info_gi) { + case RTW89_GILTF_SGI_4XHE08: + case RTW89_GILTF_2XHE08: + case RTW89_GILTF_1XHE08: + return NL80211_RATE_INFO_EHT_GI_0_8; + case RTW89_GILTF_2XHE16: + case RTW89_GILTF_1XHE16: + return NL80211_RATE_INFO_EHT_GI_1_6; + case RTW89_GILTF_LGI_4XHE32: + return NL80211_RATE_INFO_EHT_GI_3_2; + default: + rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info_gi); + if (rx_status) + return NL80211_RATE_INFO_EHT_GI_3_2; + return U8_MAX; + } +} + +static u8 rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev *rtwdev, + u8 desc_info_gi, + bool rx_status, bool eht) +{ + return eht ? rtw89_rxdesc_to_nl_eht_gi(rtwdev, desc_info_gi, rx_status) : + rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info_gi, rx_status); +} + static bool rtw89_check_rx_statu_gi_match(struct ieee80211_rx_status *status, u8 gi_ltf, bool eht) @@ -1876,17 +1966,19 @@ struct rtw89_vif_rx_stats_iter_data { }; static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf, struct sk_buff *skb) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct ieee80211_trigger *tf = (struct ieee80211_trigger *)skb->data; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; u8 *pos, *end, type, tf_bw; u16 aid, tf_rua; - if (!ether_addr_equal(vif->bss_conf.bssid, tf->ta) || - rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION || - rtwvif->net_type == RTW89_NET_TYPE_NO_LINK) + if (!ether_addr_equal(bss_conf->bssid, tf->ta) || + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION || + rtwvif_link->net_type == RTW89_NET_TYPE_NO_LINK) return; type = le64_get_bits(tf->common_info, IEEE80211_TRIGGER_TYPE_MASK); @@ -1915,7 +2007,7 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev, rtwdev->stats.rx_tf_acc++; if (tf_bw == IEEE80211_TRIGGER_ULBW_160_80P80MHZ && rua <= NL80211_RATE_INFO_HE_RU_ALLOC_106) - rtwvif->pwr_diff_en = true; + rtwvif_link->pwr_diff_en = true; break; } @@ -1986,7 +2078,7 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev, ieee80211_queue_work(rtwdev->hw, &rtwdev->cancel_6ghz_probe_work); } -static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif, +static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif_link *rtwvif_link, struct ieee80211_hdr *hdr, size_t len) { struct ieee80211_mgmt *mgmt = (typeof(mgmt))hdr; @@ -1994,20 +2086,22 @@ static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif, if (len < offsetof(typeof(*mgmt), u.beacon.variable)) return; - WRITE_ONCE(rtwvif->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp)); + WRITE_ONCE(rtwvif_link->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp)); } static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_vif_rx_stats_iter_data *iter_data = data; struct rtw89_dev *rtwdev = iter_data->rtwdev; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat; struct rtw89_rx_desc_info *desc_info = iter_data->desc_info; struct sk_buff *skb = iter_data->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct rtw89_rx_phy_ppdu *phy_ppdu = iter_data->phy_ppdu; + struct ieee80211_bss_conf *bss_conf; + struct rtw89_vif_link *rtwvif_link; const u8 *bssid = iter_data->bssid; if (rtwdev->scanning && @@ -2015,33 +2109,49 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, ieee80211_is_probe_resp(hdr->frame_control))) rtw89_core_cancel_6ghz_probe_tx(rtwdev, skb); - if (!vif->bss_conf.bssid) - return; + rcu_read_lock(); + + /* FIXME: For single link, taking link on HW-0 here is okay. But, when + * enabling multiple active links, we should determine the right link. + */ + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) + goto out; + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + if (!bss_conf->bssid) + goto out; if (ieee80211_is_trigger(hdr->frame_control)) { - rtw89_stats_trigger_frame(rtwdev, vif, skb); - return; + rtw89_stats_trigger_frame(rtwdev, rtwvif_link, bss_conf, skb); + goto out; } - if (!ether_addr_equal(vif->bss_conf.bssid, bssid)) - return; + if (!ether_addr_equal(bss_conf->bssid, bssid)) + goto out; if (ieee80211_is_beacon(hdr->frame_control)) { if (vif->type == NL80211_IFTYPE_STATION && !test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) { - rtw89_vif_sync_bcn_tsf(rtwvif, hdr, skb->len); + rtw89_vif_sync_bcn_tsf(rtwvif_link, hdr, skb->len); rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu); } pkt_stat->beacon_nr++; + + if (phy_ppdu) + ewma_rssi_add(&rtwdev->phystat.bcn_rssi, phy_ppdu->rssi_avg); } - if (!ether_addr_equal(vif->addr, hdr->addr1)) - return; + if (!ether_addr_equal(bss_conf->addr, hdr->addr1)) + goto out; if (desc_info->data_rate < RTW89_HW_RATE_NR) pkt_stat->rx_rate_cnt[desc_info->data_rate]++; rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false); + +out: + rcu_read_unlock(); } static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev, @@ -2432,15 +2542,23 @@ void rtw89_core_stats_sta_rx_status_iter(void *data, struct ieee80211_sta *sta) struct rtw89_core_iter_rx_status *iter_data = (struct rtw89_core_iter_rx_status *)data; struct ieee80211_rx_status *rx_status = iter_data->rx_status; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; struct rtw89_rx_desc_info *desc_info = iter_data->desc_info; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; u8 mac_id = iter_data->mac_id; - if (mac_id != rtwsta->mac_id) + /* FIXME: For single link, taking link on HW-0 here is okay. But, when + * enabling multiple active links, we should determine the right link. + */ + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) return; - rtwsta->rx_status = *rx_status; - rtwsta->rx_hw_rate = desc_info->data_rate; + if (mac_id != rtwsta_link->mac_id) + return; + + rtwsta_link->rx_status = *rx_status; + rtwsta_link->rx_hw_rate = desc_info->data_rate; } static void rtw89_core_stats_sta_rx_status(struct rtw89_dev *rtwdev, @@ -2546,6 +2664,10 @@ static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + /* FIXME: Fix __rtw89_enter_ps_mode() to consider MLO cases. */ + if (rtwdev->support_mlo) + return RTW89_PS_MODE_NONE; + if (rtw89_disable_ps_mode || !chip->ps_mode_supported || RTW89_CHK_FW_FEATURE(NO_DEEP_PS, &rtwdev->fw)) return RTW89_PS_MODE_NONE; @@ -2658,7 +2780,7 @@ static void rtw89_core_ba_work(struct work_struct *work) list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->ba_list, list) { struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq); struct ieee80211_sta *sta = txq->sta; - struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); u8 tid = txq->tid; if (!sta) { @@ -2686,8 +2808,8 @@ skip_ba_work: spin_unlock_bh(&rtwdev->ba_lock); } -static void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta) +void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta) { struct rtw89_txq *rtwtxq, *tmp; @@ -2701,8 +2823,8 @@ static void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev, spin_unlock_bh(&rtwdev->ba_lock); } -static void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta) +void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta) { struct rtw89_txq *rtwtxq, *tmp; @@ -2718,10 +2840,10 @@ static void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev, spin_unlock_bh(&rtwdev->ba_lock); } -static void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta) +void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct sk_buff *skb, *tmp; skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) { @@ -2762,7 +2884,7 @@ static void rtw89_core_txq_check_agg(struct rtw89_dev *rtwdev, struct ieee80211_hw *hw = rtwdev->hw; struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq); struct ieee80211_sta *sta = txq->sta; - struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); if (test_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags)) return; @@ -2838,10 +2960,19 @@ static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev, bool *sched_txq, bool *reinvoke) { struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; - struct ieee80211_sta *sta = txq->sta; - struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(txq->sta); + struct rtw89_sta_link *rtwsta_link; + + if (!rtwsta) + return false; + + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) { + rtw89_err(rtwdev, "agg wait: find no link on HW-0\n"); + return false; + } - if (!sta || rtwsta->max_agg_wait <= 0) + if (rtwsta_link->max_agg_wait <= 0) return false; if (rtwdev->stats.tx_tfc_lv <= RTW89_TFC_MID) @@ -2855,7 +2986,7 @@ static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev, return false; } - if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta->max_agg_wait) { + if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta_link->max_agg_wait) { *reinvoke = true; rtwtxq->wait_cnt++; return true; @@ -2879,7 +3010,7 @@ static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac, bool *reinv ieee80211_txq_schedule_start(hw, ac); while ((txq = ieee80211_next_txq(hw, ac))) { rtwtxq = (struct rtw89_txq *)txq->drv_priv; - rtwvif = (struct rtw89_vif *)txq->vif->drv_priv; + rtwvif = vif_to_rtwvif(txq->vif); if (rtwvif->offchan) { ieee80211_return_txq(hw, txq, true); @@ -2955,16 +3086,23 @@ static void rtw89_forbid_ba_work(struct work_struct *w) static void rtw89_core_sta_pending_tx_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_vif *rtwvif_target = data, *rtwvif = rtwsta->rtwvif; - struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_vif_link *target = data; + struct rtw89_vif_link *rtwvif_link; struct sk_buff *skb, *tmp; + unsigned int link_id; int qsel, ret; - if (rtwvif->chanctx_idx != rtwvif_target->chanctx_idx) - return; + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + if (rtwvif_link->chanctx_idx == target->chanctx_idx) + goto bottom; + return; + +bottom: if (skb_queue_len(&rtwsta->roc_queue) == 0) return; @@ -2982,17 +3120,17 @@ static void rtw89_core_sta_pending_tx_iter(void *data, } static void rtw89_core_handle_sta_pending_tx(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_core_sta_pending_tx_iter, - rtwvif); + rtwvif_link); } static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool qos, bool ps) + struct rtw89_vif_link *rtwvif_link, bool qos, bool ps) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; struct sk_buff *skb; @@ -3002,7 +3140,7 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, return 0; rcu_read_lock(); - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + sta = ieee80211_find_sta(vif, vif->cfg.ap_addr); if (!sta) { ret = -EINVAL; goto out; @@ -3040,31 +3178,49 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_roc *roc = &rtwvif->roc; + struct rtw89_vif_link *rtwvif_link; struct cfg80211_chan_def roc_chan; - struct rtw89_vif *tmp; + struct rtw89_vif *tmp_vif; + u32 reg; int ret; lockdep_assert_held(&rtwdev->mutex); rtw89_leave_ips_by_hwflags(rtwdev); rtw89_leave_lps(rtwdev); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, RTW89_ROC_BY_LINK_INDEX); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "roc start: find no link on HW-%u\n", + RTW89_ROC_BY_LINK_INDEX); + return; + } + rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC); - ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, true); + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, "roc send null-1 failed: %d\n", ret); - rtw89_for_each_rtwvif(rtwdev, tmp) - if (tmp->chanctx_idx == rtwvif->chanctx_idx) - tmp->offchan = true; + rtw89_for_each_rtwvif(rtwdev, tmp_vif) { + struct rtw89_vif_link *tmp_link; + unsigned int link_id; + + rtw89_vif_for_each_link(tmp_vif, tmp_link, link_id) { + if (tmp_link->chanctx_idx == rtwvif_link->chanctx_idx) { + tmp_vif->offchan = true; + break; + } + } + } cfg80211_chandef_create(&roc_chan, &roc->chan, NL80211_CHAN_NO_HT); - rtw89_config_roc_chandef(rtwdev, rtwvif->chanctx_idx, &roc_chan); + rtw89_config_roc_chandef(rtwdev, rtwvif_link->chanctx_idx, &roc_chan); rtw89_set_channel(rtwdev); - rtw89_write32_clr(rtwdev, - rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), - B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH); + + reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx); + rtw89_write32_clr(rtwdev, reg, B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH); ieee80211_ready_on_channel(hw); cancel_delayed_work(&rtwvif->roc.roc_work); @@ -3077,7 +3233,9 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_roc *roc = &rtwvif->roc; - struct rtw89_vif *tmp; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *tmp_vif; + u32 reg; int ret; lockdep_assert_held(&rtwdev->mutex); @@ -3087,24 +3245,28 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_leave_ips_by_hwflags(rtwdev); rtw89_leave_lps(rtwdev); - rtw89_write32_mask(rtwdev, - rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), - B_AX_RX_FLTR_CFG_MASK, - rtwdev->hal.rx_fltr); + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, RTW89_ROC_BY_LINK_INDEX); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "roc end: find no link on HW-%u\n", + RTW89_ROC_BY_LINK_INDEX); + return; + } + + reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr); roc->state = RTW89_ROC_IDLE; - rtw89_config_roc_chandef(rtwdev, rtwvif->chanctx_idx, NULL); + rtw89_config_roc_chandef(rtwdev, rtwvif_link->chanctx_idx, NULL); rtw89_chanctx_proceed(rtwdev); - ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, false); + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, "roc send null-0 failed: %d\n", ret); - rtw89_for_each_rtwvif(rtwdev, tmp) - if (tmp->chanctx_idx == rtwvif->chanctx_idx) - tmp->offchan = false; + rtw89_for_each_rtwvif(rtwdev, tmp_vif) + tmp_vif->offchan = false; - rtw89_core_handle_sta_pending_tx(rtwdev, rtwvif); + rtw89_core_handle_sta_pending_tx(rtwdev, rtwvif_link); queue_work(rtwdev->txq_wq, &rtwdev->txq_work); if (hw->conf.flags & IEEE80211_CONF_IDLE) @@ -3188,39 +3350,52 @@ static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; bool tfc_changed; tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats); + rtw89_for_each_rtwvif(rtwdev, rtwvif) { rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats); - rtw89_fw_h2c_tp_offload(rtwdev, rtwvif); + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_fw_h2c_tp_offload(rtwdev, rtwvif_link); } return tfc_changed; } -static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - if ((rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION && - rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) || - rtwvif->tdls_peer) - return; - - if (rtwvif->offchan) + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) return; - if (rtwvif->stats.tx_tfc_lv == RTW89_TFC_IDLE && - rtwvif->stats.rx_tfc_lv == RTW89_TFC_IDLE) - rtw89_enter_lps(rtwdev, rtwvif, true); + rtw89_enter_lps(rtwdev, rtwvif_link, true); } static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; - rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_vif_enter_lps(rtwdev, rtwvif); + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + if (rtwvif->tdls_peer) + continue; + if (rtwvif->offchan) + continue; + + if (rtwvif->stats.tx_tfc_lv != RTW89_TFC_IDLE || + rtwvif->stats.rx_tfc_lv != RTW89_TFC_IDLE) + continue; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_vif_enter_lps(rtwdev, rtwvif_link); + } } static void rtw89_core_rfk_track(struct rtw89_dev *rtwdev) @@ -3234,14 +3409,16 @@ static void rtw89_core_rfk_track(struct rtw89_dev *rtwdev) rtw89_chip_rfk_track(rtwdev); } -void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_P2P_PS_CHANGE); else - rtw89_process_p2p_ps(rtwdev, vif); + rtw89_process_p2p_ps(rtwdev, rtwvif_link, bss_conf); } void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev, @@ -3326,7 +3503,8 @@ void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits) } int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx) + struct rtw89_sta_link *rtwsta_link, u8 tid, + u8 *cam_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_cam_info *cam_info = &rtwdev->cam_info; @@ -3363,7 +3541,7 @@ int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev, } entry->tid = tid; - list_add_tail(&entry->list, &rtwsta->ba_cam_list); + list_add_tail(&entry->list, &rtwsta_link->ba_cam_list); *cam_idx = idx; @@ -3371,7 +3549,8 @@ int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev, } int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx) + struct rtw89_sta_link *rtwsta_link, u8 tid, + u8 *cam_idx) { struct rtw89_cam_info *cam_info = &rtwdev->cam_info; struct rtw89_ba_cam_entry *entry = NULL, *tmp; @@ -3379,7 +3558,7 @@ int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, lockdep_assert_held(&rtwdev->mutex); - list_for_each_entry_safe(entry, tmp, &rtwsta->ba_cam_list, list) { + list_for_each_entry_safe(entry, tmp, &rtwsta_link->ba_cam_list, list) { if (entry->tid != tid) continue; @@ -3396,24 +3575,25 @@ int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, #define RTW89_TYPE_MAPPING(_type) \ case NL80211_IFTYPE_ ## _type: \ - rtwvif->wifi_role = RTW89_WIFI_ROLE_ ## _type; \ + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_ ## _type; \ break -void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc) +void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_bss_conf *bss_conf; switch (vif->type) { case NL80211_IFTYPE_STATION: if (vif->p2p) - rtwvif->wifi_role = RTW89_WIFI_ROLE_P2P_CLIENT; + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_P2P_CLIENT; else - rtwvif->wifi_role = RTW89_WIFI_ROLE_STATION; + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_STATION; break; case NL80211_IFTYPE_AP: if (vif->p2p) - rtwvif->wifi_role = RTW89_WIFI_ROLE_P2P_GO; + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_P2P_GO; else - rtwvif->wifi_role = RTW89_WIFI_ROLE_AP; + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_AP; break; RTW89_TYPE_MAPPING(ADHOC); RTW89_TYPE_MAPPING(MONITOR); @@ -3426,23 +3606,27 @@ void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc) switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - rtwvif->net_type = RTW89_NET_TYPE_AP_MODE; - rtwvif->self_role = RTW89_SELF_ROLE_AP; + rtwvif_link->net_type = RTW89_NET_TYPE_AP_MODE; + rtwvif_link->self_role = RTW89_SELF_ROLE_AP; break; case NL80211_IFTYPE_ADHOC: - rtwvif->net_type = RTW89_NET_TYPE_AD_HOC; - rtwvif->self_role = RTW89_SELF_ROLE_CLIENT; + rtwvif_link->net_type = RTW89_NET_TYPE_AD_HOC; + rtwvif_link->self_role = RTW89_SELF_ROLE_CLIENT; break; case NL80211_IFTYPE_STATION: if (assoc) { - rtwvif->net_type = RTW89_NET_TYPE_INFRA; - rtwvif->trigger = vif->bss_conf.he_support; + rtwvif_link->net_type = RTW89_NET_TYPE_INFRA; + + rcu_read_lock(); + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + rtwvif_link->trigger = bss_conf->he_support; + rcu_read_unlock(); } else { - rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; - rtwvif->trigger = false; + rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK; + rtwvif_link->trigger = false; } - rtwvif->self_role = RTW89_SELF_ROLE_CLIENT; - rtwvif->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL; + rtwvif_link->self_role = RTW89_SELF_ROLE_CLIENT; + rtwvif_link->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL; break; case NL80211_IFTYPE_MONITOR: break; @@ -3452,137 +3636,110 @@ void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc) } } -int rtw89_core_sta_add(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); struct rtw89_hal *hal = &rtwdev->hal; u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; int i; int ret; - rtwsta->rtwdev = rtwdev; - rtwsta->rtwvif = rtwvif; - rtwsta->prev_rssi = 0; - INIT_LIST_HEAD(&rtwsta->ba_cam_list); - skb_queue_head_init(&rtwsta->roc_queue); - - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - rtw89_core_txq_init(rtwdev, sta->txq[i]); - - ewma_rssi_init(&rtwsta->avg_rssi); - ewma_snr_init(&rtwsta->avg_snr); - ewma_evm_init(&rtwsta->evm_1ss); + rtwsta_link->prev_rssi = 0; + INIT_LIST_HEAD(&rtwsta_link->ba_cam_list); + ewma_rssi_init(&rtwsta_link->avg_rssi); + ewma_snr_init(&rtwsta_link->avg_snr); + ewma_evm_init(&rtwsta_link->evm_1ss); for (i = 0; i < ant_num; i++) { - ewma_rssi_init(&rtwsta->rssi[i]); - ewma_evm_init(&rtwsta->evm_min[i]); - ewma_evm_init(&rtwsta->evm_max[i]); + ewma_rssi_init(&rtwsta_link->rssi[i]); + ewma_evm_init(&rtwsta_link->evm_min[i]); + ewma_evm_init(&rtwsta_link->evm_max[i]); } if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - /* for station mode, assign the mac_id from itself */ - rtwsta->mac_id = rtwvif->mac_id; - /* must do rtw89_reg_6ghz_recalc() before rfk channel */ - ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true); + ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, true); if (ret) return ret; - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_CONN_START); - rtw89_chip_rfk_channel(rtwdev, rtwvif); + rtw89_chip_rfk_channel(rtwdev, rtwvif_link); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { - rtwsta->mac_id = rtw89_acquire_mac_id(rtwdev); - if (rtwsta->mac_id == RTW89_MAX_MAC_ID_NUM) - return -ENOSPC; - - ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta->mac_id, false); + ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta_link->mac_id, false); if (ret) { - rtw89_release_mac_id(rtwdev, rtwsta->mac_id); rtw89_warn(rtwdev, "failed to send h2c macid pause\n"); return ret; } - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link, RTW89_ROLE_CREATE); if (ret) { - rtw89_release_mac_id(rtwdev, rtwsta->mac_id); rtw89_warn(rtwdev, "failed to send h2c role info\n"); return ret; } - ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) return ret; - ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) return ret; - - rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); } return 0; } -int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); if (vif->type == NL80211_IFTYPE_STATION) - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, false); - - rtwdev->total_sta_assoc--; - if (sta->tdls) - rtwvif->tdls_peer--; - rtwsta->disassoc = true; + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, false); return 0; } -int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_disconnect(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); int ret; - rtw89_mac_bf_monitor_calc(rtwdev, sta, true); - rtw89_mac_bf_disassoc(rtwdev, vif, sta); - rtw89_core_free_sta_pending_ba(rtwdev, sta); - rtw89_core_free_sta_pending_forbid_ba(rtwdev, sta); - rtw89_core_free_sta_pending_roc_tx(rtwdev, sta); + rtw89_mac_bf_monitor_calc(rtwdev, rtwsta_link, true); + rtw89_mac_bf_disassoc(rtwdev, rtwvif_link, rtwsta_link); if (vif->type == NL80211_IFTYPE_AP || sta->tdls) - rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam); + rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta_link->addr_cam); if (sta->tdls) - rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam); + rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta_link->bssid_cam); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - rtw89_vif_type_mapping(vif, false); - rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, true); + rtw89_vif_type_mapping(rtwvif_link, false); + rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif_link, true); } - ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cmac table\n"); return ret; } - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, true); + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, true); if (ret) { rtw89_warn(rtwdev, "failed to send h2c join info\n"); return ret; } /* update cam aid mac_id net_type */ - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; @@ -3591,106 +3748,114 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, return ret; } -int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta); + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); + struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif_link, + rtwsta_link); const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); int ret; if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { if (sta->tdls) { - ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, sta->addr); + struct ieee80211_link_sta *link_sta; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif_link, bssid_cam, + link_sta->addr); if (ret) { rtw89_warn(rtwdev, "failed to send h2c init bssid cam for TDLS\n"); + rcu_read_unlock(); return ret; } + + rcu_read_unlock(); } - ret = rtw89_cam_init_addr_cam(rtwdev, &rtwsta->addr_cam, bssid_cam); + ret = rtw89_cam_init_addr_cam(rtwdev, &rtwsta_link->addr_cam, bssid_cam); if (ret) { rtw89_warn(rtwdev, "failed to send h2c init addr cam\n"); return ret; } } - ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cmac table\n"); return ret; } - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, false); + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, false); if (ret) { rtw89_warn(rtwdev, "failed to send h2c join info\n"); return ret; } /* update cam aid mac_id net_type */ - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; } - rtwdev->total_sta_assoc++; - if (sta->tdls) - rtwvif->tdls_peer++; - rtw89_phy_ra_assoc(rtwdev, sta); - rtw89_mac_bf_assoc(rtwdev, vif, sta); - rtw89_mac_bf_monitor_calc(rtwdev, sta, false); + rtw89_phy_ra_assoc(rtwdev, rtwsta_link); + rtw89_mac_bf_assoc(rtwdev, rtwvif_link, rtwsta_link); + rtw89_mac_bf_monitor_calc(rtwdev, rtwsta_link, false); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ieee80211_bss_conf *bss_conf; + + rcu_read_lock(); + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); if (bss_conf->he_support && !(bss_conf->he_oper.params & IEEE80211_HE_OPERATION_ER_SU_DISABLE)) - rtwsta->er_cap = true; + rtwsta_link->er_cap = true; - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, + rcu_read_unlock(); + + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_CONN_END); - rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template, chan); - rtw89_phy_ul_tb_assoc(rtwdev, rtwvif); + rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta_link->htc_template, chan); + rtw89_phy_ul_tb_assoc(rtwdev, rtwvif_link); - ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id); + ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id); if (ret) { rtw89_warn(rtwdev, "failed to send h2c general packet\n"); return ret; } - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); } return ret; } -int rtw89_core_sta_remove(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); int ret; if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - rtw89_reg_6ghz_recalc(rtwdev, rtwvif, false); - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, + rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, false); + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_DIS_CONN); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { - rtw89_release_mac_id(rtwdev, rtwsta->mac_id); - - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link, RTW89_ROLE_REMOVE); if (ret) { rtw89_warn(rtwdev, "failed to send h2c role info\n"); return ret; } - - rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); } return 0; @@ -4152,15 +4317,16 @@ static void rtw89_core_ppdu_sts_init(struct rtw89_dev *rtwdev) void rtw89_core_update_beacon_work(struct work_struct *work) { struct rtw89_dev *rtwdev; - struct rtw89_vif *rtwvif = container_of(work, struct rtw89_vif, - update_beacon_work); + struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link, + update_beacon_work); - if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE) + if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE) return; - rtwdev = rtwvif->rtwdev; + rtwdev = rtwvif_link->rtwvif->rtwdev; + mutex_lock(&rtwdev->mutex); - rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); mutex_unlock(&rtwdev->mutex); } @@ -4266,8 +4432,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) rtw89_phy_dm_init(rtwdev); - rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); - rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); + rtw89_mac_cfg_ppdu_status_bands(rtwdev, true); + rtw89_mac_update_rts_threshold(rtwdev); rtw89_tas_reset(rtwdev); @@ -4355,6 +4521,168 @@ void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id) clear_bit(mac_id, rtwdev->mac_id_map); } +void rtw89_init_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + u8 mac_id, u8 port) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 support_link_num = chip->support_link_num; + u8 support_mld_num = 0; + unsigned int link_id; + u8 index; + + bitmap_zero(rtwvif->links_inst_map, __RTW89_MLD_MAX_LINK_NUM); + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) + rtwvif->links[link_id] = NULL; + + rtwvif->rtwdev = rtwdev; + + if (rtwdev->support_mlo) { + rtwvif->links_inst_valid_num = support_link_num; + support_mld_num = chip->support_macid_num / support_link_num; + } else { + rtwvif->links_inst_valid_num = 1; + } + + for (index = 0; index < rtwvif->links_inst_valid_num; index++) { + struct rtw89_vif_link *inst = &rtwvif->links_inst[index]; + + inst->rtwvif = rtwvif; + inst->mac_id = mac_id + index * support_mld_num; + inst->mac_idx = RTW89_MAC_0 + index; + inst->phy_idx = RTW89_PHY_0 + index; + + /* multi-link use the same port id on different HW bands */ + inst->port = port; + } +} + +void rtw89_init_sta(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, u8 mac_id) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 support_link_num = chip->support_link_num; + u8 support_mld_num = 0; + unsigned int link_id; + u8 index; + + bitmap_zero(rtwsta->links_inst_map, __RTW89_MLD_MAX_LINK_NUM); + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) + rtwsta->links[link_id] = NULL; + + rtwsta->rtwdev = rtwdev; + rtwsta->rtwvif = rtwvif; + + if (rtwdev->support_mlo) { + rtwsta->links_inst_valid_num = support_link_num; + support_mld_num = chip->support_macid_num / support_link_num; + } else { + rtwsta->links_inst_valid_num = 1; + } + + for (index = 0; index < rtwsta->links_inst_valid_num; index++) { + struct rtw89_sta_link *inst = &rtwsta->links_inst[index]; + + inst->rtwvif_link = &rtwvif->links_inst[index]; + + inst->rtwsta = rtwsta; + inst->mac_id = mac_id + index * support_mld_num; + } +} + +struct rtw89_vif_link *rtw89_vif_set_link(struct rtw89_vif *rtwvif, + unsigned int link_id) +{ + struct rtw89_vif_link *rtwvif_link = rtwvif->links[link_id]; + u8 index; + int ret; + + if (rtwvif_link) + return rtwvif_link; + + index = find_first_zero_bit(rtwvif->links_inst_map, + rtwvif->links_inst_valid_num); + if (index == rtwvif->links_inst_valid_num) { + ret = -EBUSY; + goto err; + } + + rtwvif_link = &rtwvif->links_inst[index]; + rtwvif_link->link_id = link_id; + + set_bit(index, rtwvif->links_inst_map); + rtwvif->links[link_id] = rtwvif_link; + return rtwvif_link; + +err: + rtw89_err(rtwvif->rtwdev, "vif (link_id %u) failed to set link: %d\n", + link_id, ret); + return NULL; +} + +void rtw89_vif_unset_link(struct rtw89_vif *rtwvif, unsigned int link_id) +{ + struct rtw89_vif_link **container = &rtwvif->links[link_id]; + struct rtw89_vif_link *link = *container; + u8 index; + + if (!link) + return; + + index = rtw89_vif_link_inst_get_index(link); + clear_bit(index, rtwvif->links_inst_map); + *container = NULL; +} + +struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta, + unsigned int link_id) +{ + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_vif_link *rtwvif_link = rtwvif->links[link_id]; + struct rtw89_sta_link *rtwsta_link = rtwsta->links[link_id]; + u8 index; + int ret; + + if (rtwsta_link) + return rtwsta_link; + + if (!rtwvif_link) { + ret = -ENOLINK; + goto err; + } + + index = rtw89_vif_link_inst_get_index(rtwvif_link); + if (test_bit(index, rtwsta->links_inst_map)) { + ret = -EBUSY; + goto err; + } + + rtwsta_link = &rtwsta->links_inst[index]; + rtwsta_link->link_id = link_id; + + set_bit(index, rtwsta->links_inst_map); + rtwsta->links[link_id] = rtwsta_link; + return rtwsta_link; + +err: + rtw89_err(rtwsta->rtwdev, "sta (link_id %u) failed to set link: %d\n", + link_id, ret); + return NULL; +} + +void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id) +{ + struct rtw89_sta_link **container = &rtwsta->links[link_id]; + struct rtw89_sta_link *link = *container; + u8 index; + + if (!link) + return; + + index = rtw89_sta_link_inst_get_index(link); + clear_bit(index, rtwsta->links_inst_map); + *container = NULL; +} + int rtw89_core_init(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -4444,39 +4772,45 @@ void rtw89_core_deinit(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_core_deinit); -void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, const u8 *mac_addr, bool hw_scan) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); rtwdev->scanning = true; rtw89_leave_lps(rtwdev); if (hw_scan) rtw89_leave_ips_by_hwflags(rtwdev); - ether_addr_copy(rtwvif->mac_addr, mac_addr); - rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, chan->band_type); - rtw89_chip_rfk_scan(rtwdev, rtwvif, true); + ether_addr_copy(rtwvif_link->mac_addr, mac_addr); + rtw89_btc_ntfy_scan_start(rtwdev, rtwvif_link->phy_idx, chan->band_type); + rtw89_chip_rfk_scan(rtwdev, rtwvif_link, true); rtw89_hci_recalc_int_mit(rtwdev); rtw89_phy_config_edcca(rtwdev, true); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, mac_addr); + rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, mac_addr); } void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, bool hw_scan) + struct rtw89_vif_link *rtwvif_link, bool hw_scan) { - struct rtw89_vif *rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL; + struct ieee80211_bss_conf *bss_conf; - if (!rtwvif) + if (!rtwvif_link) return; - ether_addr_copy(rtwvif->mac_addr, vif->addr); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ether_addr_copy(rtwvif_link->mac_addr, bss_conf->addr); + + rcu_read_unlock(); + + rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); - rtw89_chip_rfk_scan(rtwdev, rtwvif, false); - rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0); + rtw89_chip_rfk_scan(rtwdev, rtwvif_link, false); + rtw89_btc_ntfy_scan_finish(rtwdev, rtwvif_link->phy_idx); rtw89_phy_config_edcca(rtwdev, false); rtwdev->scanning = false; @@ -4513,11 +4847,20 @@ static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev) static void rtw89_core_setup_phycap(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; + rtwdev->hal.support_cckpd = !(rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv <= CHIP_CBV) && !(rtwdev->chip->chip_id == RTL8852B && rtwdev->hal.cv <= CHIP_CAV); rtwdev->hal.support_igi = rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv <= CHIP_CBV; + + if (test_bit(RTW89_QUIRK_THERMAL_PROT_120C, rtwdev->quirks)) + rtwdev->hal.thermal_prot_th = chip->thermal_th[1]; + else if (test_bit(RTW89_QUIRK_THERMAL_PROT_110C, rtwdev->quirks)) + rtwdev->hal.thermal_prot_th = chip->thermal_th[0]; + else + rtwdev->hal.thermal_prot_th = 0; } static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev) @@ -4688,17 +5031,39 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_chip_info_setup); +void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct rtw89_chip_info *chip = rtwdev->chip; + struct ieee80211_bss_conf *bss_conf; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + if (!bss_conf->he_support || !vif->cfg.assoc) { + rcu_read_unlock(); + return; + } + + rcu_read_unlock(); + + if (chip->ops->set_txpwr_ul_tb_offset) + chip->ops->set_txpwr_ul_tb_offset(rtwdev, 0, rtwvif_link->mac_idx); +} + static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + u8 n = rtwdev->support_mlo ? chip->support_link_num : 1; struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_hal *hal = &rtwdev->hal; int ret; int tx_headroom = IEEE80211_HT_CTL_LEN; - hw->vif_data_size = sizeof(struct rtw89_vif); - hw->sta_data_size = sizeof(struct rtw89_sta); + hw->vif_data_size = struct_size_t(struct rtw89_vif, links_inst, n); + hw->sta_data_size = struct_size_t(struct rtw89_sta, links_inst, n); hw->txq_data_size = sizeof(struct rtw89_txq); hw->chanctx_data_size = sizeof(struct rtw89_chanctx_cfg); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 4ed9034fdb46..5ad32eacd0d5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -829,6 +829,8 @@ enum rtw89_phy_idx { RTW89_PHY_MAX }; +#define __RTW89_MLD_MAX_LINK_NUM 2 + enum rtw89_chanctx_idx { RTW89_CHANCTX_0 = 0, RTW89_CHANCTX_1 = 1, @@ -1160,14 +1162,15 @@ struct rtw89_tx_desc_info { bool er_cap; bool stbc; bool ldpc; + bool upd_wlan_hdr; }; struct rtw89_core_tx_request { enum rtw89_core_tx_type tx_type; struct sk_buff *skb; - struct ieee80211_vif *vif; - struct ieee80211_sta *sta; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; struct rtw89_tx_desc_info desc_info; }; @@ -1350,7 +1353,6 @@ struct rtw89_btc_wl_smap { u32 connecting: 1; u32 roaming: 1; u32 dbccing: 1; - u32 transacting: 1; u32 _4way: 1; u32 rf_off: 1; u32 lps: 2; @@ -2937,6 +2939,7 @@ struct rtw89_btc_dm { u8 wl_pre_agc: 2; u8 wl_lna2: 1; + u8 freerun_chk: 1; u8 wl_pre_agc_rb: 2; u8 bt_select: 2; /* 0:s0, 1:s1, 2:s0 & s1, refer to enum btc_bt_index */ u8 slot_req_more: 1; @@ -2975,6 +2978,8 @@ enum rtw89_btc_btf_fw_event { BTF_EVNT_BT_REG = 3, BTF_EVNT_CX_RUNINFO = 4, BTF_EVNT_BT_PSD = 5, + BTF_EVNT_BT_DEV_INFO = 6, /* fwc2hfunc > 0 */ + BTF_EVNT_BT_LEAUDIO_INFO = 7, /* fwc2hfunc > 1 */ BTF_EVNT_BUF_OVERFLOW, BTF_EVNT_C2H_LOOPBACK, BTF_EVNT_MAX, @@ -3141,6 +3146,7 @@ struct rtw89_btc_ver { u8 fcxinit; u8 fwevntrptl; + u8 fwc2hfunc; u8 drvinfo_type; u16 info_buf; u8 max_role_num; @@ -3354,12 +3360,13 @@ struct rtw89_sec_cam_entry { u8 key[32]; }; -struct rtw89_sta { +struct rtw89_sta_link { + struct rtw89_sta *rtwsta; + unsigned int link_id; + u8 mac_id; - bool disassoc; bool er_cap; - struct rtw89_dev *rtwdev; - struct rtw89_vif *rtwvif; + struct rtw89_vif_link *rtwvif_link; struct rtw89_ra_info ra; struct rtw89_ra_report ra_report; int max_agg_wait; @@ -3370,15 +3377,12 @@ struct rtw89_sta { struct ewma_evm evm_1ss; struct ewma_evm evm_min[RF_PATH_MAX]; struct ewma_evm evm_max[RF_PATH_MAX]; - struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS]; - DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS); struct ieee80211_rx_status rx_status; u16 rx_hw_rate; __le32 htc_template; struct rtw89_addr_cam_entry addr_cam; /* AP mode or TDLS peer only */ struct rtw89_bssid_cam_entry bssid_cam; /* TDLS peer only */ struct list_head ba_cam_list; - struct sk_buff_head roc_queue; bool use_cfg_mask; struct cfg80211_bitrate_mask mask; @@ -3424,6 +3428,8 @@ enum rtw89_roc_state { RTW89_ROC_MGMT, }; +#define RTW89_ROC_BY_LINK_INDEX 0 + struct rtw89_roc { struct ieee80211_channel chan; struct delayed_work roc_work; @@ -3460,10 +3466,10 @@ struct rtw89_p2p_noa_setter { u8 noa_index; }; -struct rtw89_vif { - struct list_head list; - struct rtw89_dev *rtwdev; - struct rtw89_roc roc; +struct rtw89_vif_link { + struct rtw89_vif *rtwvif; + unsigned int link_id; + bool chanctx_assigned; /* only valid when running with chanctx_ops */ enum rtw89_chanctx_idx chanctx_idx; enum rtw89_reg_6ghz_power reg_6ghz_power; @@ -3473,7 +3479,6 @@ struct rtw89_vif { u8 port; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - __be32 ip_addr; u8 phy_idx; u8 mac_idx; u8 net_type; @@ -3484,7 +3489,6 @@ struct rtw89_vif { u8 hit_rule; u8 last_noa_nr; u64 sync_bcn_tsf; - bool offchan; bool trigger; bool lsig_txop; u8 tgt_ind; @@ -3498,15 +3502,11 @@ struct rtw89_vif { bool pre_pwr_diff_en; bool pwr_diff_en; u8 def_tri_idx; - u32 tdls_peer; struct work_struct update_beacon_work; struct rtw89_addr_cam_entry addr_cam; struct rtw89_bssid_cam_entry bssid_cam; struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS]; - struct rtw89_traffic_stats stats; struct rtw89_phy_rate_pattern rate_pattern; - struct cfg80211_scan_request *scan_req; - struct ieee80211_scan_ies *scan_ies; struct list_head general_pkt_list; struct rtw89_p2p_noa_setter p2p_noa; }; @@ -3599,11 +3599,11 @@ struct rtw89_chip_ops { void (*rfk_hw_init)(struct rtw89_dev *rtwdev); void (*rfk_init)(struct rtw89_dev *rtwdev); void (*rfk_init_late)(struct rtw89_dev *rtwdev); - void (*rfk_channel)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); + void (*rfk_channel)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void (*rfk_band_changed)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan); - void (*rfk_scan)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + void (*rfk_scan)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool start); void (*rfk_track)(struct rtw89_dev *rtwdev); void (*power_trim)(struct rtw89_dev *rtwdev); @@ -3646,23 +3646,25 @@ struct rtw89_chip_ops { u32 *tx_en, enum rtw89_sch_tx_sel sel); int (*resume_sch_tx)(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en); int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_default_cmac_tbl)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_assoc_cmac_tbl)(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_ampdu_cmac_tbl)(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_update_beacon)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); - int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link); + int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params); void (*btc_set_rfe)(struct rtw89_dev *rtwdev); @@ -4245,6 +4247,7 @@ struct rtw89_chip_info { u8 wde_qempty_acq_grpnum; u8 wde_qempty_mgq_grpsel; u32 rf_base_addr[2]; + u8 thermal_th[2]; u8 support_macid_num; u8 support_link_num; u8 support_chanctx_num; @@ -4445,6 +4448,8 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V0, RTW89_FW_FEATURE_WOW_REASON_V1, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, + RTW89_FW_FEATURE_RFK_RXDCK_V0, + RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, }; struct rtw89_fw_suit { @@ -4511,11 +4516,14 @@ enum rtw89_fw_mss_dev_type { }; struct rtw89_fw_secure { - bool secure_boot; + bool secure_boot: 1; + bool can_mss_v1: 1; + bool can_mss_v0: 1; u32 sb_sel_mgn; u8 mss_dev_type; u8 mss_cust_idx; u8 mss_key_num; + u8 mss_idx; /* v0 */ }; struct rtw89_fw_info { @@ -4561,7 +4569,7 @@ enum rtw89_sar_subband { RTW89_SAR_2GHZ_SUBBAND, RTW89_SAR_5GHZ_SUBBAND_1_2, /* U-NII-1 and U-NII-2 */ RTW89_SAR_5GHZ_SUBBAND_2_E, /* U-NII-2-Extended */ - RTW89_SAR_5GHZ_SUBBAND_3, /* U-NII-3 */ + RTW89_SAR_5GHZ_SUBBAND_3_4, /* U-NII-3 and U-NII-4 */ RTW89_SAR_6GHZ_SUBBAND_5_L, /* U-NII-5 lower part */ RTW89_SAR_6GHZ_SUBBAND_5_H, /* U-NII-5 higher part */ RTW89_SAR_6GHZ_SUBBAND_6, /* U-NII-6 */ @@ -4623,7 +4631,7 @@ enum rtw89_chanctx_changes { }; enum rtw89_entity_mode { - RTW89_ENTITY_MODE_SCC, + RTW89_ENTITY_MODE_SCC_OR_SMLD, RTW89_ENTITY_MODE_MCC_PREPARE, RTW89_ENTITY_MODE_MCC, @@ -4632,6 +4640,16 @@ enum rtw89_entity_mode { RTW89_ENTITY_MODE_UNHANDLED = -ESRCH, }; +#define RTW89_MAX_INTERFACE_NUM 2 + +/* only valid when running with chanctx_ops */ +struct rtw89_entity_mgnt { + struct list_head active_list; + struct rtw89_vif *active_roles[RTW89_MAX_INTERFACE_NUM]; + enum rtw89_chanctx_idx chanctx_tbl[RTW89_MAX_INTERFACE_NUM] + [__RTW89_MLD_MAX_LINK_NUM]; +}; + struct rtw89_chanctx { struct cfg80211_chan_def chandef; struct rtw89_chan chan; @@ -4650,8 +4668,12 @@ struct rtw89_edcca_bak { enum rtw89_dm_type { RTW89_DM_DYNAMIC_EDCCA, + RTW89_DM_THERMAL_PROTECT, }; +#define RTW89_THERMAL_PROT_LV_MAX 5 +#define RTW89_THERMAL_PROT_STEP 19 /* -19% for each level */ + struct rtw89_hal { u32 rx_fltr; u8 cv; @@ -4672,12 +4694,16 @@ struct rtw89_hal { struct rtw89_chanctx chanctx[NUM_OF_RTW89_CHANCTX]; struct cfg80211_chan_def roc_chandef; - bool entity_active; + bool entity_active[RTW89_PHY_MAX]; bool entity_pause; enum rtw89_entity_mode entity_mode; + struct rtw89_entity_mgnt entity_mgnt; struct rtw89_edcca_bak edcca_bak; u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */ + + u8 thermal_prot_th; + u8 thermal_prot_lv; /* 0 ~ RTW89_THERMAL_PROT_LV_MAX */ }; #define RTW89_MAX_MAC_ID_NUM 128 @@ -4710,10 +4736,22 @@ enum rtw89_flags { enum rtw89_quirks { RTW89_QUIRK_PCI_BER, + RTW89_QUIRK_THERMAL_PROT_120C, + RTW89_QUIRK_THERMAL_PROT_110C, NUM_OF_RTW89_QUIRKS, }; +enum rtw89_custid { + RTW89_CUSTID_NONE, + RTW89_CUSTID_ACER, + RTW89_CUSTID_AMD, + RTW89_CUSTID_ASUS, + RTW89_CUSTID_DELL, + RTW89_CUSTID_HP, + RTW89_CUSTID_LENOVO, +}; + enum rtw89_pkt_drop_sel { RTW89_PKT_DROP_SEL_MACID_BE_ONCE, RTW89_PKT_DROP_SEL_MACID_BK_ONCE, @@ -4750,6 +4788,8 @@ DECLARE_EWMA(thermal, 4, 4); struct rtw89_phy_stat { struct ewma_thermal avg_thermal[RF_PATH_MAX]; + u8 last_thermal_max; + struct ewma_rssi bcn_rssi; struct rtw89_pkt_stat cur_pkt_stat; struct rtw89_pkt_stat last_pkt_stat; }; @@ -4791,13 +4831,17 @@ enum rtw89_rfk_chs_nrs { RTW89_RFK_CHS_NR = __RTW89_RFK_CHS_NR_V1, }; -struct rtw89_rfk_mcc_info { +struct rtw89_rfk_mcc_info_data { u8 ch[RTW89_RFK_CHS_NR]; u8 band[RTW89_RFK_CHS_NR]; u8 bw[RTW89_RFK_CHS_NR]; u8 table_idx; }; +struct rtw89_rfk_mcc_info { + struct rtw89_rfk_mcc_info_data data[2]; +}; + #define RTW89_IQK_CHS_NR 2 #define RTW89_IQK_PATH_NR 4 @@ -4902,6 +4946,7 @@ struct rtw89_agc_gaincode_set { #define IGI_RSSI_TH_NUM 5 #define FA_TH_NUM 4 +#define TIA_LNA_OP1DB_NUM 8 #define LNA_GAIN_NUM 7 #define TIA_GAIN_NUM 2 struct rtw89_dig_info { @@ -5196,7 +5241,7 @@ struct rtw89_early_h2c { }; struct rtw89_hw_scan_info { - struct ieee80211_vif *scanning_vif; + struct rtw89_vif_link *scanning_vif; struct list_head pkt_list[NUM_NL80211_BANDS]; struct rtw89_chan op_chan; bool abort; @@ -5371,7 +5416,7 @@ struct rtw89_wow_aoac_report { }; struct rtw89_wow_param { - struct ieee80211_vif *wow_vif; + struct rtw89_vif_link *rtwvif_link; DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM); struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM]; struct rtw89_wow_key_info key_info; @@ -5408,7 +5453,7 @@ struct rtw89_mcc_policy { }; struct rtw89_mcc_role { - struct rtw89_vif *rtwvif; + struct rtw89_vif_link *rtwvif_link; struct rtw89_mcc_policy policy; struct rtw89_mcc_limit limit; @@ -5509,6 +5554,7 @@ struct rtw89_dev { struct rtw89_efuse efuse; struct rtw89_traffic_stats stats; struct rtw89_rfe_data *rfe_data; + enum rtw89_custid custid; /* ensures exclusive access from mac80211 callbacks */ struct mutex mutex; @@ -5608,6 +5654,122 @@ struct rtw89_dev { u8 priv[] __aligned(sizeof(void *)); }; +struct rtw89_vif { + struct rtw89_dev *rtwdev; + struct list_head list; + struct list_head mgnt_entry; + + u8 mac_addr[ETH_ALEN]; + __be32 ip_addr; + + struct rtw89_traffic_stats stats; + u32 tdls_peer; + + struct ieee80211_scan_ies *scan_ies; + struct cfg80211_scan_request *scan_req; + + struct rtw89_roc roc; + bool offchan; + + u8 links_inst_valid_num; + DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM); + struct rtw89_vif_link *links[IEEE80211_MLD_MAX_NUM_LINKS]; + struct rtw89_vif_link links_inst[] __counted_by(links_inst_valid_num); +}; + +static inline bool rtw89_vif_assign_link_is_valid(struct rtw89_vif_link **rtwvif_link, + const struct rtw89_vif *rtwvif, + unsigned int link_id) +{ + *rtwvif_link = rtwvif->links[link_id]; + return !!*rtwvif_link; +} + +#define rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) \ + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) \ + if (rtw89_vif_assign_link_is_valid(&(rtwvif_link), rtwvif, link_id)) + +struct rtw89_sta { + struct rtw89_dev *rtwdev; + struct rtw89_vif *rtwvif; + + bool disassoc; + + struct sk_buff_head roc_queue; + + struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS]; + DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS); + + u8 links_inst_valid_num; + DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM); + struct rtw89_sta_link *links[IEEE80211_MLD_MAX_NUM_LINKS]; + struct rtw89_sta_link links_inst[] __counted_by(links_inst_valid_num); +}; + +static inline bool rtw89_sta_assign_link_is_valid(struct rtw89_sta_link **rtwsta_link, + const struct rtw89_sta *rtwsta, + unsigned int link_id) +{ + *rtwsta_link = rtwsta->links[link_id]; + return !!*rtwsta_link; +} + +#define rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) \ + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) \ + if (rtw89_sta_assign_link_is_valid(&(rtwsta_link), rtwsta, link_id)) + +static inline u8 rtw89_vif_get_main_macid(struct rtw89_vif *rtwvif) +{ + /* const after init, so no need to check if active first */ + return rtwvif->links_inst[0].mac_id; +} + +static inline u8 rtw89_vif_get_main_port(struct rtw89_vif *rtwvif) +{ + /* const after init, so no need to check if active first */ + return rtwvif->links_inst[0].port; +} + +static inline struct rtw89_vif_link * +rtw89_vif_get_link_inst(struct rtw89_vif *rtwvif, u8 index) +{ + if (index >= rtwvif->links_inst_valid_num || + !test_bit(index, rtwvif->links_inst_map)) + return NULL; + return &rtwvif->links_inst[index]; +} + +static inline +u8 rtw89_vif_link_inst_get_index(struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + + return rtwvif_link - rtwvif->links_inst; +} + +static inline u8 rtw89_sta_get_main_macid(struct rtw89_sta *rtwsta) +{ + /* const after init, so no need to check if active first */ + return rtwsta->links_inst[0].mac_id; +} + +static inline struct rtw89_sta_link * +rtw89_sta_get_link_inst(struct rtw89_sta *rtwsta, u8 index) +{ + if (index >= rtwsta->links_inst_valid_num || + !test_bit(index, rtwsta->links_inst_map)) + return NULL; + return &rtwsta->links_inst[index]; +} + +static inline +u8 rtw89_sta_link_inst_get_index(struct rtw89_sta_link *rtwsta_link) +{ + struct rtw89_sta *rtwsta = rtwsta_link->rtwsta; + + return rtwsta_link - rtwsta->links_inst; +} + static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { @@ -5972,9 +6134,26 @@ static inline struct ieee80211_vif *rtwvif_to_vif_safe(struct rtw89_vif *rtwvif) return rtwvif ? rtwvif_to_vif(rtwvif) : NULL; } +static inline +struct ieee80211_vif *rtwvif_link_to_vif(struct rtw89_vif_link *rtwvif_link) +{ + return rtwvif_to_vif(rtwvif_link->rtwvif); +} + +static inline +struct ieee80211_vif *rtwvif_link_to_vif_safe(struct rtw89_vif_link *rtwvif_link) +{ + return rtwvif_link ? rtwvif_link_to_vif(rtwvif_link) : NULL; +} + +static inline struct rtw89_vif *vif_to_rtwvif(struct ieee80211_vif *vif) +{ + return (struct rtw89_vif *)vif->drv_priv; +} + static inline struct rtw89_vif *vif_to_rtwvif_safe(struct ieee80211_vif *vif) { - return vif ? (struct rtw89_vif *)vif->drv_priv : NULL; + return vif ? vif_to_rtwvif(vif) : NULL; } static inline struct ieee80211_sta *rtwsta_to_sta(struct rtw89_sta *rtwsta) @@ -5989,11 +6168,88 @@ static inline struct ieee80211_sta *rtwsta_to_sta_safe(struct rtw89_sta *rtwsta) return rtwsta ? rtwsta_to_sta(rtwsta) : NULL; } +static inline +struct ieee80211_sta *rtwsta_link_to_sta(struct rtw89_sta_link *rtwsta_link) +{ + return rtwsta_to_sta(rtwsta_link->rtwsta); +} + +static inline +struct ieee80211_sta *rtwsta_link_to_sta_safe(struct rtw89_sta_link *rtwsta_link) +{ + return rtwsta_link ? rtwsta_link_to_sta(rtwsta_link) : NULL; +} + +static inline struct rtw89_sta *sta_to_rtwsta(struct ieee80211_sta *sta) +{ + return (struct rtw89_sta *)sta->drv_priv; +} + static inline struct rtw89_sta *sta_to_rtwsta_safe(struct ieee80211_sta *sta) { - return sta ? (struct rtw89_sta *)sta->drv_priv : NULL; + return sta ? sta_to_rtwsta(sta) : NULL; +} + +static inline struct ieee80211_bss_conf * +__rtw89_vif_rcu_dereference_link(struct rtw89_vif_link *rtwvif_link, bool *nolink) +{ + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct ieee80211_bss_conf *bss_conf; + + bss_conf = rcu_dereference(vif->link_conf[rtwvif_link->link_id]); + if (unlikely(!bss_conf)) { + *nolink = true; + return &vif->bss_conf; + } + + *nolink = false; + return bss_conf; +} + +#define rtw89_vif_rcu_dereference_link(rtwvif_link, assert) \ +({ \ + typeof(rtwvif_link) p = rtwvif_link; \ + struct ieee80211_bss_conf *bss_conf; \ + bool nolink; \ + \ + bss_conf = __rtw89_vif_rcu_dereference_link(p, &nolink); \ + if (unlikely(nolink) && (assert)) \ + rtw89_err(p->rtwvif->rtwdev, \ + "%s: cannot find exact bss_conf for link_id %u\n",\ + __func__, p->link_id); \ + bss_conf; \ +}) + +static inline struct ieee80211_link_sta * +__rtw89_sta_rcu_dereference_link(struct rtw89_sta_link *rtwsta_link, bool *nolink) +{ + struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); + struct ieee80211_link_sta *link_sta; + + link_sta = rcu_dereference(sta->link[rtwsta_link->link_id]); + if (unlikely(!link_sta)) { + *nolink = true; + return &sta->deflink; + } + + *nolink = false; + return link_sta; } +#define rtw89_sta_rcu_dereference_link(rtwsta_link, assert) \ +({ \ + typeof(rtwsta_link) p = rtwsta_link; \ + struct ieee80211_link_sta *link_sta; \ + bool nolink; \ + \ + link_sta = __rtw89_sta_rcu_dereference_link(p, &nolink); \ + if (unlikely(nolink) && (assert)) \ + rtw89_err(p->rtwsta->rtwdev, \ + "%s: cannot find exact link_sta for link_id %u\n",\ + __func__, p->link_id); \ + link_sta; \ +}) + static inline u8 rtw89_hw_to_rate_info_bw(enum rtw89_bandwidth hw_bw) { if (hw_bw == RTW89_CHANNEL_WIDTH_160) @@ -6078,29 +6334,29 @@ enum nl80211_he_ru_alloc rtw89_he_rua_to_ru_alloc(u16 rua) } static inline -struct rtw89_addr_cam_entry *rtw89_get_addr_cam_of(struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) +struct rtw89_addr_cam_entry *rtw89_get_addr_cam_of(struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - if (rtwsta) { - struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); + if (rtwsta_link) { + struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) - return &rtwsta->addr_cam; + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) + return &rtwsta_link->addr_cam; } - return &rtwvif->addr_cam; + return &rtwvif_link->addr_cam; } static inline -struct rtw89_bssid_cam_entry *rtw89_get_bssid_cam_of(struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) +struct rtw89_bssid_cam_entry *rtw89_get_bssid_cam_of(struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - if (rtwsta) { - struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); + if (rtwsta_link) { + struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); if (sta->tdls) - return &rtwsta->bssid_cam; + return &rtwsta_link->bssid_cam; } - return &rtwvif->bssid_cam; + return &rtwvif_link->bssid_cam; } static inline @@ -6157,13 +6413,21 @@ const struct rtw89_chan_rcd *rtw89_chan_rcd_get(struct rtw89_dev *rtwdev, } static inline +const struct rtw89_chan_rcd *rtw89_chan_rcd_get_by_chan(const struct rtw89_chan *chan) +{ + const struct rtw89_chanctx *chanctx = + container_of_const(chan, struct rtw89_chanctx, chan); + + return &chanctx->rcd; +} + +static inline const struct rtw89_chan *rtw89_scan_chan_get(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; - if (rtwvif) - return rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); + if (rtwvif_link) + return rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); else return rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); } @@ -6240,12 +6504,12 @@ static inline void rtw89_chip_rfk_init_late(struct rtw89_dev *rtwdev) } static inline void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->ops->rfk_channel) - chip->ops->rfk_channel(rtwdev, rtwvif); + chip->ops->rfk_channel(rtwdev, rtwvif_link); } static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev, @@ -6259,12 +6523,12 @@ static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev, } static inline void rtw89_chip_rfk_scan(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool start) + struct rtw89_vif_link *rtwvif_link, bool start) { const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->ops->rfk_scan) - chip->ops->rfk_scan(rtwdev, rtwvif, start); + chip->ops->rfk_scan(rtwdev, rtwvif_link, start); } static inline void rtw89_chip_rfk_track(struct rtw89_dev *rtwdev) @@ -6279,8 +6543,12 @@ static inline void rtw89_chip_set_txpwr_ctrl(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; - if (chip->ops->set_txpwr_ctrl) - chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_0); + if (!chip->ops->set_txpwr_ctrl) + return; + + chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_0); + if (rtwdev->dbcc_en) + chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_1); } static inline void rtw89_chip_power_trim(struct rtw89_dev *rtwdev) @@ -6291,8 +6559,8 @@ static inline void rtw89_chip_power_trim(struct rtw89_dev *rtwdev) chip->ops->power_trim(rtwdev); } -static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx phy_idx) +static inline void __rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -6300,6 +6568,13 @@ static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev, chip->ops->init_txpwr_unit(rtwdev, phy_idx); } +static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev) +{ + __rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0); + if (rtwdev->dbcc_en) + __rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_1); +} + static inline u8 rtw89_chip_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) { @@ -6347,20 +6622,6 @@ static inline void rtw89_chip_cfg_txrx_path(struct rtw89_dev *rtwdev) chip->ops->cfg_txrx_path(rtwdev); } -static inline -void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif) -{ - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - const struct rtw89_chip_info *chip = rtwdev->chip; - - if (!vif->bss_conf.he_support || !vif->cfg.assoc) - return; - - if (chip->ops->set_txpwr_ul_tb_offset) - chip->ops->set_txpwr_ul_tb_offset(rtwdev, 0, rtwvif->mac_idx); -} - static inline void rtw89_chip_digital_pwr_comp(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -6457,14 +6718,14 @@ int rtw89_chip_resume_sch_tx(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en) static inline int rtw89_chip_h2c_dctl_sec_cam(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; if (!chip->ops->h2c_dctl_sec_cam) return 0; - return chip->ops->h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + return chip->ops->h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link); } static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) @@ -6479,13 +6740,14 @@ static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) return hdr->addr3; } -static inline bool rtw89_sta_has_beamformer_cap(struct ieee80211_sta *sta) +static inline +bool rtw89_sta_has_beamformer_cap(struct ieee80211_link_sta *link_sta) { - if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) || - (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] & + if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) || + (link_sta->he_cap.he_cap_elem.phy_cap_info[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) || - (sta->deflink.he_cap.he_cap_elem.phy_cap_info[4] & + (link_sta->he_cap.he_cap_elem.phy_cap_info[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) return true; return false; @@ -6605,21 +6867,21 @@ void rtw89_core_napi_start(struct rtw89_dev *rtwdev); void rtw89_core_napi_stop(struct rtw89_dev *rtwdev); int rtw89_core_napi_init(struct rtw89_dev *rtwdev); void rtw89_core_napi_deinit(struct rtw89_dev *rtwdev); -int rtw89_core_sta_add(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rtw89_core_sta_remove(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); +int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); +int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); +int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); +int rtw89_core_sta_link_disconnect(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); +int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); void rtw89_core_set_tid_config(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, struct cfg80211_tid_config *tid_config); @@ -6635,22 +6897,40 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device, void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev); u8 rtw89_acquire_mac_id(struct rtw89_dev *rtwdev); void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id); +void rtw89_init_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + u8 mac_id, u8 port); +void rtw89_init_sta(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, u8 mac_id); +struct rtw89_vif_link *rtw89_vif_set_link(struct rtw89_vif *rtwvif, + unsigned int link_id); +void rtw89_vif_unset_link(struct rtw89_vif *rtwvif, unsigned int link_id); +struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta, + unsigned int link_id); +void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id); void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev); void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef); void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef, struct rtw89_chan *chan); int rtw89_set_channel(struct rtw89_dev *rtwdev); -void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_chan *chan); u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size); void rtw89_core_release_bit_map(unsigned long *addr, u8 bit); void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits); int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx); + struct rtw89_sta_link *rtwsta_link, u8 tid, + u8 *cam_idx); int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx); -void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc); + struct rtw89_sta_link *rtwsta_link, u8 tid, + u8 *cam_idx); +void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta); +void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta); +void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta); +void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc); int rtw89_chip_info_setup(struct rtw89_dev *rtwdev); +void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate); int rtw89_regd_setup(struct rtw89_dev *rtwdev); int rtw89_regd_init(struct rtw89_dev *rtwdev, @@ -6667,13 +6947,15 @@ void rtw89_core_update_beacon_work(struct work_struct *work); void rtw89_roc_work(struct work_struct *work); void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); -void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, const u8 *mac_addr, bool hw_scan); void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, bool hw_scan); -int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool hw_scan); +int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool active); -void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf); void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event); #endif diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 29f85210f919..6abd88fa80ba 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3506,7 +3506,9 @@ out: return count; } -static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) +static void rtw89_sta_link_info_get_iter(struct seq_file *m, + struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) { static const char * const he_gi_str[] = { [NL80211_RATE_INFO_HE_GI_0_8] = "0.8", @@ -3518,20 +3520,26 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) [NL80211_RATE_INFO_EHT_GI_1_6] = "1.6", [NL80211_RATE_INFO_EHT_GI_3_2] = "3.2", }; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rate_info *rate = &rtwsta->ra_report.txrate; - struct ieee80211_rx_status *status = &rtwsta->rx_status; - struct seq_file *m = (struct seq_file *)data; - struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rate_info *rate = &rtwsta_link->ra_report.txrate; + struct ieee80211_rx_status *status = &rtwsta_link->rx_status; struct rtw89_hal *hal = &rtwdev->hal; u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; bool ant_asterisk = hal->tx_path_diversity || hal->ant_diversity; + struct ieee80211_link_sta *link_sta; u8 evm_min, evm_max, evm_1ss; + u16 max_rc_amsdu_len; u8 rssi; u8 snr; int i; - seq_printf(m, "TX rate [%d]: ", rtwsta->mac_id); + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + max_rc_amsdu_len = link_sta->agg.max_rc_amsdu_len; + + rcu_read_unlock(); + + seq_printf(m, "TX rate [%u, %u]: ", rtwsta_link->mac_id, rtwsta_link->link_id); if (rate->flags & RATE_INFO_FLAGS_MCS) seq_printf(m, "HT MCS-%d%s", rate->mcs, @@ -3549,13 +3557,13 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) eht_gi_str[rate->eht_gi] : "N/A"); else seq_printf(m, "Legacy %d", rate->legacy); - seq_printf(m, "%s", rtwsta->ra_report.might_fallback_legacy ? " FB_G" : ""); + seq_printf(m, "%s", rtwsta_link->ra_report.might_fallback_legacy ? " FB_G" : ""); seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(rate->bw)); - seq_printf(m, "\t(hw_rate=0x%x)", rtwsta->ra_report.hw_rate); - seq_printf(m, "\t==> agg_wait=%d (%d)\n", rtwsta->max_agg_wait, - sta->deflink.agg.max_rc_amsdu_len); + seq_printf(m, " (hw_rate=0x%x)", rtwsta_link->ra_report.hw_rate); + seq_printf(m, " ==> agg_wait=%d (%d)\n", rtwsta_link->max_agg_wait, + max_rc_amsdu_len); - seq_printf(m, "RX rate [%d]: ", rtwsta->mac_id); + seq_printf(m, "RX rate [%u, %u]: ", rtwsta_link->mac_id, rtwsta_link->link_id); switch (status->encoding) { case RX_ENC_LEGACY: @@ -3582,24 +3590,24 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) break; } seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(status->bw)); - seq_printf(m, "\t(hw_rate=0x%x)\n", rtwsta->rx_hw_rate); + seq_printf(m, " (hw_rate=0x%x)\n", rtwsta_link->rx_hw_rate); - rssi = ewma_rssi_read(&rtwsta->avg_rssi); + rssi = ewma_rssi_read(&rtwsta_link->avg_rssi); seq_printf(m, "RSSI: %d dBm (raw=%d, prev=%d) [", - RTW89_RSSI_RAW_TO_DBM(rssi), rssi, rtwsta->prev_rssi); + RTW89_RSSI_RAW_TO_DBM(rssi), rssi, rtwsta_link->prev_rssi); for (i = 0; i < ant_num; i++) { - rssi = ewma_rssi_read(&rtwsta->rssi[i]); + rssi = ewma_rssi_read(&rtwsta_link->rssi[i]); seq_printf(m, "%d%s%s", RTW89_RSSI_RAW_TO_DBM(rssi), ant_asterisk && (hal->antenna_tx & BIT(i)) ? "*" : "", i + 1 == ant_num ? "" : ", "); } seq_puts(m, "]\n"); - evm_1ss = ewma_evm_read(&rtwsta->evm_1ss); + evm_1ss = ewma_evm_read(&rtwsta_link->evm_1ss); seq_printf(m, "EVM: [%2u.%02u, ", evm_1ss >> 2, (evm_1ss & 0x3) * 25); for (i = 0; i < (hal->ant_diversity ? 2 : 1); i++) { - evm_min = ewma_evm_read(&rtwsta->evm_min[i]); - evm_max = ewma_evm_read(&rtwsta->evm_max[i]); + evm_min = ewma_evm_read(&rtwsta_link->evm_min[i]); + evm_max = ewma_evm_read(&rtwsta_link->evm_max[i]); seq_printf(m, "%s(%2u.%02u, %2u.%02u)", i == 0 ? "" : " ", evm_min >> 2, (evm_min & 0x3) * 25, @@ -3607,10 +3615,22 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) } seq_puts(m, "]\t"); - snr = ewma_snr_read(&rtwsta->avg_snr); + snr = ewma_snr_read(&rtwsta_link->avg_snr); seq_printf(m, "SNR: %u\n", snr); } +static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) +{ + struct seq_file *m = (struct seq_file *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) + rtw89_sta_link_info_get_iter(m, rtwdev, rtwsta_link); +} + static void rtw89_debug_append_rx_rate(struct seq_file *m, struct rtw89_pkt_stat *pkt_stat, enum rtw89_hw_rate first_rate, int len) @@ -3652,14 +3672,22 @@ static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v) struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_rx_rate_cnt_info *info; + struct rtw89_hal *hal = &rtwdev->hal; enum rtw89_hw_rate first_rate; + u8 rssi; int i; - seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d), RX: %u [%u] Mbps (lv: %d)\n", - stats->tx_throughput, stats->tx_throughput_raw, stats->tx_tfc_lv, + rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi); + + seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d", + stats->tx_throughput, stats->tx_throughput_raw, stats->tx_tfc_lv); + if (hal->thermal_prot_lv) + seq_printf(m, ", duty: %d%%", + 100 - hal->thermal_prot_lv * RTW89_THERMAL_PROT_STEP); + seq_printf(m, "), RX: %u [%u] Mbps (lv: %d)\n", stats->rx_throughput, stats->rx_throughput_raw, stats->rx_tfc_lv); - seq_printf(m, "Beacon: %u, TF: %u\n", pkt_stat->beacon_nr, - stats->rx_tf_periodic); + seq_printf(m, "Beacon: %u (%d dBm), TF: %u\n", pkt_stat->beacon_nr, + RTW89_RSSI_RAW_TO_DBM(rssi), stats->rx_tf_periodic); seq_printf(m, "Avg packet length: TX=%u, RX=%u\n", stats->tx_avg_len, stats->rx_avg_len); @@ -3737,28 +3765,41 @@ static void rtw89_dump_pkt_offload(struct seq_file *m, struct list_head *pkt_lis seq_puts(m, "\n"); } +static void rtw89_vif_link_ids_get(struct seq_file *m, u8 *mac, + struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam; + + seq_printf(m, " [%u] %pM\n", rtwvif_link->mac_id, rtwvif_link->mac_addr); + seq_printf(m, "\tlink_id=%u\n", rtwvif_link->link_id); + seq_printf(m, "\tbssid_cam_idx=%u\n", bssid_cam->bssid_cam_idx); + rtw89_dump_addr_cam(m, rtwdev, &rtwvif_link->addr_cam); + rtw89_dump_pkt_offload(m, &rtwvif_link->general_pkt_list, + "\tpkt_ofld[GENERAL]: "); +} + static void rtw89_vif_ids_get_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_dev *rtwdev = rtwvif->rtwdev; struct seq_file *m = (struct seq_file *)data; - struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; - seq_printf(m, "VIF [%d] %pM\n", rtwvif->mac_id, rtwvif->mac_addr); - seq_printf(m, "\tbssid_cam_idx=%u\n", bssid_cam->bssid_cam_idx); - rtw89_dump_addr_cam(m, rtwdev, &rtwvif->addr_cam); - rtw89_dump_pkt_offload(m, &rtwvif->general_pkt_list, "\tpkt_ofld[GENERAL]: "); + seq_printf(m, "VIF %pM\n", rtwvif->mac_addr); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_vif_link_ids_get(m, mac, rtwdev, rtwvif_link); } -static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_sta *rtwsta) +static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = rtwsta->rtwvif; - struct rtw89_dev *rtwdev = rtwvif->rtwdev; struct rtw89_ba_cam_entry *entry; bool first = true; - list_for_each_entry(entry, &rtwsta->ba_cam_list, list) { + list_for_each_entry(entry, &rtwsta_link->ba_cam_list, list) { if (first) { seq_puts(m, "\tba_cam "); first = false; @@ -3771,16 +3812,36 @@ static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_sta *rtwsta) seq_puts(m, "\n"); } +static void rtw89_sta_link_ids_get(struct seq_file *m, + struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) +{ + struct ieee80211_link_sta *link_sta; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + seq_printf(m, " [%u] %pM\n", rtwsta_link->mac_id, link_sta->addr); + + rcu_read_unlock(); + + seq_printf(m, "\tlink_id=%u\n", rtwsta_link->link_id); + rtw89_dump_addr_cam(m, rtwdev, &rtwsta_link->addr_cam); + rtw89_dump_ba_cam(m, rtwdev, rtwsta_link); +} + static void rtw89_sta_ids_get_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_dev *rtwdev = rtwsta->rtwdev; struct seq_file *m = (struct seq_file *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; - seq_printf(m, "STA [%d] %pM %s\n", rtwsta->mac_id, sta->addr, - sta->tdls ? "(TDLS)" : ""); - rtw89_dump_addr_cam(m, rtwdev, &rtwsta->addr_cam); - rtw89_dump_ba_cam(m, rtwsta); + seq_printf(m, "STA %pM %s\n", sta->addr, sta->tdls ? "(TDLS)" : ""); + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) + rtw89_sta_link_ids_get(m, rtwdev, rtwsta_link); } static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v) @@ -3830,6 +3891,7 @@ static const struct rtw89_disabled_dm_info { const char *name; } rtw89_disabled_dm_infos[] = { DM_INFO(DYNAMIC_EDCCA), + DM_INFO(THERMAL_PROTECT), }; static int diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index e1236079a84a..6c6c763510af 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -11,11 +11,38 @@ #define EF_CV_MASK GENMASK(7, 4) #define EF_CV_INV 15 +#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0) +#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4) +#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0) +#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6) + +#define EFUSE_EXTERNALPN_ADDR_AX 0x5EC +#define EFUSE_CUSTOMER_ADDR_AX 0x5ED +#define EFUSE_SERIALNUM_ADDR_AX 0x5ED + +#define EFUSE_B1_EXTERNALPN_MASK GENMASK(7, 0) +#define EFUSE_B2_CUSTOMER_MASK GENMASK(3, 0) +#define EFUSE_B2_SERIALNUM_MASK GENMASK(6, 4) + +#define OTP_KEY_INFO_NUM 2 + +static const u8 otp_key_info_externalPN[OTP_KEY_INFO_NUM] = {0x0, 0x0}; +static const u8 otp_key_info_customer[OTP_KEY_INFO_NUM] = {0x0, 0x1}; +static const u8 otp_key_info_serialNum[OTP_KEY_INFO_NUM] = {0x0, 0x1}; + enum rtw89_efuse_bank { RTW89_EFUSE_BANK_WIFI, RTW89_EFUSE_BANK_BT, }; +enum rtw89_efuse_mss_dev_type { + MSS_DEV_TYPE_FWSEC_DEF = 0xF, + MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC, + MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA, + MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9, + MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6, +}; + static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev, enum rtw89_efuse_bank bank) { @@ -354,3 +381,126 @@ int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *ecv) return 0; } EXPORT_SYMBOL(rtw89_read_efuse_ver); + +static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type) +{ + switch (mss_dev_type) { + case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX: + mss_dev_type = 0x0; + break; + case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB: + mss_dev_type = 0x1; + break; + case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB: + mss_dev_type = 0x2; + break; + case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX: + mss_dev_type = 0x3; + break; + case MSS_DEV_TYPE_FWSEC_DEF: + mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF; + break; + default: + rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type); + mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV; + break; + } + + return mss_dev_type; +} + +int rtw89_efuse_recognize_mss_info_v1(struct rtw89_dev *rtwdev, u8 b1, u8 b2) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u8 mss_dev_type; + + if (chip->chip_id == RTL8852B && b1 == 0xFF && b2 == 0x6E) { + mss_dev_type = MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB; + sec->mss_cust_idx = 0; + sec->mss_key_num = 0; + + goto mss_dev_type; + } + + mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK); + sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) | + u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4); + sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK); + +mss_dev_type: + sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type); + if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) { + rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type); + return -ENOENT; + } + + sec->can_mss_v1 = true; + + return 0; +} + +static +int rtw89_efuse_recognize_mss_index_v0(struct rtw89_dev *rtwdev, u8 b1, u8 b2) +{ + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u8 externalPN; + u8 serialNum; + u8 customer; + u8 i; + + externalPN = 0xFF - u8_get_bits(b1, EFUSE_B1_EXTERNALPN_MASK); + customer = 0xF - u8_get_bits(b2, EFUSE_B2_CUSTOMER_MASK); + serialNum = 0x7 - u8_get_bits(b2, EFUSE_B2_SERIALNUM_MASK); + + for (i = 0; i < OTP_KEY_INFO_NUM; i++) { + if (externalPN == otp_key_info_externalPN[i] && + customer == otp_key_info_customer[i] && + serialNum == otp_key_info_serialNum[i]) { + sec->mss_idx = i; + sec->can_mss_v0 = true; + return 0; + } + } + + return -ENOENT; +} + +int rtw89_efuse_read_fw_secure_ax(struct rtw89_dev *rtwdev) +{ + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u32 sec_addr = EFUSE_EXTERNALPN_ADDR_AX; + u32 sec_size = 2; + u8 sec_map[2]; + u8 b1, b2; + int ret; + + ret = rtw89_dump_physical_efuse_map(rtwdev, sec_map, + sec_addr, sec_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump secsel map\n"); + return ret; + } + + b1 = sec_map[0]; + b2 = sec_map[1]; + + if (b1 == 0xFF && b2 == 0xFF) + return 0; + + rtw89_efuse_recognize_mss_index_v0(rtwdev, b1, b2); + rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2); + if (!sec->can_mss_v1 && !sec->can_mss_v0) + goto out; + + sec->secure_boot = true; + +out: + rtw89_debug(rtwdev, RTW89_DBG_FW, + "MSS secure_boot=%d(%d/%d) dev_type=%d cust_idx=%d key_num=%d mss_index=%d\n", + sec->secure_boot, sec->can_mss_v0, sec->can_mss_v1, + sec->mss_dev_type, sec->mss_cust_idx, + sec->mss_key_num, sec->mss_idx); + + return 0; +} diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index 72416f56a071..a96fc1044791 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -23,6 +23,8 @@ int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev); int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev); int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle); int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); +int rtw89_efuse_recognize_mss_info_v1(struct rtw89_dev *rtwdev, u8 b1, u8 b2); +int rtw89_efuse_read_fw_secure_ax(struct rtw89_dev *rtwdev); int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c index 0be26d5fdf7c..64768923b0f0 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse_be.c +++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c @@ -8,11 +8,7 @@ #include "reg.h" #define EFUSE_EXTERNALPN_ADDR_BE 0x1580 -#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0) -#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4) #define EFUSE_SERIALNUM_ADDR_BE 0x1581 -#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0) -#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6) #define EFUSE_SB_CRYP_SEL_ADDR 0x1582 #define EFUSE_SB_CRYP_SEL_SIZE 2 #define EFUSE_SB_CRYP_SEL_DEFAULT 0xFFFF @@ -20,14 +16,6 @@ #define EFUSE_SEC_BE_START 0x1580 #define EFUSE_SEC_BE_SIZE 4 -enum rtw89_efuse_mss_dev_type { - MSS_DEV_TYPE_FWSEC_DEF = 0xF, - MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC, - MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA, - MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9, - MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6, -}; - static const u32 sb_sel_mgn[SB_SEL_MGN_MAX_SIZE] = { 0x8000100, 0xC000180 }; @@ -477,33 +465,6 @@ static u16 get_sb_cryp_sel_idx(u16 sb_cryp_sel) return sb_cryp_sel_v + low_bit; } -static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type) -{ - switch (mss_dev_type) { - case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX: - mss_dev_type = 0x0; - break; - case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB: - mss_dev_type = 0x1; - break; - case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB: - mss_dev_type = 0x2; - break; - case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX: - mss_dev_type = 0x3; - break; - case MSS_DEV_TYPE_FWSEC_DEF: - mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF; - break; - default: - rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type); - mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV; - break; - } - - return mss_dev_type; -} - int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) { struct rtw89_fw_secure *sec = &rtwdev->fw.sec; @@ -511,7 +472,6 @@ int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) u32 sec_size = EFUSE_SEC_BE_SIZE; u16 sb_cryp_sel, sb_cryp_sel_idx; u8 sec_map[EFUSE_SEC_BE_SIZE]; - u8 mss_dev_type; u8 b1, b2; int ret; @@ -538,16 +498,9 @@ int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) b1 = sec_map[EFUSE_EXTERNALPN_ADDR_BE - sec_addr]; b2 = sec_map[EFUSE_SERIALNUM_ADDR_BE - sec_addr]; - mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK); - sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) | - u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4); - sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK); - - sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type); - if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) { - rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type); + ret = rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2); + if (ret) goto out; - } sec->secure_boot = true; @@ -559,4 +512,3 @@ out: return 0; } -EXPORT_SYMBOL(rtw89_efuse_read_fw_secure_be); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d9b0e7ebe619..2191c037d72e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -56,6 +56,11 @@ static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb); static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_wait_info *wait, unsigned int cond); +static int __parse_security_section(struct rtw89_dev *rtwdev, + struct rtw89_fw_bin_info *info, + struct rtw89_fw_hdr_section_info *section_info, + const void *content, + u32 *mssc_len); static struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len, bool header) @@ -124,13 +129,16 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le struct rtw89_fw_bin_info *info) { const struct rtw89_fw_hdr *fw_hdr = (const struct rtw89_fw_hdr *)fw; + const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_fw_hdr_section_info *section_info; + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; const struct rtw89_fw_dynhdr_hdr *fwdynhdr; const struct rtw89_fw_hdr_section *section; const u8 *fw_end = fw + len; const u8 *bin; u32 base_hdr_len; - u32 mssc_len = 0; + u32 mssc_len; + int ret; u32 i; if (!info) @@ -139,6 +147,7 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM); base_hdr_len = struct_size(fw_hdr, sections, info->section_num); info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR); + info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_W7_IDMEM_SHARE_MODE); if (info->dynamic_hdr_en) { info->hdr_len = le32_get_bits(fw_hdr->w3, FW_HDR_W3_LEN); @@ -161,26 +170,47 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le section = &fw_hdr->sections[i]; section_info->type = le32_get_bits(section->w1, FWSECTION_HDR_W1_SECTIONTYPE); - if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { - section_info->mssc = - le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC); - mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; - } else { - section_info->mssc = 0; - } - section_info->len = le32_get_bits(section->w1, FWSECTION_HDR_W1_SEC_SIZE); + if (le32_get_bits(section->w1, FWSECTION_HDR_W1_CHECKSUM)) section_info->len += FWDL_SECTION_CHKSUM_LEN; section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_W1_REDL); section_info->dladdr = le32_get_bits(section->w0, FWSECTION_HDR_W0_DL_ADDR) & 0x1fffffff; section_info->addr = bin; - bin += section_info->len; + + if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { + section_info->mssc = + le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC); + + ret = __parse_security_section(rtwdev, info, section_info, + bin, &mssc_len); + if (ret) + return ret; + + if (sec->secure_boot && chip->chip_id == RTL8852B) + section_info->len_override = 960; + } else { + section_info->mssc = 0; + mssc_len = 0; + } + + rtw89_debug(rtwdev, RTW89_DBG_FW, + "section[%d] type=%d len=0x%-6x mssc=%d mssc_len=%d addr=%tx\n", + i, section_info->type, section_info->len, + section_info->mssc, mssc_len, bin - fw); + rtw89_debug(rtwdev, RTW89_DBG_FW, + " ignore=%d key_addr=%p (0x%tx) key_len=%d key_idx=%d\n", + section_info->ignore, section_info->key_addr, + section_info->key_addr ? + section_info->key_addr - section_info->addr : 0, + section_info->key_len, section_info->key_idx); + + bin += section_info->len + mssc_len; section_info++; } - if (fw_end != bin + mssc_len) { + if (fw_end != bin) { rtw89_err(rtwdev, "[ERR]fw bin size\n"); return -EINVAL; } @@ -235,7 +265,6 @@ static int __get_mssc_key_idx(struct rtw89_dev *rtwdev, static int __parse_formatted_mssc(struct rtw89_dev *rtwdev, struct rtw89_fw_bin_info *info, struct rtw89_fw_hdr_section_info *section_info, - const struct rtw89_fw_hdr_section_v1 *section, const void *content, u32 *mssc_len) { @@ -318,18 +347,15 @@ ignore: static int __parse_security_section(struct rtw89_dev *rtwdev, struct rtw89_fw_bin_info *info, struct rtw89_fw_hdr_section_info *section_info, - const struct rtw89_fw_hdr_section_v1 *section, const void *content, u32 *mssc_len) { + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; int ret; - section_info->mssc = - le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC); - - if (section_info->mssc == FORMATTED_MSSC) { + if ((section_info->mssc & FORMATTED_MSSC_MASK) == FORMATTED_MSSC) { ret = __parse_formatted_mssc(rtwdev, info, section_info, - section, content, mssc_len); + content, mssc_len); if (ret) return -EINVAL; } else { @@ -337,6 +363,14 @@ static int __parse_security_section(struct rtw89_dev *rtwdev, if (info->dsp_checksum) *mssc_len += section_info->mssc * FWDL_SECURITY_CHKSUM_LEN; + if (sec->secure_boot) { + if (sec->mss_idx >= section_info->mssc) + return -EFAULT; + section_info->key_addr = content + section_info->len + + sec->mss_idx * FWDL_SECURITY_SIGLEN; + section_info->key_len = FWDL_SECURITY_SIGLEN; + } + info->secure_section_exist = true; } @@ -361,6 +395,7 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le info->dsp_checksum = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_DSP_CHKSUM); base_hdr_len = struct_size(fw_hdr, sections, info->section_num); info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_DYN_HDR); + info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_IDMEM_SHARE_MODE); if (info->dynamic_hdr_en) { info->hdr_len = le32_get_bits(fw_hdr->w5, FW_HDR_V1_W5_HDR_SIZE); @@ -394,8 +429,11 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le section_info->addr = bin; if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { + section_info->mssc = + le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC); + ret = __parse_security_section(rtwdev, info, section_info, - section, bin, &mssc_len); + bin, &mssc_len); if (ret) return ret; } else { @@ -665,11 +703,13 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 37, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 38, 0, NO_PACKET_DROP), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), + __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER), @@ -687,6 +727,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 12, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, RFK_PRE_NOTIFY_V0), + __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 42, 0, RFK_RXDCK_V0), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -1152,9 +1193,24 @@ static u32 __rtw89_fw_download_tweak_hdr_v0(struct rtw89_dev *rtwdev, struct rtw89_fw_bin_info *info, struct rtw89_fw_hdr *fw_hdr) { + struct rtw89_fw_hdr_section_info *section_info; + struct rtw89_fw_hdr_section *section; + int i; + le32p_replace_bits(&fw_hdr->w7, FWDL_SECTION_PER_PKT_LEN, FW_HDR_W7_PART_SIZE); + for (i = 0; i < info->section_num; i++) { + section_info = &info->section_info[i]; + + if (!section_info->len_override) + continue; + + section = &fw_hdr->sections[i]; + le32p_replace_bits(§ion->w1, section_info->len_override, + FWSECTION_HDR_W1_SEC_SIZE); + } + return 0; } @@ -1283,10 +1339,20 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev, if (info->ignore) return 0; + if (info->len_override) { + if (info->len_override > info->len) + rtw89_warn(rtwdev, "override length %u larger than original %u\n", + info->len_override, info->len); + else + residue_len = info->len_override; + } + if (info->key_addr && info->key_len) { - if (info->len > FWDL_SECTION_PER_PKT_LEN || info->len < info->key_len) - rtw89_warn(rtwdev, "ignore to copy key data because of len %d, %d, %d\n", - info->len, FWDL_SECTION_PER_PKT_LEN, info->key_len); + if (residue_len > FWDL_SECTION_PER_PKT_LEN || info->len < info->key_len) + rtw89_warn(rtwdev, + "ignore to copy key data because of len %d, %d, %d, %d\n", + info->len, FWDL_SECTION_PER_PKT_LEN, + info->key_len, residue_len); else copy_key = true; } @@ -1422,6 +1488,8 @@ static int rtw89_fw_download_suit(struct rtw89_dev *rtwdev, return ret; } + rtw89_fwdl_secure_idmem_share_mode(rtwdev, info.idmem_share_mode); + if (rtwdev->chip->chip_id == RTL8922A && (fw_suit->type == RTW89_FW_NORMAL || fw_suit->type == RTW89_FW_WOWLAN)) rtw89_write32(rtwdev, R_BE_SECURE_BOOT_MALLOC_INFO, 0x20248000); @@ -1741,8 +1809,8 @@ plain_log: } #define H2C_CAM_LEN 60 -int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, const u8 *scan_mac_addr) +int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr) { struct sk_buff *skb; int ret; @@ -1753,8 +1821,9 @@ int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, return -ENOMEM; } skb_put(skb, H2C_CAM_LEN); - rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif, rtwsta, scan_mac_addr, skb->data); - rtw89_cam_fill_bssid_cam_info(rtwdev, rtwvif, rtwsta, skb->data); + rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif_link, rtwsta_link, scan_mac_addr, + skb->data); + rtw89_cam_fill_bssid_cam_info(rtwdev, rtwvif_link, rtwsta_link, skb->data); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -1776,8 +1845,8 @@ fail: } int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { struct rtw89_h2c_dctlinfo_ud_v1 *h2c; u32 len = sizeof(*h2c); @@ -1792,7 +1861,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_dctlinfo_ud_v1 *)skb->data; - rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif, rtwsta, h2c); + rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif_link, rtwsta_link, h2c); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -1815,8 +1884,8 @@ fail: EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1); int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { struct rtw89_h2c_dctlinfo_ud_v2 *h2c; u32 len = sizeof(*h2c); @@ -1831,7 +1900,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data; - rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif, rtwsta, h2c); + rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif_link, rtwsta_link, h2c); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -1854,10 +1923,10 @@ fail: EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2); int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; struct rtw89_h2c_dctlinfo_ud_v2 *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -1908,21 +1977,24 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v2); -int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params) { const struct rtw89_chip_info *chip = rtwdev->chip; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_h2c_ba_cam *h2c; - u8 macid = rtwsta->mac_id; + u8 macid = rtwsta_link->mac_id; u32 len = sizeof(*h2c); struct sk_buff *skb; u8 entry_idx; int ret; ret = valid ? - rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) : - rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx); + rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta_link, params->tid, + &entry_idx) : + rtw89_core_release_sta_ba_entry(rtwdev, rtwsta_link, params->tid, + &entry_idx); if (ret) { /* it still works even if we don't have static BA CAM, because * hardware can create dynamic BA CAM automatically. @@ -1960,7 +2032,8 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, if (chip->bacam_ver == RTW89_BACAM_V0_EXT) { h2c->w1 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W1_STD_EN) | - le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BA_CAM_W1_BAND); + le32_encode_bits(rtwvif_link->mac_idx, + RTW89_H2C_BA_CAM_W1_BAND); } end: @@ -2039,13 +2112,14 @@ void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev) } } -int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params) { const struct rtw89_chip_info *chip = rtwdev->chip; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_h2c_ba_cam_v1 *h2c; - u8 macid = rtwsta->mac_id; + u8 macid = rtwsta_link->mac_id; u32 len = sizeof(*h2c); struct sk_buff *skb; u8 entry_idx; @@ -2053,8 +2127,10 @@ int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, int ret; ret = valid ? - rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) : - rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx); + rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta_link, params->tid, + &entry_idx) : + rtw89_core_release_sta_ba_entry(rtwdev, rtwsta_link, params->tid, + &entry_idx); if (ret) { /* it still works even if we don't have static BA CAM, because * hardware can create dynamic BA CAM automatically. @@ -2092,7 +2168,8 @@ int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, entry_idx += chip->bacam_dynamic_num; /* std entry right after dynamic ones */ h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK) | le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W1_STD_ENTRY_EN) | - le32_encode_bits(!!rtwvif->mac_idx, RTW89_H2C_BA_CAM_V1_W1_BAND_SEL); + le32_encode_bits(!!rtwvif_link->mac_idx, + RTW89_H2C_BA_CAM_V1_W1_BAND_SEL); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -2197,15 +2274,14 @@ fail: } static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { static const u8 gtkbody[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E, 0x01, 0x03, 0x00, 0x5F, 0x02, 0x03}; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_eapol_2_of_2 *eapol_pkt; + struct ieee80211_bss_conf *bss_conf; struct ieee80211_hdr_3addr *hdr; struct sk_buff *skb; u8 key_des_ver; @@ -2227,10 +2303,17 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS | IEEE80211_FCTL_PROTECTED); + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ether_addr_copy(hdr->addr1, bss_conf->bssid); - ether_addr_copy(hdr->addr2, vif->addr); + ether_addr_copy(hdr->addr2, bss_conf->addr); ether_addr_copy(hdr->addr3, bss_conf->bssid); + rcu_read_unlock(); + skb_put_zero(skb, sec_hdr_len); eapol_pkt = skb_put_zero(skb, sizeof(*eapol_pkt)); @@ -2241,11 +2324,10 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, } static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); + struct ieee80211_bss_conf *bss_conf; struct ieee80211_hdr_3addr *hdr; struct rtw89_sa_query *sa_query; struct sk_buff *skb; @@ -2258,10 +2340,17 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION | IEEE80211_FCTL_PROTECTED); + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ether_addr_copy(hdr->addr1, bss_conf->bssid); - ether_addr_copy(hdr->addr2, vif->addr); + ether_addr_copy(hdr->addr2, bss_conf->addr); ether_addr_copy(hdr->addr3, bss_conf->bssid); + rcu_read_unlock(); + skb_put_zero(skb, sec_hdr_len); sa_query = skb_put_zero(skb, sizeof(*sa_query)); @@ -2272,8 +2361,9 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, } static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct ieee80211_hdr_3addr *hdr; @@ -2295,9 +2385,9 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS); hdr->frame_control = fc; - ether_addr_copy(hdr->addr1, rtwvif->bssid); - ether_addr_copy(hdr->addr2, rtwvif->mac_addr); - ether_addr_copy(hdr->addr3, rtwvif->bssid); + ether_addr_copy(hdr->addr1, rtwvif_link->bssid); + ether_addr_copy(hdr->addr2, rtwvif_link->mac_addr); + ether_addr_copy(hdr->addr3, rtwvif_link->bssid); skb_put_zero(skb, sec_hdr_len); @@ -2312,18 +2402,18 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, arp_hdr->ar_pln = 4; arp_hdr->ar_op = htons(ARPOP_REPLY); - ether_addr_copy(arp_skb->sender_hw, rtwvif->mac_addr); + ether_addr_copy(arp_skb->sender_hw, rtwvif_link->mac_addr); arp_skb->sender_ip = rtwvif->ip_addr; return skb; } static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, enum rtw89_fw_pkt_ofld_type type, u8 *id) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_pktofld_info *info; struct sk_buff *skb; int ret; @@ -2346,13 +2436,13 @@ static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, true); break; case RTW89_PKT_OFLD_TYPE_EAPOL_KEY: - skb = rtw89_eapol_get(rtwdev, rtwvif); + skb = rtw89_eapol_get(rtwdev, rtwvif_link); break; case RTW89_PKT_OFLD_TYPE_SA_QUERY: - skb = rtw89_sa_query_get(rtwdev, rtwvif); + skb = rtw89_sa_query_get(rtwdev, rtwvif_link); break; case RTW89_PKT_OFLD_TYPE_ARP_RSP: - skb = rtw89_arp_response_get(rtwdev, rtwvif); + skb = rtw89_arp_response_get(rtwdev, rtwvif_link); break; default: goto err; @@ -2367,7 +2457,7 @@ static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, if (ret) goto err; - list_add_tail(&info->list, &rtwvif->general_pkt_list); + list_add_tail(&info->list, &rtwvif_link->general_pkt_list); *id = info->id; return 0; @@ -2377,9 +2467,10 @@ err: } void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool notify_fw) + struct rtw89_vif_link *rtwvif_link, + bool notify_fw) { - struct list_head *pkt_list = &rtwvif->general_pkt_list; + struct list_head *pkt_list = &rtwvif_link->general_pkt_list; struct rtw89_pktofld_info *info, *tmp; list_for_each_entry_safe(info, tmp, pkt_list, list) { @@ -2394,16 +2485,20 @@ void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, notify_fw); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif_link, + notify_fw); } #define H2C_GENERAL_PKT_LEN 6 #define H2C_GENERAL_PKT_ID_UND 0xff int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u8 macid) + struct rtw89_vif_link *rtwvif_link, u8 macid) { u8 pkt_id_ps_poll = H2C_GENERAL_PKT_ID_UND; u8 pkt_id_null = H2C_GENERAL_PKT_ID_UND; @@ -2411,11 +2506,11 @@ int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct sk_buff *skb; int ret; - rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_PS_POLL, &pkt_id_ps_poll); - rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id_null); - rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_QOS_NULL, &pkt_id_qos_null); skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_GENERAL_PKT_LEN); @@ -2478,7 +2573,7 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_PS, - H2C_FUNC_MAC_LPS_PARM, 0, 1, + H2C_FUNC_MAC_LPS_PARM, 0, !lps_param->psmode, H2C_LPS_PARM_LEN); ret = rtw89_h2c_tx(rtwdev, skb, false); @@ -2494,10 +2589,10 @@ fail: return ret; } -int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_h2c_lps_ch_info *h2c; u32 len = sizeof(*h2c); @@ -2546,13 +2641,14 @@ fail: } #define H2C_P2P_ACT_LEN 20 -int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf, struct ieee80211_p2p_noa_desc *desc, u8 act, u8 noa_id) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - bool p2p_type_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; - u8 ctwindow_oppps = vif->bss_conf.p2p_noa_attr.oppps_ctwindow; + bool p2p_type_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; + u8 ctwindow_oppps = bss_conf->p2p_noa_attr.oppps_ctwindow; struct sk_buff *skb; u8 *cmd; int ret; @@ -2565,7 +2661,7 @@ int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, skb_put(skb, H2C_P2P_ACT_LEN); cmd = skb->data; - RTW89_SET_FWCMD_P2P_MACID(cmd, rtwvif->mac_id); + RTW89_SET_FWCMD_P2P_MACID(cmd, rtwvif_link->mac_id); RTW89_SET_FWCMD_P2P_P2PID(cmd, 0); RTW89_SET_FWCMD_P2P_NOAID(cmd, noa_id); RTW89_SET_FWCMD_P2P_ACT(cmd, act); @@ -2622,11 +2718,11 @@ static void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev, #define H2C_CMC_TBL_LEN 68 int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; - u8 macid = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 macid = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; struct sk_buff *skb; int ret; @@ -2648,7 +2744,7 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, } SET_CMC_TBL_DOPPLER_CTRL(skb->data, 0); SET_CMC_TBL_TXPWR_TOLERENCE(skb->data, 0); - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) SET_CMC_TBL_DATA_DCM(skb->data, 0); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -2671,10 +2767,10 @@ fail: EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl); int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; struct rtw89_h2c_cctlinfo_ud_g7 *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -2755,24 +2851,25 @@ fail: EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7); static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, u8 *pads) + struct ieee80211_link_sta *link_sta, + u8 *pads) { bool ppe_th; u8 ppe16, ppe8; - u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; - u8 ppe_thres_hdr = sta->deflink.he_cap.ppe_thres[0]; + u8 nss = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1; + u8 ppe_thres_hdr = link_sta->he_cap.ppe_thres[0]; u8 ru_bitmap; u8 n, idx, sh; u16 ppe; int i; ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, - sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]); + link_sta->he_cap.he_cap_elem.phy_cap_info[6]); if (!ppe_th) { u8 pad; pad = FIELD_GET(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK, - sta->deflink.he_cap.he_cap_elem.phy_cap_info[9]); + link_sta->he_cap.he_cap_elem.phy_cap_info[9]); for (i = 0; i < RTW89_PPE_BW_NUM; i++) pads[i] = pad; @@ -2794,7 +2891,7 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, sh = n & 7; n += IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2; - ppe = le16_to_cpu(*((__le16 *)&sta->deflink.he_cap.ppe_thres[idx])); + ppe = le16_to_cpu(*((__le16 *)&link_sta->he_cap.ppe_thres[idx])); ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; sh += IEEE80211_PPE_THRES_INFO_PPET_SIZE; ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; @@ -2809,23 +2906,35 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, } int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); const struct rtw89_chip_info *chip = rtwdev->chip; - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); + struct ieee80211_link_sta *link_sta; struct sk_buff *skb; u8 pads[RTW89_PPE_BW_NUM]; - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; u16 lowest_rate; int ret; memset(pads, 0, sizeof(pads)); - if (sta && sta->deflink.he_cap.has_he) - __get_sta_he_pkt_padding(rtwdev, sta, pads); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); + return -ENOMEM; + } + + rcu_read_lock(); + + if (rtwsta_link) + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (rtwsta_link && link_sta->he_cap.has_he) + __get_sta_he_pkt_padding(rtwdev, link_sta, pads); if (vif->p2p) lowest_rate = RTW89_HW_RATE_OFDM6; @@ -2834,11 +2943,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, else lowest_rate = RTW89_HW_RATE_OFDM6; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); - if (!skb) { - rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); - return -ENOMEM; - } skb_put(skb, H2C_CMC_TBL_LEN); SET_CTRL_INFO_MACID(skb->data, mac_id); SET_CTRL_INFO_OPERATION(skb->data, 1); @@ -2851,7 +2955,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, SET_CMC_TBL_ULDL(skb->data, 1); else SET_CMC_TBL_ULDL(skb->data, 0); - SET_CMC_TBL_MULTI_PORT_ID(skb->data, rtwvif->port); + SET_CMC_TBL_MULTI_PORT_ID(skb->data, rtwvif_link->port); if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD_V1) { SET_CMC_TBL_NOMINAL_PKT_PADDING_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_20]); SET_CMC_TBL_NOMINAL_PKT_PADDING40_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_40]); @@ -2863,12 +2967,14 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, SET_CMC_TBL_NOMINAL_PKT_PADDING80(skb->data, pads[RTW89_CHANNEL_WIDTH_80]); SET_CMC_TBL_NOMINAL_PKT_PADDING160(skb->data, pads[RTW89_CHANNEL_WIDTH_160]); } - if (sta) + if (rtwsta_link) SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(skb->data, - sta->deflink.he_cap.has_he); - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + link_sta->he_cap.has_he); + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) SET_CMC_TBL_DATA_DCM(skb->data, 0); + rcu_read_unlock(); + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, chip->h2c_cctl_func_id, 0, 1, @@ -2889,9 +2995,10 @@ fail: EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl); static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, u8 *pads) + struct ieee80211_link_sta *link_sta, + u8 *pads) { - u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; + u8 nss = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1; u16 ppe_thres_hdr; u8 ppe16, ppe8; u8 n, idx, sh; @@ -2900,12 +3007,12 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, u16 ppe; int i; - ppe_th = !!u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], + ppe_th = !!u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5], IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT); if (!ppe_th) { u8 pad; - pad = u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], + pad = u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5], IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); for (i = 0; i < RTW89_PPE_BW_NUM; i++) @@ -2914,7 +3021,7 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, return; } - ppe_thres_hdr = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres); + ppe_thres_hdr = get_unaligned_le16(link_sta->eht_cap.eht_ppe_thres); ru_bitmap = u16_get_bits(ppe_thres_hdr, IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); n = hweight8(ru_bitmap); @@ -2931,7 +3038,7 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, sh = n & 7; n += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2; - ppe = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres + idx); + ppe = get_unaligned_le16(link_sta->eht_cap.eht_ppe_thres + idx); ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; sh += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE; ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; @@ -2946,14 +3053,15 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, } int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + struct ieee80211_bss_conf *bss_conf; + struct ieee80211_link_sta *link_sta; u8 pads[RTW89_PPE_BW_NUM]; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -2961,11 +3069,24 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, int ret; memset(pads, 0, sizeof(pads)); - if (sta) { - if (sta->deflink.eht_cap.has_eht) - __get_sta_eht_pkt_padding(rtwdev, sta, pads); - else if (sta->deflink.he_cap.has_he) - __get_sta_he_pkt_padding(rtwdev, sta, pads); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n"); + return -ENOMEM; + } + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + + if (rtwsta_link) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->eht_cap.has_eht) + __get_sta_eht_pkt_padding(rtwdev, link_sta, pads); + else if (link_sta->he_cap.has_he) + __get_sta_he_pkt_padding(rtwdev, link_sta, pads); } if (vif->p2p) @@ -2975,11 +3096,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, else lowest_rate = RTW89_HW_RATE_OFDM6; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); - if (!skb) { - rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n"); - return -ENOMEM; - } skb_put(skb, len); h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; @@ -3000,16 +3116,16 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, h2c->w3 = le32_encode_bits(0, CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL); h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL); - h2c->w4 = le32_encode_bits(rtwvif->port, CCTLINFO_G7_W4_MULTI_PORT_ID); + h2c->w4 = le32_encode_bits(rtwvif_link->port, CCTLINFO_G7_W4_MULTI_PORT_ID); h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_MULTI_PORT_ID); - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) { + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) { h2c->w4 |= le32_encode_bits(0, CCTLINFO_G7_W4_DATA_DCM); h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_DATA_DCM); } - if (vif->bss_conf.eht_support) { - u16 punct = vif->bss_conf.chanreq.oper.punctured; + if (bss_conf->eht_support) { + u16 punct = bss_conf->chanreq.oper.punctured; h2c->w4 |= le32_encode_bits(~punct, CCTLINFO_G7_W4_ACT_SUBCH_CBW); @@ -3036,12 +3152,14 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, CCTLINFO_G7_W6_ULDL); h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ULDL); - if (sta) { - h2c->w8 = le32_encode_bits(sta->deflink.he_cap.has_he, + if (rtwsta_link) { + h2c->w8 = le32_encode_bits(link_sta->he_cap.has_he, CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT); h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT); } + rcu_read_unlock(); + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, @@ -3062,10 +3180,10 @@ fail: EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7); int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = rtwsta_link->rtwsta; struct rtw89_h2c_cctlinfo_ud_g7 *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -3102,7 +3220,7 @@ int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, else if (agg_num > 0x200 && agg_num <= 0x400) ba_bmap = 5; - h2c->c0 = le32_encode_bits(rtwsta->mac_id, CCTLINFO_G7_C0_MACID) | + h2c->c0 = le32_encode_bits(rtwsta_link->mac_id, CCTLINFO_G7_C0_MACID) | le32_encode_bits(1, CCTLINFO_G7_C0_OP); h2c->w3 = le32_encode_bits(ba_bmap, CCTLINFO_G7_W3_BA_BMAP); @@ -3128,7 +3246,7 @@ fail: EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_g7); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta) + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; struct sk_buff *skb; @@ -3140,15 +3258,15 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, return -ENOMEM; } skb_put(skb, H2C_CMC_TBL_LEN); - SET_CTRL_INFO_MACID(skb->data, rtwsta->mac_id); + SET_CTRL_INFO_MACID(skb->data, rtwsta_link->mac_id); SET_CTRL_INFO_OPERATION(skb->data, 1); - if (rtwsta->cctl_tx_time) { + if (rtwsta_link->cctl_tx_time) { SET_CMC_TBL_AMPDU_TIME_SEL(skb->data, 1); - SET_CMC_TBL_AMPDU_MAX_TIME(skb->data, rtwsta->ampdu_max_time); + SET_CMC_TBL_AMPDU_MAX_TIME(skb->data, rtwsta_link->ampdu_max_time); } - if (rtwsta->cctl_tx_retry_limit) { + if (rtwsta_link->cctl_tx_retry_limit) { SET_CMC_TBL_DATA_TXCNT_LMT_SEL(skb->data, 1); - SET_CMC_TBL_DATA_TX_CNT_LMT(skb->data, rtwsta->data_tx_cnt_lmt); + SET_CMC_TBL_DATA_TX_CNT_LMT(skb->data, rtwsta_link->data_tx_cnt_lmt); } rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -3170,7 +3288,7 @@ fail: } int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta) + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; struct sk_buff *skb; @@ -3185,7 +3303,7 @@ int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, return -ENOMEM; } skb_put(skb, H2C_CMC_TBL_LEN); - SET_CTRL_INFO_MACID(skb->data, rtwsta->mac_id); + SET_CTRL_INFO_MACID(skb->data, rtwsta_link->mac_id); SET_CTRL_INFO_OPERATION(skb->data, 1); __rtw89_fw_h2c_set_tx_path(rtwdev, skb); @@ -3209,11 +3327,11 @@ fail: } int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + rtwvif_link->chanctx_idx); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_h2c_bcn_upd *h2c; struct sk_buff *skb_beacon; struct ieee80211_hdr *hdr; @@ -3240,7 +3358,7 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, return -ENOMEM; } - noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data); + noa_len = rtw89_p2p_noa_fetch(rtwvif_link, &noa_data); if (noa_len && (noa_len <= skb_tailroom(skb_beacon) || pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) { @@ -3260,11 +3378,11 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_bcn_upd *)skb->data; - h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_W0_PORT) | + h2c->w0 = le32_encode_bits(rtwvif_link->port, RTW89_H2C_BCN_UPD_W0_PORT) | le32_encode_bits(0, RTW89_H2C_BCN_UPD_W0_MBSSID) | - le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) | + le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) | le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_W0_GRP_IE_OFST); - h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) | + h2c->w1 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) | le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_W1_SSN_SEL) | le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_W1_SSN_MODE) | le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_W1_RATE); @@ -3289,10 +3407,10 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon); int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_h2c_bcn_upd_be *h2c; struct sk_buff *skb_beacon; struct ieee80211_hdr *hdr; @@ -3319,7 +3437,7 @@ int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, return -ENOMEM; } - noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data); + noa_len = rtw89_p2p_noa_fetch(rtwvif_link, &noa_data); if (noa_len && (noa_len <= skb_tailroom(skb_beacon) || pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) { @@ -3339,11 +3457,11 @@ int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_bcn_upd_be *)skb->data; - h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) | + h2c->w0 = le32_encode_bits(rtwvif_link->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) | le32_encode_bits(0, RTW89_H2C_BCN_UPD_BE_W0_MBSSID) | - le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) | + le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) | le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_BE_W0_GRP_IE_OFST); - h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) | + h2c->w1 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) | le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_BE_W1_SSN_SEL) | le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_BE_W1_SSN_MODE) | le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_BE_W1_RATE); @@ -3373,22 +3491,22 @@ EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be); #define H2C_ROLE_MAINTAIN_LEN 4 int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, enum rtw89_upd_mode upd_mode) { struct sk_buff *skb; - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; u8 self_role; int ret; - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) { - if (rtwsta) + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) { + if (rtwsta_link) self_role = RTW89_SELF_ROLE_AP_CLIENT; else - self_role = rtwvif->self_role; + self_role = rtwvif_link->self_role; } else { - self_role = rtwvif->self_role; + self_role = rtwvif_link->self_role; } skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_ROLE_MAINTAIN_LEN); @@ -3400,7 +3518,7 @@ int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, SET_FWROLE_MAINTAIN_MACID(skb->data, mac_id); SET_FWROLE_MAINTAIN_SELF_ROLE(skb->data, self_role); SET_FWROLE_MAINTAIN_UPD_MODE(skb->data, upd_mode); - SET_FWROLE_MAINTAIN_WIFI_ROLE(skb->data, rtwvif->wifi_role); + SET_FWROLE_MAINTAIN_WIFI_ROLE(skb->data, rtwvif_link->wifi_role); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT, @@ -3421,39 +3539,53 @@ fail: } static enum rtw89_fw_sta_type -rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) +rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf; + struct ieee80211_link_sta *link_sta; + enum rtw89_fw_sta_type type; - if (!sta) + rcu_read_lock(); + + if (!rtwsta_link) goto by_vif; - if (sta->deflink.eht_cap.has_eht) - return RTW89_FW_BE_STA; - else if (sta->deflink.he_cap.has_he) - return RTW89_FW_AX_STA; + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->eht_cap.has_eht) + type = RTW89_FW_BE_STA; + else if (link_sta->he_cap.has_he) + type = RTW89_FW_AX_STA; else - return RTW89_FW_N_AC_STA; + type = RTW89_FW_N_AC_STA; + + goto out; by_vif: - if (vif->bss_conf.eht_support) - return RTW89_FW_BE_STA; - else if (vif->bss_conf.he_support) - return RTW89_FW_AX_STA; + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + + if (bss_conf->eht_support) + type = RTW89_FW_BE_STA; + else if (bss_conf->he_support) + type = RTW89_FW_AX_STA; else - return RTW89_FW_N_AC_STA; + type = RTW89_FW_N_AC_STA; + +out: + rcu_read_unlock(); + + return type; } -int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, bool dis_conn) +int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool dis_conn) { struct sk_buff *skb; - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; - u8 self_role = rtwvif->self_role; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; + u8 self_role = rtwvif_link->self_role; enum rtw89_fw_sta_type sta_type; - u8 net_type = rtwvif->net_type; + u8 net_type = rtwvif_link->net_type; struct rtw89_h2c_join_v1 *h2c_v1; struct rtw89_h2c_join *h2c; u32 len = sizeof(*h2c); @@ -3465,7 +3597,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, format_v1 = true; } - if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta) { + if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta_link) { self_role = RTW89_SELF_ROLE_AP_CLIENT; net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type; } @@ -3480,16 +3612,17 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_JOININFO_W0_MACID) | le32_encode_bits(dis_conn, RTW89_H2C_JOININFO_W0_OP) | - le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_JOININFO_W0_BAND) | - le32_encode_bits(rtwvif->wmm, RTW89_H2C_JOININFO_W0_WMM) | - le32_encode_bits(rtwvif->trigger, RTW89_H2C_JOININFO_W0_TGR) | + le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_JOININFO_W0_BAND) | + le32_encode_bits(rtwvif_link->wmm, RTW89_H2C_JOININFO_W0_WMM) | + le32_encode_bits(rtwvif_link->trigger, RTW89_H2C_JOININFO_W0_TGR) | le32_encode_bits(0, RTW89_H2C_JOININFO_W0_ISHESTA) | le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DLBW) | le32_encode_bits(0, RTW89_H2C_JOININFO_W0_TF_MAC_PAD) | le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DL_T_PE) | - le32_encode_bits(rtwvif->port, RTW89_H2C_JOININFO_W0_PORT_ID) | + le32_encode_bits(rtwvif_link->port, RTW89_H2C_JOININFO_W0_PORT_ID) | le32_encode_bits(net_type, RTW89_H2C_JOININFO_W0_NET_TYPE) | - le32_encode_bits(rtwvif->wifi_role, RTW89_H2C_JOININFO_W0_WIFI_ROLE) | + le32_encode_bits(rtwvif_link->wifi_role, + RTW89_H2C_JOININFO_W0_WIFI_ROLE) | le32_encode_bits(self_role, RTW89_H2C_JOININFO_W0_SELF_ROLE); if (!format_v1) @@ -3497,7 +3630,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, h2c_v1 = (struct rtw89_h2c_join_v1 *)skb->data; - sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif, rtwsta); + sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif_link, rtwsta_link); h2c_v1->w1 = le32_encode_bits(sta_type, RTW89_H2C_JOININFO_W1_STA_TYPE); h2c_v1->w2 = 0; @@ -3618,7 +3751,7 @@ fail: } #define H2C_EDCA_LEN 12 -int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u8 ac, u32 val) { struct sk_buff *skb; @@ -3631,7 +3764,7 @@ int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, } skb_put(skb, H2C_EDCA_LEN); RTW89_SET_EDCA_SEL(skb->data, 0); - RTW89_SET_EDCA_BAND(skb->data, rtwvif->mac_idx); + RTW89_SET_EDCA_BAND(skb->data, rtwvif_link->mac_idx); RTW89_SET_EDCA_WMM(skb->data, 0); RTW89_SET_EDCA_AC(skb->data, ac); RTW89_SET_EDCA_PARAM(skb->data, val); @@ -3655,7 +3788,8 @@ fail: } #define H2C_TSF32_TOGL_LEN 4 -int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool en) { struct sk_buff *skb; @@ -3671,9 +3805,9 @@ int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif skb_put(skb, H2C_TSF32_TOGL_LEN); cmd = skb->data; - RTW89_SET_FWCMD_TSF32_TOGL_BAND(cmd, rtwvif->mac_idx); + RTW89_SET_FWCMD_TSF32_TOGL_BAND(cmd, rtwvif_link->mac_idx); RTW89_SET_FWCMD_TSF32_TOGL_EN(cmd, en); - RTW89_SET_FWCMD_TSF32_TOGL_PORT(cmd, rtwvif->port); + RTW89_SET_FWCMD_TSF32_TOGL_PORT(cmd, rtwvif_link->port); RTW89_SET_FWCMD_TSF32_TOGL_EARLY(cmd, early_us); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -3726,12 +3860,57 @@ fail: return ret; } +int rtw89_fw_h2c_tx_duty(struct rtw89_dev *rtwdev, u8 lv) +{ + struct rtw89_h2c_tx_duty *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 pause, active; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c tx duty\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_tx_duty *)skb->data; + + static_assert(RTW89_THERMAL_PROT_LV_MAX * RTW89_THERMAL_PROT_STEP < 100); + + if (lv == 0 || lv > RTW89_THERMAL_PROT_LV_MAX) { + h2c->w1 = le32_encode_bits(1, RTW89_H2C_TX_DUTY_W1_STOP); + } else { + active = 100 - lv * RTW89_THERMAL_PROT_STEP; + pause = 100 - active; + + h2c->w0 = le32_encode_bits(pause, RTW89_H2C_TX_DUTY_W0_PAUSE_INTVL_MASK) | + le32_encode_bits(active, RTW89_H2C_TX_DUTY_W0_TX_INTVL_MASK); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, + H2C_FUNC_TX_DUTY, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, + struct rtw89_vif_link *rtwvif_link, bool connect) { - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); - struct ieee80211_bss_conf *bss_conf = vif ? &vif->bss_conf : NULL; + struct ieee80211_bss_conf *bss_conf; s32 thold = RTW89_DEFAULT_CQM_THOLD; u32 hyst = RTW89_DEFAULT_CQM_HYST; struct rtw89_h2c_bcnfltr *h2c; @@ -3742,9 +3921,20 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, if (!RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) return -EINVAL; - if (!rtwvif || !bss_conf || rtwvif->net_type != RTW89_NET_TYPE_INFRA) + if (!rtwvif_link || rtwvif_link->net_type != RTW89_NET_TYPE_INFRA) return -EINVAL; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + + if (bss_conf->cqm_rssi_hyst) + hyst = bss_conf->cqm_rssi_hyst; + if (bss_conf->cqm_rssi_thold) + thold = bss_conf->cqm_rssi_thold; + + rcu_read_unlock(); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c bcn filter\n"); @@ -3754,11 +3944,6 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_bcnfltr *)skb->data; - if (bss_conf->cqm_rssi_hyst) - hyst = bss_conf->cqm_rssi_hyst; - if (bss_conf->cqm_rssi_thold) - thold = bss_conf->cqm_rssi_thold; - h2c->w0 = le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_RSSI) | le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_BCN) | le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_EN) | @@ -3768,7 +3953,7 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, le32_encode_bits(hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) | le32_encode_bits(thold + MAX_RSSI, RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD) | - le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID); + le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, @@ -3833,15 +4018,16 @@ fail: return ret; } -int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_traffic_stats *stats = &rtwvif->stats; struct rtw89_h2c_ofld *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - if (rtwvif->net_type != RTW89_NET_TYPE_INFRA) + if (rtwvif_link->net_type != RTW89_NET_TYPE_INFRA) return -EINVAL; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); @@ -3853,7 +4039,7 @@ int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) skb_put(skb, len); h2c = (struct rtw89_h2c_ofld *)skb->data; - h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_OFLD_W0_MAC_ID) | + h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_OFLD_W0_MAC_ID) | le32_encode_bits(stats->tx_throughput, RTW89_H2C_OFLD_W0_TX_TP) | le32_encode_bits(stats->rx_throughput, RTW89_H2C_OFLD_W0_RX_TP); @@ -4688,6 +4874,7 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, return 0; } +static int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, struct list_head *chan_list) { @@ -4759,8 +4946,10 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, return 0; } +static int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, - struct list_head *chan_list) + struct list_head *chan_list, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_h2c_chinfo_elem_be *elem; @@ -4785,7 +4974,8 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, h2c->ch_num = ch_num; h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */ - h2c->arg = u8_encode_bits(RTW89_PHY_0, RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK); + h2c->arg = u8_encode_bits(rtwvif_link->mac_idx, + RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK); list_for_each_entry(ch_info, chan_list, list) { elem = (struct rtw89_h2c_chinfo_elem_be *)skb_put(skb, sizeof(*elem)); @@ -4858,7 +5048,7 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, #define RTW89_SCAN_DELAY_TSF_UNIT 104800 int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool wowlan) { struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; @@ -4880,19 +5070,19 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, h2c = (struct rtw89_h2c_scanofld *)skb->data; if (option->delay) { - ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, &tsf); + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "NLO failed to get port tsf: %d\n", ret); scan_mode = RTW89_SCAN_IMMEDIATE; } else { scan_mode = RTW89_SCAN_DELAY; - tsf += option->delay * RTW89_SCAN_DELAY_TSF_UNIT; + tsf += (u64)option->delay * RTW89_SCAN_DELAY_TSF_UNIT; } } - h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_W0_MACID) | - le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_W0_PORT_ID) | - le32_encode_bits(RTW89_PHY_0, RTW89_H2C_SCANOFLD_W0_BAND) | + h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_SCANOFLD_W0_MACID) | + le32_encode_bits(rtwvif_link->port, RTW89_H2C_SCANOFLD_W0_PORT_ID) | + le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_SCANOFLD_W0_BAND) | le32_encode_bits(option->enable, RTW89_H2C_SCANOFLD_W0_OPERATION); h2c->w1 = le32_encode_bits(true, RTW89_H2C_SCANOFLD_W1_NOTIFY_END) | @@ -4963,9 +5153,10 @@ static void rtw89_scan_get_6g_disabled_chan(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool wowlan) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct cfg80211_scan_request *req = rtwvif->scan_req; @@ -5016,8 +5207,8 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, le32_encode_bits(option->repeat, RTW89_H2C_SCANOFLD_BE_W0_REPEAT) | le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_NOTIFY_END) | le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_LEARN_CH) | - le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_BE_W0_MACID) | - le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_BE_W0_PORT) | + le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_SCANOFLD_BE_W0_MACID) | + le32_encode_bits(rtwvif_link->port, RTW89_H2C_SCANOFLD_BE_W0_PORT) | le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_W0_BAND); h2c->w1 = le32_encode_bits(option->num_macc_role, RTW89_H2C_SCANOFLD_BE_W1_NUM_MACC_ROLE) | @@ -5082,11 +5273,11 @@ flex_member: for (i = 0; i < option->num_opch; i++) { opch = ptr; - opch->w0 = le32_encode_bits(rtwvif->mac_id, + opch->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) | le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) | - le32_encode_bits(rtwvif->port, + le32_encode_bits(rtwvif_link->port, RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) | le32_encode_bits(RTW89_SCAN_OPMODE_INTV, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) | @@ -5180,7 +5371,7 @@ fail: int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_fw_h2c_rf_get_mccch *mccch; struct sk_buff *skb; int ret; @@ -5227,7 +5418,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; struct rtw89_fw_h2c_rfk_pre_info_v0 *h2c_v0; struct rtw89_fw_h2c_rfk_pre_info *h2c; - u8 tbl_sel = rfk_mcc->table_idx; + u8 tbl_sel[NUM_OF_RTW89_FW_RFK_PATH]; u32 len = sizeof(*h2c); struct sk_buff *skb; u8 ver = U8_MAX; @@ -5251,19 +5442,24 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, h2c->common.mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR); + BUILD_BUG_ON(ARRAY_SIZE(rfk_mcc->data) < NUM_OF_RTW89_FW_RFK_PATH); for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) { for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { h2c->common.dbcc.ch[path][tbl] = - cpu_to_le32(rfk_mcc->ch[tbl]); + cpu_to_le32(rfk_mcc->data[path].ch[tbl]); h2c->common.dbcc.band[path][tbl] = - cpu_to_le32(rfk_mcc->band[tbl]); + cpu_to_le32(rfk_mcc->data[path].band[tbl]); } } for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { - h2c->common.tbl.cur_ch[path] = cpu_to_le32(rfk_mcc->ch[tbl_sel]); - h2c->common.tbl.cur_band[path] = cpu_to_le32(rfk_mcc->band[tbl_sel]); + tbl_sel[path] = rfk_mcc->data[path].table_idx; + + h2c->common.tbl.cur_ch[path] = + cpu_to_le32(rfk_mcc->data[path].ch[tbl_sel[path]]); + h2c->common.tbl.cur_band[path] = + cpu_to_le32(rfk_mcc->data[path].band[tbl_sel[path]]); } h2c->common.phy_idx = cpu_to_le32(phy_idx); @@ -5271,9 +5467,9 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, if (ver == 0) { /* RFK_PRE_NOTIFY_V0 */ h2c_v0 = (struct rtw89_fw_h2c_rfk_pre_info_v0 *)skb->data; - h2c_v0->cur_band = cpu_to_le32(rfk_mcc->band[tbl_sel]); - h2c_v0->cur_bw = cpu_to_le32(rfk_mcc->bw[tbl_sel]); - h2c_v0->cur_center_ch = cpu_to_le32(rfk_mcc->ch[tbl_sel]); + h2c_v0->cur_band = cpu_to_le32(rfk_mcc->data[0].band[tbl_sel[0]]); + h2c_v0->cur_bw = cpu_to_le32(rfk_mcc->data[0].bw[tbl_sel[0]]); + h2c_v0->cur_center_ch = cpu_to_le32(rfk_mcc->data[0].ch[tbl_sel[0]]); val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1); h2c_v0->ktbl_sel0 = cpu_to_le32(val32); @@ -5518,30 +5714,44 @@ fail: } int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, - const struct rtw89_chan *chan) + const struct rtw89_chan *chan, bool is_chl_k) { + struct rtw89_h2c_rf_rxdck_v0 *v0; struct rtw89_h2c_rf_rxdck *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; + int ver = -1; int ret; + if (RTW89_CHK_FW_FEATURE(RFK_RXDCK_V0, &rtwdev->fw)) { + len = sizeof(*v0); + ver = 0; + } + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c RF RXDCK\n"); return -ENOMEM; } skb_put(skb, len); - h2c = (struct rtw89_h2c_rf_rxdck *)skb->data; + v0 = (struct rtw89_h2c_rf_rxdck_v0 *)skb->data; + + v0->len = len; + v0->phy = phy_idx; + v0->is_afe = false; + v0->kpath = RF_AB; + v0->cur_band = chan->band_type; + v0->cur_bw = chan->band_width; + v0->cur_ch = chan->channel; + v0->rxdck_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK); + + if (ver == 0) + goto hdr; - h2c->len = len; - h2c->phy = phy_idx; - h2c->is_afe = false; - h2c->kpath = RF_AB; - h2c->cur_band = chan->band_type; - h2c->cur_bw = chan->band_width; - h2c->cur_ch = chan->channel; - h2c->rxdck_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK); + h2c = (struct rtw89_h2c_rf_rxdck *)skb->data; + h2c->is_chl_k = is_chl_k; +hdr: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, H2C_FUNC_RFK_RXDCK_OFFLOAD, 0, 0, len); @@ -5871,12 +6081,10 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev) } static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct cfg80211_scan_request *req, struct rtw89_pktofld_info *info, enum nl80211_band band, u8 ssid_idx) { - struct cfg80211_scan_request *req = rtwvif->scan_req; - if (band != NL80211_BAND_6GHZ) return false; @@ -5892,11 +6100,13 @@ static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev, } static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct sk_buff *skb, u8 ssid_idx) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct ieee80211_scan_ies *ies = rtwvif->scan_ies; + struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_pktofld_info *info; struct sk_buff *new; int ret = 0; @@ -5921,8 +6131,7 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev, goto out; } - rtw89_is_6ghz_wildcard_probe_req(rtwdev, rtwvif, info, band, - ssid_idx); + rtw89_is_6ghz_wildcard_probe_req(rtwdev, req, info, band, ssid_idx); ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new); if (ret) { @@ -5939,22 +6148,23 @@ out: } static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct sk_buff *skb; u8 num = req->n_ssids, i; int ret; for (i = 0; i < num; i++) { - skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr, + skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, req->ssids[i].ssid, req->ssids[i].ssid_len, req->ie_len); if (!skb) return -ENOMEM; - ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb, i); + ret = rtw89_append_probe_req_ie(rtwdev, rtwvif_link, skb, i); kfree_skb(skb); if (ret) @@ -5965,13 +6175,12 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev, } static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev, + struct ieee80211_scan_ies *ies, struct cfg80211_scan_request *req, struct rtw89_mac_chinfo *ch_info) { - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; struct list_head *pkt_list = rtwdev->scan_info.pkt_list; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); - struct ieee80211_scan_ies *ies = rtwvif->scan_ies; struct cfg80211_scan_6ghz_params *params; struct rtw89_pktofld_info *info, *tmp; struct ieee80211_hdr *hdr; @@ -6000,8 +6209,11 @@ static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev, if (found) continue; - skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr, + skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, NULL, 0, req->ie_len); + if (!skb) + return -ENOMEM; + skb_put_data(skb, ies->ies[NL80211_BAND_6GHZ], ies->len[NL80211_BAND_6GHZ]); skb_put_data(skb, ies->common_ies, ies->common_ie_len); hdr = (struct ieee80211_hdr *)skb->data; @@ -6090,8 +6302,9 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, struct rtw89_mac_chinfo *ch_info) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct ieee80211_scan_ies *ies = rtwvif->scan_ies; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_chan *op = &rtwdev->scan_info.op_chan; struct rtw89_pktofld_info *info; @@ -6117,7 +6330,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, } } - ret = rtw89_update_6ghz_rnr_chan(rtwdev, req, ch_info); + ret = rtw89_update_6ghz_rnr_chan(rtwdev, ies, req, ch_info); if (ret) rtw89_warn(rtwdev, "RNR fails: %d\n", ret); @@ -6155,8 +6368,10 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, ch_info->period = max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME); ch_info->dwell_time = RTW89_DWELL_TIME; + ch_info->pause_data = true; break; case RTW89_CHAN_ACTIVE: + ch_info->pause_data = true; break; default: rtw89_err(rtwdev, "Channel type out of bound\n"); @@ -6207,8 +6422,8 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, struct rtw89_mac_chinfo_be *ch_info) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_pktofld_info *info; u8 band, probe_count = 0, i; @@ -6255,8 +6470,10 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, ch_info->period = max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME); ch_info->dwell_time = RTW89_DWELL_TIME; + ch_info->pause_data = true; break; case RTW89_CHAN_ACTIVE: + ch_info->pause_data = true; break; default: rtw89_warn(rtwdev, "Channel type out of bound\n"); @@ -6265,7 +6482,7 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, } int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; @@ -6315,8 +6532,9 @@ out: } int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected) + struct rtw89_vif_link *rtwvif_link, bool connected) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_mac_chinfo *ch_info, *tmp; struct ieee80211_channel *channel; @@ -6392,7 +6610,7 @@ out: } int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; @@ -6432,7 +6650,8 @@ int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev, list_add_tail(&ch_info->list, &chan_list); } - ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list); + ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list, + rtwvif_link); out: list_for_each_entry_safe(ch_info, tmp, &chan_list, list) { @@ -6444,8 +6663,9 @@ out: } int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected) + struct rtw89_vif_link *rtwvif_link, bool connected) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_mac_chinfo_be *ch_info, *tmp; struct ieee80211_channel *channel; @@ -6491,7 +6711,8 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, } rtwdev->scan_info.last_chan_idx = idx; - ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list); + ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list, + rtwvif_link); out: list_for_each_entry_safe(ch_info, tmp, &chan_list, list) { @@ -6503,79 +6724,88 @@ out: } static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected) + struct rtw89_vif_link *rtwvif_link, bool connected) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; - ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif); + ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif_link); if (ret) { rtw89_err(rtwdev, "Update probe request failed\n"); goto out; } - ret = mac->add_chan_list(rtwdev, rtwvif, connected); + ret = mac->add_chan_list(rtwdev, rtwvif_link, connected); out: return ret; } -void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_scan_request *scan_req) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct cfg80211_scan_request *req = &scan_req->req; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, + rtwvif_link->chanctx_idx); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; u32 rx_fltr = rtwdev->hal.rx_fltr; u8 mac_addr[ETH_ALEN]; + u32 reg; + + /* clone op and keep it during scan */ + rtwdev->scan_info.op_chan = *chan; - rtw89_get_channel(rtwdev, rtwvif, &rtwdev->scan_info.op_chan); - rtwdev->scan_info.scanning_vif = vif; + rtwdev->scan_info.scanning_vif = rtwvif_link; rtwdev->scan_info.last_chan_idx = 0; rtwdev->scan_info.abort = false; rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_req = req; ieee80211_stop_queues(rtwdev->hw); - rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, false); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, false); if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) get_random_mask_addr(mac_addr, req->mac_addr, req->mac_addr_mask); else - ether_addr_copy(mac_addr, vif->addr); - rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, true); + ether_addr_copy(mac_addr, rtwvif_link->mac_addr); + rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, true); rx_fltr &= ~B_AX_A_BCN_CHK_EN; rx_fltr &= ~B_AX_A_BC; rx_fltr &= ~B_AX_A_A1_MATCH; - rtw89_write32_mask(rtwdev, - rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), - B_AX_RX_FLTR_CFG_MASK, - rx_fltr); + + reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rx_fltr); rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_HW_SCAN); } -void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool aborted) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct cfg80211_scan_info info = { .aborted = aborted, }; + struct rtw89_vif *rtwvif; + u32 reg; - if (!vif) + if (!rtwvif_link) return; - rtw89_write32_mask(rtwdev, - rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), - B_AX_RX_FLTR_CFG_MASK, - rtwdev->hal.rx_fltr); + rtw89_chanctx_proceed(rtwdev); + + rtwvif = rtwvif_link->rtwvif; - rtw89_core_scan_complete(rtwdev, vif, true); + reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr); + + rtw89_core_scan_complete(rtwdev, rtwvif_link, true); ieee80211_scan_completed(rtwdev->hw, &info); ieee80211_wake_queues(rtwdev->hw); - rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, true); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, true); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); rtw89_release_pkt_list(rtwdev); @@ -6584,18 +6814,17 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, scan_info->last_chan_idx = 0; scan_info->scanning_vif = NULL; scan_info->abort = false; - - rtw89_chanctx_proceed(rtwdev); } -void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; int ret; scan_info->abort = true; - ret = rtw89_hw_scan_offload(rtwdev, vif, false); + ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, false); if (ret) rtw89_warn(rtwdev, "rtw89_hw_scan_offload failed ret %d\n", ret); @@ -6604,40 +6833,43 @@ void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) * RTW89_SCAN_END_SCAN_NOTIFY, so that ieee80211_stop() can flush scan * work properly. */ - rtw89_hw_scan_complete(rtwdev, vif, true); + rtw89_hw_scan_complete(rtwdev, rtwvif_link, true); } static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; rtw89_for_each_rtwvif(rtwdev, rtwvif) { - /* This variable implies connected or during attempt to connect */ - if (!is_zero_ether_addr(rtwvif->bssid)) - return true; + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + /* This variable implies connected or during attempt to connect */ + if (!is_zero_ether_addr(rtwvif_link->bssid)) + return true; + } } return false; } -int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_scan_option opt = {0}; - struct rtw89_vif *rtwvif; bool connected; int ret = 0; - rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL; - if (!rtwvif) + if (!rtwvif_link) return -EINVAL; connected = rtw89_is_any_vif_connected_or_connecting(rtwdev); opt.enable = enable; opt.target_ch_mode = connected; if (enable) { - ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif, connected); + ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif_link, connected); if (ret) goto out; } @@ -6645,14 +6877,14 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { opt.operation = enable ? RTW89_SCAN_OP_START : RTW89_SCAN_OP_STOP; opt.scan_mode = RTW89_SCAN_MODE_SA; - opt.band = RTW89_PHY_0; + opt.band = rtwvif_link->mac_idx; opt.num_macc_role = 0; opt.mlo_mode = rtwdev->mlo_dbcc_mode; opt.num_opch = connected ? 1 : 0; opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; } - ret = mac->scan_offload(rtwdev, &opt, rtwvif, false); + ret = mac->scan_offload(rtwdev, &opt, rtwvif_link, false); out: return ret; } @@ -6758,7 +6990,7 @@ fail: } #define H2C_KEEP_ALIVE_LEN 4 -int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct sk_buff *skb; @@ -6766,7 +6998,7 @@ int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, int ret; if (enable) { - ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id); if (ret) @@ -6784,7 +7016,7 @@ int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, RTW89_SET_KEEP_ALIVE_ENABLE(skb->data, enable); RTW89_SET_KEEP_ALIVE_PKT_NULL_ID(skb->data, pkt_id); RTW89_SET_KEEP_ALIVE_PERIOD(skb->data, 5); - RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif->mac_id); + RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif_link->mac_id); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -6806,7 +7038,7 @@ fail: return ret; } -int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_h2c_arp_offload *h2c; @@ -6816,7 +7048,7 @@ int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, int ret; if (enable) { - ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_ARP_RSP, &pkt_id); if (ret) @@ -6834,7 +7066,7 @@ int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, h2c->w0 = le32_encode_bits(enable, RTW89_H2C_ARP_OFFLOAD_W0_ENABLE) | le32_encode_bits(0, RTW89_H2C_ARP_OFFLOAD_W0_ACTION) | - le32_encode_bits(rtwvif->mac_id, RTW89_H2C_ARP_OFFLOAD_W0_MACID) | + le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_ARP_OFFLOAD_W0_MACID) | le32_encode_bits(pkt_id, RTW89_H2C_ARP_OFFLOAD_W0_PKT_ID); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -6859,11 +7091,11 @@ fail: #define H2C_DISCONNECT_DETECT_LEN 8 int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable) + struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct sk_buff *skb; - u8 macid = rtwvif->mac_id; + u8 macid = rtwvif_link->mac_id; int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DISCONNECT_DETECT_LEN); @@ -6902,7 +7134,7 @@ fail: return ret; } -int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; @@ -6923,7 +7155,7 @@ int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, h2c->w0 = le32_encode_bits(enable, RTW89_H2C_NLO_W0_ENABLE) | le32_encode_bits(enable, RTW89_H2C_NLO_W0_IGNORE_CIPHER) | - le32_encode_bits(rtwvif->mac_id, RTW89_H2C_NLO_W0_MACID); + le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_NLO_W0_MACID); if (enable) { h2c->nlo_cnt = nd_config->n_match_sets; @@ -6953,12 +7185,12 @@ fail: return ret; } -int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_h2c_wow_global *h2c; - u8 macid = rtwvif->mac_id; + u8 macid = rtwvif_link->mac_id; u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; @@ -7002,12 +7234,12 @@ fail: #define H2C_WAKEUP_CTRL_LEN 4 int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct sk_buff *skb; - u8 macid = rtwvif->mac_id; + u8 macid = rtwvif_link->mac_id; int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WAKEUP_CTRL_LEN); @@ -7100,13 +7332,13 @@ fail: } int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_gtk_info *gtk_info = &rtw_wow->gtk_info; struct rtw89_h2c_wow_gtk_ofld *h2c; - u8 macid = rtwvif->mac_id; + u8 macid = rtwvif_link->mac_id; u32 len = sizeof(*h2c); u8 pkt_id_sa_query = 0; struct sk_buff *skb; @@ -7128,14 +7360,14 @@ int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, if (!enable) goto hdr; - ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_EAPOL_KEY, &pkt_id_eapol); if (ret) goto fail; if (gtk_info->igtk_keyid) { - ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_SA_QUERY, &pkt_id_sa_query); if (ret) @@ -7173,7 +7405,7 @@ fail: return ret; } -int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wait_info *wait = &rtwdev->mac.ps_wait; @@ -7189,7 +7421,7 @@ int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, skb_put(skb, len); h2c = (struct rtw89_h2c_fwips *)skb->data; - h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_FW_IPS_W0_MACID) | + h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_FW_IPS_W0_MACID) | le32_encode_bits(enable, RTW89_H2C_FW_IPS_W0_ENABLE); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index ad47e77d740b..efa63d444821 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -261,6 +261,7 @@ struct rtw89_fw_hdr_section_info { u8 redl; const u8 *addr; u32 len; + u32 len_override; u32 dladdr; u32 mssc; u8 type; @@ -275,6 +276,7 @@ struct rtw89_fw_bin_info { u32 hdr_len; bool dynamic_hdr_en; u32 dynamic_hdr_len; + u8 idmem_share_mode; bool dsp_checksum; bool secure_section_exist; struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM]; @@ -563,6 +565,7 @@ struct rtw89_fw_hdr { #define FW_HDR_W6_SEC_NUM GENMASK(15, 8) #define FW_HDR_W7_PART_SIZE GENMASK(15, 0) #define FW_HDR_W7_DYN_HDR BIT(16) +#define FW_HDR_W7_IDMEM_SHARE_MODE GENMASK(21, 18) #define FW_HDR_W7_CMD_VERSERION GENMASK(31, 24) struct rtw89_fw_hdr_section_v1 { @@ -580,6 +583,7 @@ struct rtw89_fw_hdr_section_v1 { #define FWSECTION_HDR_V1_W1_REDL BIT(29) #define FWSECTION_HDR_V1_W2_MSSC GENMASK(7, 0) #define FORMATTED_MSSC 0xFF +#define FORMATTED_MSSC_MASK GENMASK(7, 0) #define FWSECTION_HDR_V1_W2_BBMCU_IDX GENMASK(27, 24) struct rtw89_fw_hdr_v1 { @@ -615,6 +619,7 @@ struct rtw89_fw_hdr_v1 { #define FW_HDR_V1_W6_DSP_CHKSUM BIT(24) #define FW_HDR_V1_W7_PART_SIZE GENMASK(15, 0) #define FW_HDR_V1_W7_DYN_HDR BIT(16) +#define FW_HDR_V1_W7_IDMEM_SHARE_MODE GENMASK(21, 18) enum rtw89_fw_mss_pool_rmp_tbl_type { MSS_POOL_RMP_TBL_BITMASK = 0x0, @@ -3689,6 +3694,13 @@ struct rtw89_c2h_pkt_ofld_rsp { #define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_OP GENMASK(10, 8) #define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_LEN GENMASK(31, 16) +struct rtw89_c2h_tx_duty_rpt { + struct rtw89_c2h_hdr c2h_hdr; + __le32 w2; +} __packed; + +#define RTW89_C2H_TX_DUTY_RPT_W2_TIMER_ERR GENMASK(2, 0) + struct rtw89_c2h_wow_aoac_report { struct rtw89_c2h_hdr c2h_hdr; u8 rpt_ver; @@ -3713,6 +3725,15 @@ struct rtw89_c2h_wow_aoac_report { #define RTW89_C2H_WOW_AOAC_RPT_REKEY_IDX BIT(0) +struct rtw89_h2c_tx_duty { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_TX_DUTY_W0_PAUSE_INTVL_MASK GENMASK(15, 0) +#define RTW89_H2C_TX_DUTY_W0_TX_INTVL_MASK GENMASK(31, 16) +#define RTW89_H2C_TX_DUTY_W1_STOP BIT(0) + struct rtw89_h2c_bcnfltr { __le32 w0; } __packed; @@ -4071,6 +4092,7 @@ enum rtw89_fw_ofld_h2c_func { H2C_FUNC_OFLD_CFG = 0x14, H2C_FUNC_ADD_SCANOFLD_CH = 0x16, H2C_FUNC_SCANOFLD = 0x17, + H2C_FUNC_TX_DUTY = 0x18, H2C_FUNC_PKT_DROP = 0x1b, H2C_FUNC_CFG_BCNFLTR = 0x1e, H2C_FUNC_OFLD_RSSI = 0x1f, @@ -4286,7 +4308,7 @@ struct rtw89_h2c_rf_dack { __le32 type; } __packed; -struct rtw89_h2c_rf_rxdck { +struct rtw89_h2c_rf_rxdck_v0 { u8 len; u8 phy; u8 is_afe; @@ -4297,6 +4319,11 @@ struct rtw89_h2c_rf_rxdck { u8 rxdck_dbg_en; } __packed; +struct rtw89_h2c_rf_rxdck { + struct rtw89_h2c_rf_rxdck_v0 v0; + u8 is_chl_k; +} __packed; + enum rtw89_rf_log_type { RTW89_RF_RUN_LOG = 0, RTW89_RF_RPT_LOG = 1, @@ -4313,6 +4340,42 @@ struct rtw89_c2h_rf_run_log { __le32 arg[4]; } __packed; +struct rtw89_c2h_rf_iqk_rpt_log { + bool iqk_tx_fail[2]; + bool iqk_rx_fail[2]; + bool is_iqk_init; + bool is_reload; + bool is_wb_txiqk[2]; + bool is_wb_rxiqk[2]; + bool is_nbiqk; + bool txiqk_en; + bool rxiqk_en; + bool lok_en; + bool iqk_xym_en; + bool iqk_sram_en; + bool iqk_fft_en; + bool is_fw_iqk; + bool is_iqk_enable; + bool iqk_cfir_en; + bool thermal_rek_en; + u8 iqk_band[2]; + u8 iqk_ch[2]; + u8 iqk_bw[2]; + u8 iqk_times; + u8 version; + u8 phy; + u8 fwk_status; + u8 rsvd; + __le32 reload_cnt; + __le32 iqk_fail_cnt; + __le32 lok_idac[2]; + __le32 lok_vbuf[2]; + __le32 rftxgain[2][4]; + __le32 rfrxgain[2][4]; + __le32 tx_xym[2][4]; + __le32 rx_xym[2][4]; +} __packed; + struct rtw89_c2h_rf_dpk_rpt_log { u8 ver; u8 idx[2]; @@ -4334,19 +4397,25 @@ struct rtw89_c2h_rf_dpk_rpt_log { struct rtw89_c2h_rf_dack_rpt_log { u8 fwdack_ver; - u8 fwdack_rpt_ver; + u8 fwdack_info_ver; u8 msbk_d[2][2][16]; u8 dadck_d[2][2]; u8 cdack_d[2][2][2]; - __le16 addck2_d[2][2][2]; + u8 addck2_hd[2][2][2]; + u8 addck2_ld[2][2][2]; u8 adgaink_d[2][2]; - __le16 biask_d[2][2]; + u8 biask_hd[2][2]; + u8 biask_ld[2][2]; u8 addck_timeout; u8 cdack_timeout; u8 dadck_timeout; u8 msbk_timeout; u8 adgaink_timeout; + u8 wbadcdck_timeout; + u8 drck_timeout; u8 dack_fail; + u8 wbdck_d[2]; + u8 rck_d; } __packed; struct rtw89_c2h_rf_rxdck_rpt_log { @@ -4357,6 +4426,14 @@ struct rtw89_c2h_rf_rxdck_rpt_log { u8 timeout[2]; } __packed; +struct rtw89_c2h_rf_tssi_rpt_log { + s8 alignment_power[2][2][4]; + u8 alignment_power_cw_h[2][2][4]; + u8 alignment_power_cw_l[2][2][4]; + u8 tssi_alimk_state[2][2]; + u8 default_txagc_offset[2][2]; +} __packed; + struct rtw89_c2h_rf_txgapk_rpt_log { __le32 r0x8010[2]; __le32 chk_cnt; @@ -4404,59 +4481,60 @@ void rtw89_h2c_pkt_set_hdr(struct rtw89_dev *rtwdev, struct sk_buff *skb, u8 type, u8 cat, u8 class, u8 func, bool rack, bool dack, u32 len); int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta); + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta); + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); -int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif, - struct rtw89_sta *rtwsta, const u8 *scan_mac_addr); + struct rtw89_vif_link *rtwvif_link); +int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif, + struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr); int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct work_struct *work); int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, enum rtw89_upd_mode upd_mode); -int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, bool dis_conn); +int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool dis_conn); int rtw89_fw_h2c_notify_dbcc(struct rtw89_dev *rtwdev, bool en); int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, bool pause); -int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u8 ac, u32 val); int rtw89_fw_h2c_set_ofld_cfg(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_tx_duty(struct rtw89_dev *rtwdev, u8 lv); int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, + struct rtw89_vif_link *rtwvif_link, bool connect); int rtw89_fw_h2c_rssi_offload(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu); -int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi); int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type); @@ -4472,17 +4550,13 @@ int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id); int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, struct sk_buff *skb_ofld); -int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, - struct list_head *chan_list); -int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, - struct list_head *chan_list); int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, struct rtw89_scan_option *opt, - struct rtw89_vif *vif, + struct rtw89_vif_link *vif, bool wowlan); int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, struct rtw89_scan_option *opt, - struct rtw89_vif *vif, + struct rtw89_vif_link *vif, bool wowlan); int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, @@ -4501,21 +4575,26 @@ int rtw89_fw_h2c_rf_txgapk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan); int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, - const struct rtw89_chan *chan); + const struct rtw89_chan *chan, bool is_chl_k); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack); int rtw89_fw_h2c_raw(struct rtw89_dev *rtwdev, const u8 *buf, u16 len); void rtw89_fw_send_all_early_h2c(struct rtw89_dev *rtwdev); void rtw89_fw_free_all_early_h2c(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u8 macid); void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool notify_fw); + struct rtw89_vif_link *rtwvif_link, + bool notify_fw); void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw); -int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params); -int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params); void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, @@ -4524,8 +4603,8 @@ int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param); int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); -int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link); +int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); struct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(struct rtw89_dev *rtwdev, u32 len); struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len); @@ -4534,49 +4613,56 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev, struct rtw89_mac_c2h_info *c2h_info); int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable); void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev); -void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_scan_request *req); -void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_scan_request *scan_req); +void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool aborted); -int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool enable); -void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected); + struct rtw89_vif_link *rtwvif_link, bool connected); int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected); + struct rtw89_vif_link *rtwvif_link, bool connected); int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, const struct rtw89_pkt_drop_params *params); -int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf, struct ieee80211_p2p_noa_desc *desc, u8 act, u8 noa_id); -int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool en); -int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable); -int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable); +int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); -int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable); + struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable); -int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable); +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable); + struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, struct rtw89_wow_cam_info *cam_info); int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_wow_request_aoac(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_add_mcc(struct rtw89_dev *rtwdev, @@ -4621,51 +4707,73 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) } static inline int rtw89_chip_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; - return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); + return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); } static inline int rtw89_chip_h2c_default_dmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->ops->h2c_default_dmac_tbl) - return chip->ops->h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta); + return chip->ops->h2c_default_dmac_tbl(rtwdev, rtwvif_link, rtwsta_link); return 0; } static inline int rtw89_chip_h2c_update_beacon(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chip_info *chip = rtwdev->chip; - return chip->ops->h2c_update_beacon(rtwdev, rtwvif); + return chip->ops->h2c_update_beacon(rtwdev, rtwvif_link); } static inline int rtw89_chip_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; - return chip->ops->h2c_assoc_cmac_tbl(rtwdev, vif, sta); + return chip->ops->h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); } -static inline int rtw89_chip_h2c_ampdu_cmac_tbl(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static inline +int rtw89_chip_h2c_ampdu_link_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->ops->h2c_ampdu_cmac_tbl) - return chip->ops->h2c_ampdu_cmac_tbl(rtwdev, vif, sta); + return chip->ops->h2c_ampdu_cmac_tbl(rtwdev, rtwvif_link, + rtwsta_link); + + return 0; +} + +static inline int rtw89_chip_h2c_ampdu_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = rtw89_chip_h2c_ampdu_link_cmac_tbl(rtwdev, rtwvif_link, + rtwsta_link); + if (ret) + return ret; + } return 0; } @@ -4675,8 +4783,20 @@ int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) { const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = chip->ops->h2c_ba_cam(rtwdev, rtwvif_link, rtwsta_link, + valid, params); + if (ret) + return ret; + } - return chip->ops->h2c_ba_cam(rtwdev, rtwsta, valid, params); + return 0; } /* must consider compatibility; don't insert new in the mid */ diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index c70a23a763b0..7907b84d204b 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1444,6 +1444,7 @@ void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev) static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) { #define PWR_ACT 1 + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_pwr_cfg * const *cfg_seq; int (*cfg_func)(struct rtw89_dev *rtwdev); @@ -1472,6 +1473,9 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) return ret; if (on) { + if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) + mac->efuse_read_fw_secure(rtwdev); + set_bit(RTW89_FLAG_POWERON, rtwdev->flags); set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); @@ -1483,7 +1487,8 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_PWR_MAJOR); - rtw89_set_entity_state(rtwdev, false); + rtw89_set_entity_state(rtwdev, RTW89_PHY_0, false); + rtw89_set_entity_state(rtwdev, RTW89_PHY_1, false); } return 0; @@ -3995,9 +4000,10 @@ fail: static void rtw89_mac_dmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid) { + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; u8 i; - if (rtwdev->chip->chip_gen != RTW89_CHIP_AX) + if (rtwdev->chip->chip_gen != RTW89_CHIP_AX || sec->secure_boot) return; for (i = 0; i < 4; i++) { @@ -4009,7 +4015,9 @@ static void rtw89_mac_dmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid) static void rtw89_mac_cmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid) { - if (rtwdev->chip->chip_gen != RTW89_CHIP_AX) + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + + if (rtwdev->chip->chip_gen != RTW89_CHIP_AX || sec->secure_boot) return; rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, @@ -4076,17 +4084,17 @@ static const struct rtw89_port_reg rtw89_port_base_ax = { }; static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u8 type) + struct rtw89_vif_link *rtwvif_link, u8 type) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif->port); + u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif_link->port); u32 reg_info, reg_ctrl; u32 val; int ret; - reg_info = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg_info, rtwvif->mac_idx); - reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg, rtwvif->mac_idx); + reg_info = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg_info, rtwvif_link->mac_idx); + reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg_ctrl, B_AX_PTCL_DBG_SEL_MASK, type); rtw89_write32_set(rtwdev, reg_ctrl, B_AX_PTCL_DBG_EN); @@ -4098,26 +4106,32 @@ static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev, rtw89_warn(rtwdev, "Polling beacon packet empty fail\n"); } -static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_set(rtwdev, p->bcn_drop_all, BIT(rtwvif->port)); - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, 1); - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, 0); - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 0); - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK, 2); - rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK, 1); - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_space, B_AX_BCN_SPACE_MASK, 1); - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); - - rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM0); - if (rtwvif->port == RTW89_PORT_0) - rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM1); - - rtw89_write32_clr(rtwdev, p->bcn_drop_all, BIT(rtwvif->port)); - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TBTT_PROHIB_EN); + rtw89_write32_set(rtwdev, p->bcn_drop_all, BIT(rtwvif_link->port)); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, + 1); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, + 0); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, + 0); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_early, B_AX_BCNERLY_MASK, 2); + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_early, + B_AX_TBTTERLY_MASK, 1); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_space, + B_AX_BCN_SPACE_MASK, 1); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_BCNTX_EN); + + rtw89_mac_check_packet_ctrl(rtwdev, rtwvif_link, AX_PTCL_DBG_BCNQ_NUM0); + if (rtwvif_link->port == RTW89_PORT_0) + rtw89_mac_check_packet_ctrl(rtwdev, rtwvif_link, AX_PTCL_DBG_BCNQ_NUM1); + + rtw89_write32_clr(rtwdev, p->bcn_drop_all, BIT(rtwvif_link->port)); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_TBTT_PROHIB_EN); fsleep(2000); } @@ -4131,286 +4145,329 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvi #define BCN_ERLY_SET_DLY (10 * 2) static void rtw89_mac_port_cfg_func_sw(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); const struct rtw89_chip_info *chip = rtwdev->chip; + struct ieee80211_bss_conf *bss_conf; bool need_backup = false; u32 backup_val; + u16 beacon_int; - if (!rtw89_read32_port_mask(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN)) + if (!rtw89_read32_port_mask(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN)) return; - if (chip->chip_id == RTL8852A && rtwvif->port != RTW89_PORT_0) { + if (chip->chip_id == RTL8852A && rtwvif_link->port != RTW89_PORT_0) { need_backup = true; - backup_val = rtw89_read32_port(rtwdev, rtwvif, p->tbtt_prohib); + backup_val = rtw89_read32_port(rtwdev, rtwvif_link, p->tbtt_prohib); } - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) - rtw89_mac_bcn_drop(rtwdev, rtwvif); + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) + rtw89_mac_bcn_drop(rtwdev, rtwvif_link); if (chip->chip_id == RTL8852A) { - rtw89_write32_port_clr(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK); - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 1); - rtw89_write16_port_clr(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK); - rtw89_write16_port_clr(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->tbtt_prohib, + B_AX_TBTT_SETUP_MASK); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, + B_AX_TBTT_HOLD_MASK, 1); + rtw89_write16_port_clr(rtwdev, rtwvif_link, p->tbtt_early, + B_AX_TBTTERLY_MASK); + rtw89_write16_port_clr(rtwdev, rtwvif_link, p->bcn_early, + B_AX_BCNERLY_MASK); } - msleep(vif->bss_conf.beacon_int + 1); - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN | + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + beacon_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + msleep(beacon_int + 1); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN | B_AX_BRK_SETUP); - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSFTR_RST); - rtw89_write32_port(rtwdev, rtwvif, p->bcn_cnt_tmr, 0); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSFTR_RST); + rtw89_write32_port(rtwdev, rtwvif_link, p->bcn_cnt_tmr, 0); if (need_backup) - rtw89_write32_port(rtwdev, rtwvif, p->tbtt_prohib, backup_val); + rtw89_write32_port(rtwdev, rtwvif_link, p->tbtt_prohib, backup_val); } static void rtw89_mac_port_cfg_tx_rpt(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TXBCN_RPT_EN); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, + B_AX_TXBCN_RPT_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TXBCN_RPT_EN); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, + B_AX_TXBCN_RPT_EN); } static void rtw89_mac_port_cfg_rx_rpt(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_RXBCN_RPT_EN); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, + B_AX_RXBCN_RPT_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_RXBCN_RPT_EN); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, + B_AX_RXBCN_RPT_EN); } static void rtw89_mac_port_cfg_net_type(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->port_cfg, B_AX_NET_TYPE_MASK, - rtwvif->net_type); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->port_cfg, B_AX_NET_TYPE_MASK, + rtwvif_link->net_type); } static void rtw89_mac_port_cfg_bcn_prct(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - bool en = rtwvif->net_type != RTW89_NET_TYPE_NO_LINK; + bool en = rtwvif_link->net_type != RTW89_NET_TYPE_NO_LINK; u32 bits = B_AX_TBTT_PROHIB_EN | B_AX_BRK_SETUP; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, bits); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, bits); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, bits); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, bits); } static void rtw89_mac_port_cfg_rx_sw(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + bool en = rtwvif_link->net_type == RTW89_NET_TYPE_INFRA || + rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC; u32 bit = B_AX_RX_BSSID_FIT_EN; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, bit); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, bit); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, bit); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, bit); } void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSF_UDT_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSF_UDT_EN); } static void rtw89_mac_port_cfg_rx_sync_by_nettype(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + bool en = rtwvif_link->net_type == RTW89_NET_TYPE_INFRA || + rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC; - rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, en); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, en); } static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_BCNTX_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_BCNTX_EN); } static void rtw89_mac_port_cfg_tx_sw_by_nettype(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - bool en = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + bool en = rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || + rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC; - rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en); + rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); } void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; rtw89_for_each_rtwvif(rtwdev, rtwvif) - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) - rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) + rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); } static void rtw89_mac_port_cfg_bcn_intv(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - u16 bcn_int = vif->bss_conf.beacon_int ? vif->bss_conf.beacon_int : BCN_INTERVAL; + struct ieee80211_bss_conf *bss_conf; + u16 bcn_int; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (bss_conf->beacon_int) + bcn_int = bss_conf->beacon_int; + else + bcn_int = BCN_INTERVAL; - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_space, B_AX_BCN_SPACE_MASK, + rcu_read_unlock(); + + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_space, B_AX_BCN_SPACE_MASK, bcn_int); } static void rtw89_mac_port_cfg_hiq_win(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - u8 win = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE ? 16 : 0; + u8 win = rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE ? 16 : 0; const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u32 reg; - reg = rtw89_mac_reg_by_idx(rtwdev, p->hiq_win[port], rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, p->hiq_win[port], rtwvif_link->mac_idx); rtw89_write8(rtwdev, reg, win); } static void rtw89_mac_port_cfg_hiq_dtim(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf; + u8 dtim_period; u32 addr; - addr = rtw89_mac_reg_by_idx(rtwdev, p->md_tsft, rtwvif->mac_idx); + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + dtim_period = bss_conf->dtim_period; + + rcu_read_unlock(); + + addr = rtw89_mac_reg_by_idx(rtwdev, p->md_tsft, rtwvif_link->mac_idx); rtw89_write8_set(rtwdev, addr, B_AX_UPD_HGQMD | B_AX_UPD_TIMIE); - rtw89_write16_port_mask(rtwdev, rtwvif, p->dtim_ctrl, B_AX_DTIM_NUM_MASK, - vif->bss_conf.dtim_period); + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->dtim_ctrl, B_AX_DTIM_NUM_MASK, + dtim_period); } static void rtw89_mac_port_cfg_bcn_setup_time(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, BCN_SETUP_DEF); } static void rtw89_mac_port_cfg_bcn_hold_time(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, BCN_HOLD_DEF); } static void rtw89_mac_port_cfg_bcn_mask_area(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_area, + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, BCN_MASK_DEF); } static void rtw89_mac_port_cfg_tbtt_early(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_early, + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_early, B_AX_TBTTERLY_MASK, TBTT_ERLY_DEF); } static void rtw89_mac_port_cfg_bss_color(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); static const u32 masks[RTW89_PORT_NUM] = { B_AX_BSS_COLOB_AX_PORT_0_MASK, B_AX_BSS_COLOB_AX_PORT_1_MASK, B_AX_BSS_COLOB_AX_PORT_2_MASK, B_AX_BSS_COLOB_AX_PORT_3_MASK, B_AX_BSS_COLOB_AX_PORT_4_MASK, }; - u8 port = rtwvif->port; + struct ieee80211_bss_conf *bss_conf; + u8 port = rtwvif_link->port; u32 reg_base; u32 reg; u8 bss_color; - bss_color = vif->bss_conf.he_bss_color.color; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + bss_color = bss_conf->he_bss_color.color; + + rcu_read_unlock(); + reg_base = port >= 4 ? p->bss_color + 4 : p->bss_color; - reg = rtw89_mac_reg_by_idx(rtwdev, reg_base, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, reg_base, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, masks[port], bss_color); } static void rtw89_mac_port_cfg_mbssid(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u32 reg; - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) return; if (port == 0) { - reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid, rtwvif_link->mac_idx); rtw89_write32_clr(rtwdev, reg, B_AX_P0MB_ALL_MASK); } } static void rtw89_mac_port_cfg_hiq_drop(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u32 reg; u32 val; - reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid_drop, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid_drop, rtwvif_link->mac_idx); val = rtw89_read32(rtwdev, reg); val &= ~FIELD_PREP(B_AX_PORT_DROP_4_0_MASK, BIT(port)); if (port == 0) @@ -4419,31 +4476,31 @@ static void rtw89_mac_port_cfg_hiq_drop(struct rtw89_dev *rtwdev, } static void rtw89_mac_port_cfg_func_en(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable) + struct rtw89_vif_link *rtwvif_link, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (enable) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN); } static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK, + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_early, B_AX_BCNERLY_MASK, BCN_ERLY_DEF); } static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; @@ -4452,20 +4509,20 @@ static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev, if (rtwdev->chip->chip_id != RTL8852C) return; - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT && - rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION) + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION) return; val = FIELD_PREP(B_AX_TBTT_SHIFT_OFST_MAG, 1) | B_AX_TBTT_SHIFT_OFST_SIGN; - rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_shift, + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift, B_AX_TBTT_SHIFT_OFST_MASK, val); } void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_vif *rtwvif_src, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_vif_link *rtwvif_src, u16 offset_tu) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -4473,8 +4530,8 @@ void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, u32 val, reg; val = RTW89_PORT_OFFSET_TU_TO_32US(offset_tu); - reg = rtw89_mac_reg_by_idx(rtwdev, p->tsf_sync + rtwvif->port * 4, - rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, p->tsf_sync + rtwvif_link->port * 4, + rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_SRC, rtwvif_src->port); rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_OFFSET_VAL, val); @@ -4482,16 +4539,16 @@ void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, } static void rtw89_mac_port_tsf_sync_rand(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_vif *rtwvif_src, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_vif_link *rtwvif_src, u8 offset, int *n_offset) { - if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif == rtwvif_src) + if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif_link == rtwvif_src) return; /* adjust offset randomly to avoid beacon conflict */ offset = offset - offset / 4 + get_random_u32() % (offset / 2); - rtw89_mac_port_tsf_sync(rtwdev, rtwvif, rtwvif_src, + rtw89_mac_port_tsf_sync(rtwdev, rtwvif_link, rtwvif_src, (*n_offset) * offset); (*n_offset)++; @@ -4499,15 +4556,19 @@ static void rtw89_mac_port_tsf_sync_rand(struct rtw89_dev *rtwdev, static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev) { - struct rtw89_vif *src = NULL, *tmp; + struct rtw89_vif_link *src = NULL, *tmp; u8 offset = 100, vif_aps = 0; + struct rtw89_vif *rtwvif; + unsigned int link_id; int n_offset = 1; - rtw89_for_each_rtwvif(rtwdev, tmp) { - if (!src || tmp->net_type == RTW89_NET_TYPE_INFRA) - src = tmp; - if (tmp->net_type == RTW89_NET_TYPE_AP_MODE) - vif_aps++; + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + rtw89_vif_for_each_link(rtwvif, tmp, link_id) { + if (!src || tmp->net_type == RTW89_NET_TYPE_INFRA) + src = tmp; + if (tmp->net_type == RTW89_NET_TYPE_AP_MODE) + vif_aps++; + } } if (vif_aps == 0) @@ -4515,104 +4576,106 @@ static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev) offset /= (vif_aps + 1); - rtw89_for_each_rtwvif(rtwdev, tmp) - rtw89_mac_port_tsf_sync_rand(rtwdev, tmp, src, offset, &n_offset); + rtw89_for_each_rtwvif(rtwdev, rtwvif) + rtw89_vif_for_each_link(rtwvif, tmp, link_id) + rtw89_mac_port_tsf_sync_rand(rtwdev, tmp, src, offset, + &n_offset); } -int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { int ret; - ret = rtw89_mac_port_update(rtwdev, rtwvif); + ret = rtw89_mac_port_update(rtwdev, rtwvif_link); if (ret) return ret; - rtw89_mac_dmac_tbl_init(rtwdev, rtwvif->mac_id); - rtw89_mac_cmac_tbl_init(rtwdev, rtwvif->mac_id); + rtw89_mac_dmac_tbl_init(rtwdev, rtwvif_link->mac_id); + rtw89_mac_cmac_tbl_init(rtwdev, rtwvif_link->mac_id); - ret = rtw89_mac_set_macid_pause(rtwdev, rtwvif->mac_id, false); + ret = rtw89_mac_set_macid_pause(rtwdev, rtwvif_link->mac_id, false); if (ret) return ret; - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_CREATE); + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_CREATE); if (ret) return ret; - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true); if (ret) return ret; - ret = rtw89_cam_init(rtwdev, rtwvif); + ret = rtw89_cam_init(rtwdev, rtwvif_link); if (ret) return ret; - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); if (ret) return ret; - ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, NULL); + ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif_link, NULL); if (ret) return ret; - ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, NULL); + ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif_link, NULL); if (ret) return ret; return 0; } -int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { int ret; - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_REMOVE); + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_REMOVE); if (ret) return ret; - rtw89_cam_deinit(rtwdev, rtwvif); + rtw89_cam_deinit(rtwdev, rtwvif_link); - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); if (ret) return ret; return 0; } -int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; if (port >= RTW89_PORT_NUM) return -EINVAL; - rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif); - rtw89_mac_port_cfg_tx_rpt(rtwdev, rtwvif, false); - rtw89_mac_port_cfg_rx_rpt(rtwdev, rtwvif, false); - rtw89_mac_port_cfg_net_type(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif); - rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif); - rtw89_mac_port_cfg_rx_sync_by_nettype(rtwdev, rtwvif); - rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif); - rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif); - rtw89_mac_port_cfg_hiq_dtim(rtwdev, rtwvif); - rtw89_mac_port_cfg_hiq_drop(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_setup_time(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif); - rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif); - rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif); - rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif); - rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif); - rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, true); + rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tx_rpt(rtwdev, rtwvif_link, false); + rtw89_mac_port_cfg_rx_rpt(rtwdev, rtwvif_link, false); + rtw89_mac_port_cfg_net_type(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_rx_sync_by_nettype(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_hiq_dtim(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_hiq_drop(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_setup_time(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_func_en(rtwdev, rtwvif_link, true); rtw89_mac_port_tsf_resync_all(rtwdev); fsleep(BCN_ERLY_SET_DLY); - rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif); + rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif_link); return 0; } -int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u64 *tsf) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -4620,12 +4683,12 @@ int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 tsf_low, tsf_high; int ret; - ret = rtw89_mac_check_mac_en(rtwdev, rtwvif->mac_idx, RTW89_CMAC_SEL); + ret = rtw89_mac_check_mac_en(rtwdev, rtwvif_link->mac_idx, RTW89_CMAC_SEL); if (ret) return ret; - tsf_low = rtw89_read32_port(rtwdev, rtwvif, p->tsftr_l); - tsf_high = rtw89_read32_port(rtwdev, rtwvif, p->tsftr_h); + tsf_low = rtw89_read32_port(rtwdev, rtwvif_link, p->tsftr_l); + tsf_high = rtw89_read32_port(rtwdev, rtwvif_link, p->tsftr_h); *tsf = (u64)tsf_high << 32 | tsf_low; return 0; @@ -4651,65 +4714,57 @@ static void rtw89_mac_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, } void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif) + struct rtw89_vif_link *rtwvif_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct ieee80211_hw *hw = rtwdev->hw; + struct ieee80211_bss_conf *bss_conf; + struct cfg80211_chan_def oper; bool tolerated = true; u32 reg; - if (!vif->bss_conf.he_support || vif->type != NL80211_IFTYPE_STATION) + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->he_support || vif->type != NL80211_IFTYPE_STATION) { + rcu_read_unlock(); return; + } - if (!(vif->bss_conf.chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR)) + oper = bss_conf->chanreq.oper; + if (!(oper.chan->flags & IEEE80211_CHAN_RADAR)) { + rcu_read_unlock(); return; + } - cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chanreq.oper, + rcu_read_unlock(); + + cfg80211_bss_iter(hw->wiphy, &oper, rtw89_mac_check_he_obss_narrow_bw_ru_iter, &tolerated); reg = rtw89_mac_reg_by_idx(rtwdev, mac->narrow_bw_ru_dis.addr, - rtwvif->mac_idx); + rtwvif_link->mac_idx); if (tolerated) rtw89_write32_clr(rtwdev, reg, mac->narrow_bw_ru_dis.mask); else rtw89_write32_set(rtwdev, reg, mac->narrow_bw_ru_dis.mask); } -void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif); + rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif_link); } -int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - int ret; - - rtwvif->mac_id = rtw89_acquire_mac_id(rtwdev); - if (rtwvif->mac_id == RTW89_MAX_MAC_ID_NUM) - return -ENOSPC; - - ret = rtw89_mac_vif_init(rtwdev, rtwvif); - if (ret) - goto release_mac_id; - - return 0; - -release_mac_id: - rtw89_release_mac_id(rtwdev, rtwvif->mac_id); - - return ret; + return rtw89_mac_vif_init(rtwdev, rtwvif_link); } -int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - int ret; - - ret = rtw89_mac_vif_deinit(rtwdev, rtwvif); - rtw89_release_mac_id(rtwdev, rtwvif->mac_id); - - return ret; + return rtw89_mac_vif_deinit(rtwdev, rtwvif_link); } static void @@ -4730,8 +4785,8 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, { const struct rtw89_c2h_scanofld *c2h = (const struct rtw89_c2h_scanofld *)skb->data; - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + struct rtw89_vif *rtwvif; struct rtw89_chan new; u8 reason, status, tx_fail, band, actual_period, expect_period; u32 last_chan = rtwdev->scan_info.last_chan_idx, report_tsf; @@ -4739,9 +4794,11 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, u16 chan; int ret; - if (!rtwvif) + if (!rtwvif_link) return; + rtwvif = rtwvif_link->rtwvif; + tx_fail = le32_get_bits(c2h->w5, RTW89_C2H_SCANOFLD_W5_TX_FAIL); status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); chan = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_PRI_CH); @@ -4781,28 +4838,28 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (rtwdev->scan_info.abort) return; - if (rtwvif && rtwvif->scan_req && + if (rtwvif_link && rtwvif->scan_req && last_chan < rtwvif->scan_req->n_channels) { - ret = rtw89_hw_scan_offload(rtwdev, vif, true); + ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true); if (ret) { - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwvif_link); rtw89_warn(rtwdev, "HW scan failed: %d\n", ret); } } else { - rtw89_hw_scan_complete(rtwdev, vif, false); + rtw89_hw_scan_complete(rtwdev, rtwvif_link, false); } break; case RTW89_SCAN_ENTER_OP_NOTIFY: case RTW89_SCAN_ENTER_CH_NOTIFY: if (rtw89_is_op_chan(rtwdev, band, chan)) { - rtw89_assign_entity_chan(rtwdev, rtwvif->chanctx_idx, + rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, &rtwdev->scan_info.op_chan); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); ieee80211_wake_queues(rtwdev->hw); } else { rtw89_chan_create(&new, chan, chan, band, RTW89_CHANNEL_WIDTH_20); - rtw89_assign_entity_chan(rtwdev, rtwvif->chanctx_idx, + rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, &new); } break; @@ -4812,10 +4869,11 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, } static void -rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct sk_buff *skb) { - struct ieee80211_vif *vif = rtwvif_to_vif_safe(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; enum nl80211_cqm_rssi_threshold_event nl_event; const struct rtw89_c2h_mac_bcnfltr_rpt *c2h = (const struct rtw89_c2h_mac_bcnfltr_rpt *)skb->data; @@ -4827,7 +4885,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, event = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_EVENT); mac_id = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_MACID); - if (mac_id != rtwvif->mac_id) + if (mac_id != rtwvif_link->mac_id) return; rtw89_debug(rtwdev, RTW89_DBG_FW, @@ -4839,7 +4897,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, if (!rtwdev->scanning && !rtwvif->offchan) ieee80211_connection_loss(vif); else - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); return; case RTW89_BCN_FLTR_NOTIFY: nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; @@ -4863,10 +4921,13 @@ static void rtw89_mac_c2h_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_bcn_fltr_rpt(rtwdev, rtwvif, c2h); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_bcn_fltr_rpt(rtwdev, rtwvif_link, c2h); } static void @@ -4975,6 +5036,18 @@ rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, } static void +rtw89_mac_c2h_tx_duty_rpt(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len) +{ + struct rtw89_c2h_tx_duty_rpt *c2h = + (struct rtw89_c2h_tx_duty_rpt *)skb_c2h->data; + u8 err; + + err = le32_get_bits(c2h->w2, RTW89_C2H_TX_DUTY_RPT_W2_TIMER_ERR); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "C2H TX duty rpt with err=%d\n", err); +} + +static void rtw89_mac_c2h_tsf32_toggle_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { @@ -5300,6 +5373,7 @@ void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_BCN_RESEND] = NULL, [RTW89_MAC_C2H_FUNC_MACID_PAUSE] = rtw89_mac_c2h_macid_pause, [RTW89_MAC_C2H_FUNC_SCANOFLD_RSP] = rtw89_mac_c2h_scanofld_rsp, + [RTW89_MAC_C2H_FUNC_TX_DUTY_RPT] = rtw89_mac_c2h_tx_duty_rpt, [RTW89_MAC_C2H_FUNC_TSF32_TOGL_RPT] = rtw89_mac_c2h_tsf32_toggle_rpt, [RTW89_MAC_C2H_FUNC_BCNFLTR_RPT] = rtw89_mac_c2h_bcn_fltr_rpt, }; @@ -5490,7 +5564,8 @@ int rtw89_mac_cfg_ppdu_status_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool enab return 0; } -void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx) +static +void __rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx) { #define MAC_AX_TIME_TH_SH 5 #define MAC_AX_LEN_TH_SH 4 @@ -5520,6 +5595,13 @@ void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write16_mask(rtwdev, reg, B_AX_RTS_LEN_TH_MASK, len_th); } +void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev) +{ + __rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); + if (rtwdev->dbcc_en) + __rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_1); +} + void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop) { bool empty; @@ -5931,15 +6013,15 @@ static int rtw89_mac_init_bfee_ax(struct rtw89_dev *rtwdev, u8 mac_idx) } static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - u8 mac_idx = rtwvif->mac_idx; u8 nc = 1, nr = 3, ng = 0, cb = 1, cs = 1, ldpc_en = 1, stbc_en = 1; - u8 port_sel = rtwvif->port; + struct ieee80211_link_sta *link_sta; + u8 mac_idx = rtwvif_link->mac_idx; + u8 port_sel = rtwvif_link->port; u8 sound_dim = 3, t; - u8 *phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info; + u8 *phy_cap; u32 reg; u16 val; int ret; @@ -5948,6 +6030,11 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev, if (ret) return ret; + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info; + if ((phy_cap[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) || (phy_cap[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) { ldpc_en &= !!(phy_cap[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD); @@ -5956,17 +6043,19 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev, phy_cap[5]); sound_dim = min(sound_dim, t); } - if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { - ldpc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); - stbc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK); + if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { + ldpc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); + stbc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK); t = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, - sta->deflink.vht_cap.cap); + link_sta->vht_cap.cap); sound_dim = min(sound_dim, t); } nc = min(nc, sound_dim); nr = min(nr, sound_dim); + rcu_read_unlock(); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); rtw89_write32_set(rtwdev, reg, B_AX_BFMEE_BFPARAM_SEL); @@ -5989,34 +6078,41 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev, } static int rtw89_mac_csi_rrsc_ax(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; u32 rrsc = BIT(RTW89_MAC_BF_RRSC_6M) | BIT(RTW89_MAC_BF_RRSC_24M); + struct ieee80211_link_sta *link_sta; + u8 mac_idx = rtwvif_link->mac_idx; u32 reg; - u8 mac_idx = rtwvif->mac_idx; int ret; ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) return ret; - if (sta->deflink.he_cap.has_he) { + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->he_cap.has_he) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_HE_MSC0) | BIT(RTW89_MAC_BF_RRSC_HE_MSC3) | BIT(RTW89_MAC_BF_RRSC_HE_MSC5)); } - if (sta->deflink.vht_cap.vht_supported) { + if (link_sta->vht_cap.vht_supported) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_VHT_MSC0) | BIT(RTW89_MAC_BF_RRSC_VHT_MSC3) | BIT(RTW89_MAC_BF_RRSC_VHT_MSC5)); } - if (sta->deflink.ht_cap.ht_supported) { + if (link_sta->ht_cap.ht_supported) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_HT_MSC0) | BIT(RTW89_MAC_BF_RRSC_HT_MSC3) | BIT(RTW89_MAC_BF_RRSC_HT_MSC5)); } + + rcu_read_unlock(); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); rtw89_write32_set(rtwdev, reg, B_AX_BFMEE_BFPARAM_SEL); rtw89_write32_clr(rtwdev, reg, B_AX_BFMEE_CSI_FORCE_RETE_EN); @@ -6028,35 +6124,53 @@ static int rtw89_mac_csi_rrsc_ax(struct rtw89_dev *rtwdev, } static void rtw89_mac_bf_assoc_ax(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta; + bool has_beamformer_cap; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + has_beamformer_cap = rtw89_sta_has_beamformer_cap(link_sta); - if (rtw89_sta_has_beamformer_cap(sta)) { + rcu_read_unlock(); + + if (has_beamformer_cap) { rtw89_debug(rtwdev, RTW89_DBG_BF, "initialize bfee for new association\n"); - rtw89_mac_init_bfee_ax(rtwdev, rtwvif->mac_idx); - rtw89_mac_set_csi_para_reg_ax(rtwdev, vif, sta); - rtw89_mac_csi_rrsc_ax(rtwdev, vif, sta); + rtw89_mac_init_bfee_ax(rtwdev, rtwvif_link->mac_idx); + rtw89_mac_set_csi_para_reg_ax(rtwdev, rtwvif_link, rtwsta_link); + rtw89_mac_csi_rrsc_ax(rtwdev, rtwvif_link, rtwsta_link); } } -void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - - rtw89_mac_bfee_ctrl(rtwdev, rtwvif->mac_idx, false); + rtw89_mac_bfee_ctrl(rtwdev, rtwvif_link->mac_idx, false); } void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - u8 mac_idx = rtwvif->mac_idx; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + u8 mac_idx; __le32 *p; + rtwvif_link = rtwvif->links[conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, conf->link_id); + return; + } + + mac_idx = rtwvif_link->mac_idx; + rtw89_debug(rtwdev, RTW89_DBG_BF, "update bf GID table\n"); p = (__le32 *)conf->mu_group.membership; @@ -6080,7 +6194,7 @@ void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif * struct rtw89_mac_bf_monitor_iter_data { struct rtw89_dev *rtwdev; - struct ieee80211_sta *down_sta; + struct rtw89_sta_link *down_rtwsta_link; int count; }; @@ -6089,23 +6203,41 @@ void rtw89_mac_bf_monitor_calc_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_mac_bf_monitor_iter_data *iter_data = (struct rtw89_mac_bf_monitor_iter_data *)data; - struct ieee80211_sta *down_sta = iter_data->down_sta; + struct rtw89_sta_link *down_rtwsta_link = iter_data->down_rtwsta_link; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct ieee80211_link_sta *link_sta; + struct rtw89_sta_link *rtwsta_link; + bool has_beamformer_cap = false; int *count = &iter_data->count; + unsigned int link_id; - if (down_sta == sta) - return; + rcu_read_lock(); - if (rtw89_sta_has_beamformer_cap(sta)) + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + if (rtwsta_link == down_rtwsta_link) + continue; + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + if (rtw89_sta_has_beamformer_cap(link_sta)) { + has_beamformer_cap = true; + break; + } + } + + if (has_beamformer_cap) (*count)++; + + rcu_read_unlock(); } void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, bool disconnect) + struct rtw89_sta_link *rtwsta_link, + bool disconnect) { struct rtw89_mac_bf_monitor_iter_data data; data.rtwdev = rtwdev; - data.down_sta = disconnect ? sta : NULL; + data.down_rtwsta_link = disconnect ? rtwsta_link : NULL; data.count = 0; ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_mac_bf_monitor_calc_iter, @@ -6121,10 +6253,12 @@ void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev, void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) { struct rtw89_traffic_stats *stats = &rtwdev->stats; - struct rtw89_vif *rtwvif; + struct rtw89_vif_link *rtwvif_link; bool en = stats->tx_tfc_lv <= stats->rx_tfc_lv; bool old = test_bit(RTW89_FLAG_BFEE_EN, rtwdev->flags); + struct rtw89_vif *rtwvif; bool keep_timer = true; + unsigned int link_id; bool old_keep_timer; old_keep_timer = test_bit(RTW89_FLAG_BFEE_TIMER_KEEP, rtwdev->flags); @@ -6134,30 +6268,32 @@ void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) if (keep_timer != old_keep_timer) { rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_bfee_standby_timer(rtwdev, rtwvif->mac_idx, - keep_timer); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_bfee_standby_timer(rtwdev, rtwvif_link->mac_idx, + keep_timer); } if (en == old) return; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_bfee_ctrl(rtwdev, rtwvif->mac_idx, en); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_bfee_ctrl(rtwdev, rtwvif_link->mac_idx, en); } static int -__rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +__rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, u32 tx_time) { #define MAC_AX_DFLT_TX_TIME 5280 - u8 mac_idx = rtwsta->rtwvif->mac_idx; + u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx; u32 max_tx_time = tx_time == 0 ? MAC_AX_DFLT_TX_TIME : tx_time; u32 reg; int ret = 0; - if (rtwsta->cctl_tx_time) { - rtwsta->ampdu_max_time = (max_tx_time - 512) >> 9; - ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta); + if (rtwsta_link->cctl_tx_time) { + rtwsta_link->ampdu_max_time = (max_tx_time - 512) >> 9; + ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link); } else { ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) { @@ -6173,31 +6309,31 @@ __rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, return ret; } -int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, bool resume, u32 tx_time) { int ret = 0; if (!resume) { - rtwsta->cctl_tx_time = true; - ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta, tx_time); + rtwsta_link->cctl_tx_time = true; + ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta_link, tx_time); } else { - ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta, tx_time); - rtwsta->cctl_tx_time = false; + ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta_link, tx_time); + rtwsta_link->cctl_tx_time = false; } return ret; } -int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, u32 *tx_time) { - u8 mac_idx = rtwsta->rtwvif->mac_idx; + u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx; u32 reg; int ret = 0; - if (rtwsta->cctl_tx_time) { - *tx_time = (rtwsta->ampdu_max_time + 1) << 9; + if (rtwsta_link->cctl_tx_time) { + *tx_time = (rtwsta_link->ampdu_max_time + 1) << 9; } else { ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) { @@ -6213,33 +6349,33 @@ int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, } int rtw89_mac_set_tx_retry_limit(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, + struct rtw89_sta_link *rtwsta_link, bool resume, u8 tx_retry) { int ret = 0; - rtwsta->data_tx_cnt_lmt = tx_retry; + rtwsta_link->data_tx_cnt_lmt = tx_retry; if (!resume) { - rtwsta->cctl_tx_retry_limit = true; - ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta); + rtwsta_link->cctl_tx_retry_limit = true; + ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link); } else { - ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta); - rtwsta->cctl_tx_retry_limit = false; + ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link); + rtwsta_link->cctl_tx_retry_limit = false; } return ret; } int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 *tx_retry) + struct rtw89_sta_link *rtwsta_link, u8 *tx_retry) { - u8 mac_idx = rtwsta->rtwvif->mac_idx; + u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx; u32 reg; int ret = 0; - if (rtwsta->cctl_tx_retry_limit) { - *tx_retry = rtwsta->data_tx_cnt_lmt; + if (rtwsta_link->cctl_tx_retry_limit) { + *tx_retry = rtwsta_link->data_tx_cnt_lmt; } else { ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) { @@ -6255,10 +6391,10 @@ int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev, } int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; - u8 mac_idx = rtwvif->mac_idx; + u8 mac_idx = rtwvif_link->mac_idx; u16 set = mac->muedca_ctrl.mask; u32 reg; u32 ret; @@ -6326,7 +6462,9 @@ int rtw89_mac_read_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 *val) } static -void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) +void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { static const enum rtw89_pkt_drop_sel sels[] = { RTW89_PKT_DROP_SEL_MACID_BE_ONCE, @@ -6334,15 +6472,14 @@ void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) RTW89_PKT_DROP_SEL_MACID_VI_ONCE, RTW89_PKT_DROP_SEL_MACID_VO_ONCE, }; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_pkt_drop_params params = {0}; int i; - params.mac_band = RTW89_MAC_0; - params.macid = rtwsta->mac_id; - params.port = rtwvif->port; + params.mac_band = rtwvif_link->mac_idx; + params.macid = rtwsta_link->mac_id; + params.port = rtwvif_link->port; params.mbssid = 0; - params.tf_trs = rtwvif->trigger; + params.tf_trs = rtwvif_link->trigger; for (i = 0; i < ARRAY_SIZE(sels); i++) { params.sel = sels[i]; @@ -6352,15 +6489,21 @@ void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) static void rtw89_mac_pkt_drop_vif_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct rtw89_vif *rtwvif = rtwsta->rtwvif; - struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; struct rtw89_vif *target = data; + unsigned int link_id; if (rtwvif != target) return; - rtw89_mac_pkt_drop_sta(rtwdev, rtwsta); + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + rtw89_mac_pkt_drop_sta(rtwdev, rtwvif_link, rtwsta_link); + } } void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) @@ -6398,6 +6541,9 @@ int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable) struct rtw89_mac_c2h_info c2h_info = {}; u32 ret; + if (RTW89_CHK_FW_FEATURE(NO_WOW_CPU_IO_RX, &rtwdev->fw)) + return 0; + h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_WOW_CPUIO_RX_CTRL; h2c_info.content_len = sizeof(h2c_info.u.hdr); h2c_info.u.hdr.w0 = u32_encode_bits(wow_enable, RTW89_H2CREG_WOW_CPUIO_RX_CTRL_EN); @@ -6434,6 +6580,9 @@ static int rtw89_wow_config_mac_ax(struct rtw89_dev *rtwdev, bool enable_wow) rtw89_write32(rtwdev, R_AX_TF_FWD, 0); rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0); + if (RTW89_CHK_FW_FEATURE(NO_WOW_CPU_IO_RX, &rtwdev->fw)) + return 0; + if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) rtw89_write8(rtwdev, R_BE_DBG_WOW_READY, WOWLAN_NOT_READY); else @@ -6475,6 +6624,20 @@ int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev, rtwdev, R_AX_WCPU_FW_CTRL); } +static +void rtw89_fwdl_secure_idmem_share_mode_ax(struct rtw89_dev *rtwdev, u8 mode) +{ + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + + if (!sec->secure_boot) + return; + + rtw89_write32_mask(rtwdev, R_AX_WCPU_FW_CTRL, + B_AX_IDMEM_SHARE_MODE_RECORD_MASK, mode); + rtw89_write32_set(rtwdev, R_AX_WCPU_FW_CTRL, + B_AX_IDMEM_SHARE_MODE_RECORD_VALID); +} + const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .band1_offset = RTW89_MAC_AX_BAND_REG_OFFSET, .filter_model_addr = R_AX_FILTER_MODEL_ADDR, @@ -6528,9 +6691,11 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, .fwdl_get_status = rtw89_fw_get_rdy_ax, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_ax, + .fwdl_secure_idmem_share_mode = rtw89_fwdl_secure_idmem_share_mode_ax, .parse_efuse_map = rtw89_parse_efuse_map_ax, .parse_phycap_map = rtw89_parse_phycap_map_ax, .cnv_efuse_state = rtw89_cnv_efuse_state_ax, + .efuse_read_fw_secure = rtw89_efuse_read_fw_secure_ax, .cfg_plt = rtw89_mac_cfg_plt_ax, .get_plt_cnt = rtw89_mac_get_plt_cnt_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 67c2a4507124..18579c020548 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -391,6 +391,7 @@ enum rtw89_mac_c2h_ofld_func { RTW89_MAC_C2H_FUNC_MACID_PAUSE, RTW89_MAC_C2H_FUNC_TSF32_TOGL_RPT = 0x6, RTW89_MAC_C2H_FUNC_SCANOFLD_RSP = 0x9, + RTW89_MAC_C2H_FUNC_TX_DUTY_RPT = 0xa, RTW89_MAC_C2H_FUNC_BCNFLTR_RPT = 0xd, RTW89_MAC_C2H_FUNC_OFLD_MAX, }; @@ -951,8 +952,9 @@ struct rtw89_mac_gen_def { void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev); void (*dle_func_en)(struct rtw89_dev *rtwdev, bool enable); void (*dle_clk_en)(struct rtw89_dev *rtwdev, bool enable); - void (*bf_assoc)(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + void (*bf_assoc)(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*typ_fltr_opt)(struct rtw89_dev *rtwdev, enum rtw89_machdr_frame_type type, @@ -983,9 +985,11 @@ struct rtw89_mac_gen_def { bool dlfw, bool include_bb); u8 (*fwdl_get_status)(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type); int (*fwdl_check_path_ready)(struct rtw89_dev *rtwdev, bool h2c_or_fwdl); + void (*fwdl_secure_idmem_share_mode)(struct rtw89_dev *rtwdev, u8 mode); int (*parse_efuse_map)(struct rtw89_dev *rtwdev); int (*parse_phycap_map)(struct rtw89_dev *rtwdev); int (*cnv_efuse_state)(struct rtw89_dev *rtwdev, bool idle); + int (*efuse_read_fw_secure)(struct rtw89_dev *rtwdev); int (*cfg_plt)(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt); u16 (*get_plt_cnt)(struct rtw89_dev *rtwdev, u8 band); @@ -1004,12 +1008,12 @@ struct rtw89_mac_gen_def { bool (*is_txq_empty)(struct rtw89_dev *rtwdev); int (*add_chan_list)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected); + struct rtw89_vif_link *rtwvif_link, bool connected); int (*add_chan_list_pno)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); int (*scan_offload)(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool wowlan); int (*wow_config_mac)(struct rtw89_dev *rtwdev, bool enable_wow); @@ -1033,81 +1037,89 @@ u32 rtw89_mac_reg_by_port(struct rtw89_dev *rtwdev, u32 base, u8 port, u8 mac_id } static inline u32 -rtw89_read32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base) +rtw89_read32_port(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); return rtw89_read32(rtwdev, reg); } static inline u32 -rtw89_read32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_read32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 mask) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); return rtw89_read32_mask(rtwdev, reg, mask); } static inline void -rtw89_write32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base, +rtw89_write32_port(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 data) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write32(rtwdev, reg, data); } static inline void -rtw89_write32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 mask, u32 data) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, mask, data); } static inline void -rtw89_write16_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write16_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 mask, u16 data) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write16_mask(rtwdev, reg, mask, data); } static inline void -rtw89_write32_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write32_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 bit) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write32_clr(rtwdev, reg, bit); } static inline void -rtw89_write16_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write16_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u16 bit) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write16_clr(rtwdev, reg, bit); } static inline void -rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 bit) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write32_set(rtwdev, reg, bit); } @@ -1139,21 +1151,21 @@ int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_qempty *qempty); void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, enum mac_ax_err_info err); -int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); -int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); +int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_vif *rtwvif_src, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_vif_link *rtwvif_src, u16 offset_tu); -int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u64 *tsf); void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en); + struct rtw89_vif_link *rtwvif_link, bool en); void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif); -void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); +void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en); -int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); +int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); int rtw89_mac_enable_bb_rf(struct rtw89_dev *rtwdev); int rtw89_mac_disable_bb_rf(struct rtw89_dev *rtwdev); @@ -1213,7 +1225,22 @@ int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) return mac->cfg_ppdu_status(rtwdev, mac_idx, enable); } -void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx); +static inline +int rtw89_mac_cfg_ppdu_status_bands(struct rtw89_dev *rtwdev, bool enable) +{ + int ret; + + ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, enable); + if (ret) + return ret; + + if (!rtwdev->dbcc_en) + return 0; + + return rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_1, enable); +} + +void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev); void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop); int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex *coex); int rtw89_mac_coex_init_v1(struct rtw89_dev *rtwdev, @@ -1251,27 +1278,30 @@ void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter); void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev); static inline -void rtw89_mac_bf_assoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +void rtw89_mac_bf_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; if (mac->bf_assoc) - mac->bf_assoc(rtwdev, vif, sta); + mac->bf_assoc(rtwdev, rtwvif_link, rtwsta_link); } -void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); +void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf); void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, bool disconnect); + struct rtw89_sta_link *rtwsta_link, + bool disconnect); void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev); void rtw89_mac_bfee_ctrl(struct rtw89_dev *rtwdev, u8 mac_idx, bool en); -int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); -int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); +int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en); + struct rtw89_vif_link *rtwvif_link, bool en); int rtw89_mac_set_macid_pause(struct rtw89_dev *rtwdev, u8 macid, bool pause); static inline void rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) @@ -1376,15 +1406,15 @@ static inline bool rtw89_mac_get_power_state(struct rtw89_dev *rtwdev) return !!val; } -int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, bool resume, u32 tx_time); -int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, u32 *tx_time); int rtw89_mac_set_tx_retry_limit(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, + struct rtw89_sta_link *rtwsta_link, bool resume, u8 tx_retry); int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 *tx_retry); + struct rtw89_sta_link *rtwsta_link, u8 *tx_retry); enum rtw89_mac_xtal_si_offset { XTAL0 = 0x0, @@ -1466,4 +1496,14 @@ int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_rsvd_qt_cfg *cfg); int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable); +static inline +void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + if (!mac->fwdl_secure_idmem_share_mode) + return; + + return mac->fwdl_secure_idmem_share_mode(rtwdev, mode); +} #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 48ad0d0f76bf..619d2d3771d5 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -23,13 +23,13 @@ static void rtw89_ops_tx(struct ieee80211_hw *hw, struct rtw89_dev *rtwdev = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); struct ieee80211_sta *sta = control->sta; u32 flags = IEEE80211_SKB_CB(skb)->flags; int ret, qsel; if (rtwvif->offchan && !(flags & IEEE80211_TX_CTL_TX_OFFCHAN) && sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); rtw89_debug(rtwdev, RTW89_DBG_TXRX, "ops_tx during offchan\n"); skb_queue_tail(&rtwsta->roc_queue, skb); @@ -105,11 +105,61 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) return 0; } +static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct ieee80211_bss_conf *bss_conf; + int ret; + + rtw89_leave_ps_mode(rtwdev); + + rtw89_vif_type_mapping(rtwvif_link, false); + + INIT_WORK(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work); + INIT_LIST_HEAD(&rtwvif_link->general_pkt_list); + + rtwvif_link->hit_rule = 0; + rtwvif_link->bcn_hit_cond = 0; + rtwvif_link->chanctx_assigned = false; + rtwvif_link->chanctx_idx = RTW89_CHANCTX_0; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ether_addr_copy(rtwvif_link->mac_addr, bss_conf->addr); + + rcu_read_unlock(); + + ret = rtw89_mac_add_vif(rtwdev, rtwvif_link); + if (ret) + return ret; + + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, NULL, BTC_ROLE_START); + return 0; +} + +static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + mutex_unlock(&rtwdev->mutex); + cancel_work_sync(&rtwvif_link->update_beacon_work); + mutex_lock(&rtwdev->mutex); + + rtw89_leave_ps_mode(rtwdev); + + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, NULL, BTC_ROLE_STOP); + + rtw89_mac_remove_vif(rtwdev, rtwvif_link); +} + static int rtw89_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + u8 mac_id, port; int ret = 0; rtw89_debug(rtwdev, RTW89_DBG_STATE, "add vif %pM type %d, p2p %d\n", @@ -123,49 +173,58 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw, vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; - rtwvif->rtwdev = rtwdev; - rtwvif->roc.state = RTW89_ROC_IDLE; - rtwvif->offchan = false; + mac_id = rtw89_acquire_mac_id(rtwdev); + if (mac_id == RTW89_MAX_MAC_ID_NUM) { + ret = -ENOSPC; + goto err; + } + + port = rtw89_core_acquire_bit_map(rtwdev->hw_port, RTW89_PORT_NUM); + if (port == RTW89_PORT_NUM) { + ret = -ENOSPC; + goto release_macid; + } + + rtw89_init_vif(rtwdev, rtwvif, mac_id, port); + + rtw89_core_txq_init(rtwdev, vif->txq); + if (!rtw89_rtwvif_in_list(rtwdev, rtwvif)) list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); - INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work); + INIT_LIST_HEAD(&rtwvif->mgnt_entry); + + ether_addr_copy(rtwvif->mac_addr, vif->addr); + + rtwvif->offchan = false; + rtwvif->roc.state = RTW89_ROC_IDLE; INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work); - rtw89_leave_ps_mode(rtwdev); rtw89_traffic_stats_init(rtwdev, &rtwvif->stats); - rtw89_vif_type_mapping(vif, false); - rtwvif->port = rtw89_core_acquire_bit_map(rtwdev->hw_port, - RTW89_PORT_NUM); - if (rtwvif->port == RTW89_PORT_NUM) { - ret = -ENOSPC; - list_del_init(&rtwvif->list); - goto out; - } - rtwvif->bcn_hit_cond = 0; - rtwvif->mac_idx = RTW89_MAC_0; - rtwvif->phy_idx = RTW89_PHY_0; - rtwvif->chanctx_idx = RTW89_CHANCTX_0; - rtwvif->chanctx_assigned = false; - rtwvif->hit_rule = 0; - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; - ether_addr_copy(rtwvif->mac_addr, vif->addr); - INIT_LIST_HEAD(&rtwvif->general_pkt_list); - - ret = rtw89_mac_add_vif(rtwdev, rtwvif); - if (ret) { - rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); - list_del_init(&rtwvif->list); - goto out; + rtwvif_link = rtw89_vif_set_link(rtwvif, 0); + if (!rtwvif_link) { + ret = -EINVAL; + goto release_port; } - rtw89_core_txq_init(rtwdev, vif->txq); - - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_START); + ret = __rtw89_ops_add_iface_link(rtwdev, rtwvif_link); + if (ret) + goto unset_link; rtw89_recalc_lps(rtwdev); -out: + + mutex_unlock(&rtwdev->mutex); + return 0; + +unset_link: + rtw89_vif_unset_link(rtwvif, 0); +release_port: + list_del_init(&rtwvif->list); + rtw89_core_release_bit_map(rtwdev->hw_port, port); +release_macid: + rtw89_release_mac_id(rtwdev, mac_id); +err: mutex_unlock(&rtwdev->mutex); return ret; @@ -175,20 +234,35 @@ static void rtw89_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + u8 macid = rtw89_vif_get_main_macid(rtwvif); + u8 port = rtw89_vif_get_main_port(rtwvif); + struct rtw89_vif_link *rtwvif_link; rtw89_debug(rtwdev, RTW89_DBG_STATE, "remove vif %pM type %d p2p %d\n", vif->addr, vif->type, vif->p2p); - cancel_work_sync(&rtwvif->update_beacon_work); cancel_delayed_work_sync(&rtwvif->roc.roc_work); mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_STOP); - rtw89_mac_remove_vif(rtwdev, rtwvif); - rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); + + rtwvif_link = rtwvif->links[0]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, 0); + goto bottom; + } + + __rtw89_ops_remove_iface_link(rtwdev, rtwvif_link); + + rtw89_vif_unset_link(rtwvif, 0); + +bottom: list_del_init(&rtwvif->list); + rtw89_core_release_bit_map(rtwdev->hw_port, port); + rtw89_release_mac_id(rtwdev, macid); + rtw89_recalc_lps(rtwdev); rtw89_enter_ips_by_hwflags(rtwdev); @@ -311,24 +385,30 @@ static const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = { }; static u8 rtw89_aifsn_to_aifs(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u8 aifsn) + struct rtw89_vif_link *rtwvif_link, u8 aifsn) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); + struct ieee80211_bss_conf *bss_conf; u8 slot_time; u8 sifs; - slot_time = vif->bss_conf.use_short_slot ? 9 : 20; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + slot_time = bss_conf->use_short_slot ? 9 : 20; + + rcu_read_unlock(); + sifs = chan->band_type == RTW89_BAND_2G ? 10 : 16; return aifsn * slot_time + sifs; } static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u16 ac) + struct rtw89_vif_link *rtwvif_link, u16 ac) { - struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; + struct ieee80211_tx_queue_params *params = &rtwvif_link->tx_params[ac]; u32 val; u8 ecw_max, ecw_min; u8 aifs; @@ -336,12 +416,12 @@ static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev, /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ ecw_max = ilog2(params->cw_max + 1); ecw_min = ilog2(params->cw_min + 1); - aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif, params->aifs); + aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif_link, params->aifs); val = FIELD_PREP(FW_EDCA_PARAM_TXOPLMT_MSK, params->txop) | FIELD_PREP(FW_EDCA_PARAM_CWMAX_MSK, ecw_max) | FIELD_PREP(FW_EDCA_PARAM_CWMIN_MSK, ecw_min) | FIELD_PREP(FW_EDCA_PARAM_AIFS_MSK, aifs); - rtw89_fw_h2c_set_edca(rtwdev, rtwvif, ac_to_fw_idx[ac], val); + rtw89_fw_h2c_set_edca(rtwdev, rtwvif_link, ac_to_fw_idx[ac], val); } #define R_MUEDCA_ACS_PARAM(acs) {R_AX_MUEDCA_ ## acs ## _PARAM_0, \ @@ -355,9 +435,9 @@ static const u32 ac_to_mu_edca_param[IEEE80211_NUM_ACS][RTW89_CHIP_GEN_NUM] = { }; static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u16 ac) + struct rtw89_vif_link *rtwvif_link, u16 ac) { - struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; + struct ieee80211_tx_queue_params *params = &rtwvif_link->tx_params[ac]; struct ieee80211_he_mu_edca_param_ac_rec *mu_edca; int gen = rtwdev->chip->chip_gen; u8 aifs, aifsn; @@ -370,32 +450,199 @@ static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, mu_edca = ¶ms->mu_edca_param_rec; aifsn = FIELD_GET(GENMASK(3, 0), mu_edca->aifsn); - aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif, aifsn) : 0; + aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif_link, aifsn) : 0; timer_32us = mu_edca->mu_edca_timer << 8; val = FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_TIMER_MASK, timer_32us) | FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_CW_MASK, mu_edca->ecw_min_max) | FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_AIFS_MASK, aifs); - reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac][gen], rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac][gen], + rtwvif_link->mac_idx); rtw89_write32(rtwdev, reg, val); - rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, true); + rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif_link, true); } static void __rtw89_conf_tx(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u16 ac) + struct rtw89_vif_link *rtwvif_link, u16 ac) { - ____rtw89_conf_tx_edca(rtwdev, rtwvif, ac); - ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif, ac); + ____rtw89_conf_tx_edca(rtwdev, rtwvif_link, ac); + ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif_link, ac); } static void rtw89_conf_tx(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { u16 ac; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - __rtw89_conf_tx(rtwdev, rtwvif, ac); + __rtw89_conf_tx(rtwdev, rtwvif_link, ac); +} + +static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + bool acquire_macid = false; + u8 macid; + int ret; + int i; + + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { + /* for station mode, assign the mac_id from itself */ + macid = rtw89_vif_get_main_macid(rtwvif); + } else { + macid = rtw89_acquire_mac_id(rtwdev); + if (macid == RTW89_MAX_MAC_ID_NUM) + return -ENOSPC; + + acquire_macid = true; + } + + rtw89_init_sta(rtwdev, rtwvif, rtwsta, macid); + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + rtw89_core_txq_init(rtwdev, sta->txq[i]); + + skb_queue_head_init(&rtwsta->roc_queue); + + rtwsta_link = rtw89_sta_set_link(rtwsta, sta->deflink.link_id); + if (!rtwsta_link) { + ret = -EINVAL; + goto err; + } + + rtwvif_link = rtwsta_link->rtwvif_link; + + ret = rtw89_core_sta_link_add(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + goto unset_link; + + if (vif->type == NL80211_IFTYPE_AP || sta->tdls) + rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); + + return 0; + +unset_link: + rtw89_sta_unset_link(rtwsta, sta->deflink.link_id); +err: + if (acquire_macid) + rtw89_release_mac_id(rtwdev, macid); + + return ret; +} + +static int __rtw89_ops_sta_assoc(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + bool station_mode) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + + if (station_mode) + rtw89_vif_type_mapping(rtwvif_link, true); + + ret = rtw89_core_sta_link_assoc(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + return ret; + } + + rtwdev->total_sta_assoc++; + if (sta->tdls) + rtwvif->tdls_peer++; + + return 0; +} + +static int __rtw89_ops_sta_disassoc(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = rtw89_core_sta_link_disassoc(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + return ret; + } + + rtwsta->disassoc = true; + + rtwdev->total_sta_assoc--; + if (sta->tdls) + rtwvif->tdls_peer--; + + return 0; +} + +static int __rtw89_ops_sta_disconnect(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_core_free_sta_pending_ba(rtwdev, sta); + rtw89_core_free_sta_pending_forbid_ba(rtwdev, sta); + rtw89_core_free_sta_pending_roc_tx(rtwdev, sta); + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = rtw89_core_sta_link_disconnect(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + return ret; + } + + return 0; +} + +static int __rtw89_ops_sta_remove(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + u8 macid = rtw89_sta_get_main_macid(rtwsta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = rtw89_core_sta_link_remove(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + return ret; + + rtw89_sta_unset_link(rtwsta, link_id); + } + + if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { + rtw89_release_mac_id(rtwdev, macid); + rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); + } + + return 0; } static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, @@ -412,16 +659,34 @@ static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, return; } - rtw89_vif_type_mapping(vif, true); + __rtw89_ops_sta_assoc(rtwdev, vif, sta, true); +} + +static void __rtw89_ops_bss_link_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + rtw89_phy_set_bss_color(rtwdev, rtwvif_link); + rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, rtwvif_link); + rtw89_mac_port_update(rtwdev, rtwvif_link); + rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, rtwvif_link); +} + +static void __rtw89_ops_bss_assoc(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; - rtw89_core_sta_assoc(rtwdev, vif, sta); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + __rtw89_ops_bss_link_assoc(rtwdev, rtwvif_link); } static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 changed) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); @@ -429,10 +694,7 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (vif->cfg.assoc) { rtw89_station_mode_sta_assoc(rtwdev, vif); - rtw89_phy_set_bss_color(rtwdev, vif); - rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); - rtw89_mac_port_update(rtwdev, rtwvif); - rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, vif); + __rtw89_ops_bss_assoc(rtwdev, vif); rtw89_queue_chanctx_work(rtwdev); } else { @@ -459,39 +721,49 @@ static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw, u64 changed) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); + rtwvif_link = rtwvif->links[conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, conf->link_id); + goto out; + } + if (changed & BSS_CHANGED_BSSID) { - ether_addr_copy(rtwvif->bssid, conf->bssid); - rtw89_cam_bssid_changed(rtwdev, rtwvif); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); - WRITE_ONCE(rtwvif->sync_bcn_tsf, 0); + ether_addr_copy(rtwvif_link->bssid, conf->bssid); + rtw89_cam_bssid_changed(rtwdev, rtwvif_link); + rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); + WRITE_ONCE(rtwvif_link->sync_bcn_tsf, 0); } if (changed & BSS_CHANGED_BEACON) - rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); if (changed & BSS_CHANGED_ERP_SLOT) - rtw89_conf_tx(rtwdev, rtwvif); + rtw89_conf_tx(rtwdev, rtwvif_link); if (changed & BSS_CHANGED_HE_BSS_COLOR) - rtw89_phy_set_bss_color(rtwdev, vif); + rtw89_phy_set_bss_color(rtwdev, rtwvif_link); if (changed & BSS_CHANGED_MU_GROUPS) rtw89_mac_bf_set_gid_table(rtwdev, vif, conf); if (changed & BSS_CHANGED_P2P_PS) - rtw89_core_update_p2p_ps(rtwdev, vif); + rtw89_core_update_p2p_ps(rtwdev, rtwvif_link, conf); if (changed & BSS_CHANGED_CQM) - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); if (changed & BSS_CHANGED_TPE) - rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true); + rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, true); +out: mutex_unlock(&rtwdev->mutex); } @@ -500,12 +772,21 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; const struct rtw89_chan *chan; mutex_lock(&rtwdev->mutex); - chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + goto out; + } + + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); if (chan->band_type == RTW89_BAND_6G) { mutex_unlock(&rtwdev->mutex); return -EOPNOTSUPP; @@ -514,16 +795,18 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, if (rtwdev->scanning) rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); - ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); - rtw89_cam_bssid_changed(rtwdev, rtwvif); - rtw89_mac_port_update(rtwdev, rtwvif); - rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); - rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_TYPE_CHANGE); - rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); - rtw89_chip_rfk_channel(rtwdev, rtwvif); + ether_addr_copy(rtwvif_link->bssid, link_conf->bssid); + rtw89_cam_bssid_changed(rtwdev, rtwvif_link); + rtw89_mac_port_update(rtwdev, rtwvif_link); + rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, NULL); + rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_TYPE_CHANGE); + rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true); + rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); + rtw89_chip_rfk_channel(rtwdev, rtwvif_link); rtw89_queue_chanctx_work(rtwdev); + +out: mutex_unlock(&rtwdev->mutex); return 0; @@ -534,12 +817,24 @@ void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); - rtw89_mac_stop_ap(rtwdev, rtwvif); - rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); - rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); + + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + goto out; + } + + rtw89_mac_stop_ap(rtwdev, rtwvif_link); + rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, NULL); + rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true); + +out: mutex_unlock(&rtwdev->mutex); } @@ -547,10 +842,13 @@ static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; - ieee80211_queue_work(rtwdev->hw, &rtwvif->update_beacon_work); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + ieee80211_queue_work(rtwdev->hw, &rtwvif_link->update_beacon_work); return 0; } @@ -561,15 +859,29 @@ static int rtw89_ops_conf_tx(struct ieee80211_hw *hw, const struct ieee80211_tx_queue_params *params) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + int ret = 0; mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); - rtwvif->tx_params[ac] = *params; - __rtw89_conf_tx(rtwdev, rtwvif, ac); + + rtwvif_link = rtwvif->links[link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_id); + ret = -ENOLINK; + goto out; + } + + rtwvif_link->tx_params[ac] = *params; + __rtw89_conf_tx(rtwdev, rtwvif_link, ac); + +out: mutex_unlock(&rtwdev->mutex); - return 0; + return ret; } static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, @@ -582,26 +894,26 @@ static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) - return rtw89_core_sta_add(rtwdev, vif, sta); + return __rtw89_ops_sta_add(rtwdev, vif, sta); if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) return 0; /* defer to bss_info_changed to have vif info */ - return rtw89_core_sta_assoc(rtwdev, vif, sta); + return __rtw89_ops_sta_assoc(rtwdev, vif, sta, false); } if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH) - return rtw89_core_sta_disassoc(rtwdev, vif, sta); + return __rtw89_ops_sta_disassoc(rtwdev, vif, sta); if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_NONE) - return rtw89_core_sta_disconnect(rtwdev, vif, sta); + return __rtw89_ops_sta_disconnect(rtwdev, vif, sta); if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) - return rtw89_core_sta_remove(rtwdev, vif, sta); + return __rtw89_ops_sta_remove(rtwdev, vif, sta); return 0; } @@ -667,7 +979,8 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, { struct rtw89_dev *rtwdev = hw->priv; struct ieee80211_sta *sta = params->sta; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); u16 tid = params->tid; struct ieee80211_txq *txq = sta->txq[tid]; struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; @@ -681,7 +994,7 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); clear_bit(tid, rtwsta->ampdu_map); - rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); + rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta); mutex_unlock(&rtwdev->mutex); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; @@ -692,7 +1005,7 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, rtwsta->ampdu_params[tid].amsdu = params->amsdu; set_bit(tid, rtwsta->ampdu_map); rtw89_leave_ps_mode(rtwdev); - rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); + rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta); mutex_unlock(&rtwdev->mutex); break; case IEEE80211_AMPDU_RX_START: @@ -720,7 +1033,7 @@ static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) - rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); + rtw89_mac_update_rts_threshold(rtwdev); mutex_unlock(&rtwdev->mutex); return 0; @@ -731,9 +1044,14 @@ static void rtw89_ops_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct station_info *sinfo) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; - sinfo->txrate = rtwsta->ra_report.txrate; + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) + return; + + sinfo->txrate = rtwsta_link->ra_report.txrate; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } @@ -743,7 +1061,7 @@ void __rtw89_drop_packets(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) struct rtw89_vif *rtwvif; if (vif) { - rtwvif = (struct rtw89_vif *)vif->drv_priv; + rtwvif = vif_to_rtwvif(vif); rtw89_mac_pkt_drop_vif(rtwdev, rtwvif); } else { rtw89_for_each_rtwvif(rtwdev, rtwvif) @@ -777,14 +1095,20 @@ struct rtw89_iter_bitrate_mask_data { static void rtw89_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_iter_bitrate_mask_data *br_data = data; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif); + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; if (vif != br_data->vif || vif->p2p) return; - rtwsta->use_cfg_mask = true; - rtwsta->mask = *br_data->mask; + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwsta_link->use_cfg_mask = true; + rtwsta_link->mask = *br_data->mask; + } + rtw89_phy_ra_update_sta(br_data->rtwdev, sta, IEEE80211_RC_SUPP_RATES_CHANGED); } @@ -854,10 +1178,20 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, const u8 *mac_addr) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); - rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, false); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "sw scan start: find no link on HW-0\n"); + goto out; + } + + rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, false); + +out: mutex_unlock(&rtwdev->mutex); } @@ -865,9 +1199,20 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); - rtw89_core_scan_complete(rtwdev, vif, false); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "sw scan complete: find no link on HW-0\n"); + goto out; + } + + rtw89_core_scan_complete(rtwdev, rtwvif_link, false); + +out: mutex_unlock(&rtwdev->mutex); } @@ -884,22 +1229,35 @@ static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *req) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); - int ret = 0; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + int ret; if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) return 1; - if (rtwdev->scanning || rtwvif->offchan) - return -EBUSY; - mutex_lock(&rtwdev->mutex); - rtw89_hw_scan_start(rtwdev, vif, req); - ret = rtw89_hw_scan_offload(rtwdev, vif, true); + + if (rtwdev->scanning || rtwvif->offchan) { + ret = -EBUSY; + goto out; + } + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "hw scan: find no link on HW-0\n"); + ret = -ENOLINK; + goto out; + } + + rtw89_hw_scan_start(rtwdev, rtwvif_link, req); + ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true); if (ret) { - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwvif_link); rtw89_err(rtwdev, "HW scan failed with status: %d\n", ret); } + +out: mutex_unlock(&rtwdev->mutex); return ret; @@ -909,6 +1267,8 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) return; @@ -917,14 +1277,25 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw, return; mutex_lock(&rtwdev->mutex); - rtw89_hw_scan_abort(rtwdev, vif); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "cancel hw scan: find no link on HW-0\n"); + goto out; + } + + rtw89_hw_scan_abort(rtwdev, rtwvif_link); + +out: mutex_unlock(&rtwdev->mutex); } static void rtw89_ops_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, + u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct rtw89_dev *rtwdev = hw->priv; rtw89_phy_ra_update_sta(rtwdev, sta, changed); @@ -970,11 +1341,24 @@ static int rtw89_ops_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; int ret; mutex_lock(&rtwdev->mutex); - ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif, ctx); + + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + ret = -ENOLINK; + goto out; + } + + ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, ctx); + +out: mutex_unlock(&rtwdev->mutex); return ret; @@ -986,10 +1370,21 @@ static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); - rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif, ctx); + + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + mutex_unlock(&rtwdev->mutex); + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + return; + } + + rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, ctx); mutex_unlock(&rtwdev->mutex); } @@ -1003,7 +1398,7 @@ static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct rtw89_roc *roc = &rtwvif->roc; - if (!vif) + if (!rtwvif) return -EINVAL; mutex_lock(&rtwdev->mutex); @@ -1053,8 +1448,8 @@ static int rtw89_ops_cancel_remain_on_channel(struct ieee80211_hw *hw, static void rtw89_set_tid_config_iter(void *data, struct ieee80211_sta *sta) { struct cfg80211_tid_config *tid_config = data; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_dev *rtwdev = rtwsta->rtwvif->rtwdev; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; rtw89_core_set_tid_config(rtwdev, sta, tid_config); } @@ -1203,7 +1598,7 @@ const struct ieee80211_ops rtw89_ops = { .remain_on_channel = rtw89_ops_remain_on_channel, .cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel, .set_sar_specs = rtw89_ops_set_sar_specs, - .sta_rc_update = rtw89_ops_sta_rc_update, + .link_sta_rc_update = rtw89_ops_sta_rc_update, .set_tid_config = rtw89_ops_set_tid_config, #ifdef CONFIG_PM .suspend = rtw89_ops_suspend, diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 31f0a5225b11..f7a396c8a3cd 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -773,7 +773,7 @@ static int dmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) return ret; } - ret = rtw89_mac_preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode); + ret = rtw89_mac_preload_init(rtwdev, mac_idx, rtwdev->mac.qta_mode); if (ret) { rtw89_err(rtwdev, "[ERR]preload init %d\n", ret); return ret; @@ -2091,13 +2091,13 @@ static int rtw89_mac_init_bfee_be(struct rtw89_dev *rtwdev, u8 mac_idx) } static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; u8 nc = 1, nr = 3, ng = 0, cb = 1, cs = 1, ldpc_en = 1, stbc_en = 1; - u8 mac_idx = rtwvif->mac_idx; - u8 port_sel = rtwvif->port; + struct ieee80211_link_sta *link_sta; + u8 mac_idx = rtwvif_link->mac_idx; + u8 port_sel = rtwvif_link->port; u8 sound_dim = 3, t; u8 *phy_cap; u32 reg; @@ -2108,7 +2108,10 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, if (ret) return ret; - phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info; + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info; if ((phy_cap[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) || (phy_cap[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) { @@ -2119,11 +2122,11 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, sound_dim = min(sound_dim, t); } - if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { - ldpc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); - stbc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK); - t = u32_get_bits(sta->deflink.vht_cap.cap, + if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { + ldpc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); + stbc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK); + t = u32_get_bits(link_sta->vht_cap.cap, IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); sound_dim = min(sound_dim, t); } @@ -2131,6 +2134,8 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, nc = min(nc, sound_dim); nr = min(nr, sound_dim); + rcu_read_unlock(); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); rtw89_write32_set(rtwdev, reg, B_BE_BFMEE_BFPARAM_SEL); @@ -2155,12 +2160,12 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, } static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; u32 rrsc = BIT(RTW89_MAC_BF_RRSC_6M) | BIT(RTW89_MAC_BF_RRSC_24M); - u8 mac_idx = rtwvif->mac_idx; + struct ieee80211_link_sta *link_sta; + u8 mac_idx = rtwvif_link->mac_idx; int ret; u32 reg; @@ -2168,22 +2173,28 @@ static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev, if (ret) return ret; - if (sta->deflink.he_cap.has_he) { + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->he_cap.has_he) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_HE_MSC0) | BIT(RTW89_MAC_BF_RRSC_HE_MSC3) | BIT(RTW89_MAC_BF_RRSC_HE_MSC5)); } - if (sta->deflink.vht_cap.vht_supported) { + if (link_sta->vht_cap.vht_supported) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_VHT_MSC0) | BIT(RTW89_MAC_BF_RRSC_VHT_MSC3) | BIT(RTW89_MAC_BF_RRSC_VHT_MSC5)); } - if (sta->deflink.ht_cap.ht_supported) { + if (link_sta->ht_cap.ht_supported) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_HT_MSC0) | BIT(RTW89_MAC_BF_RRSC_HT_MSC3) | BIT(RTW89_MAC_BF_RRSC_HT_MSC5)); } + rcu_read_unlock(); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); rtw89_write32_set(rtwdev, reg, B_BE_BFMEE_BFPARAM_SEL); rtw89_write32_clr(rtwdev, reg, B_BE_BFMEE_CSI_FORCE_RETE_EN); @@ -2195,17 +2206,25 @@ static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev, } static void rtw89_mac_bf_assoc_be(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta; + bool has_beamformer_cap; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + has_beamformer_cap = rtw89_sta_has_beamformer_cap(link_sta); + + rcu_read_unlock(); - if (rtw89_sta_has_beamformer_cap(sta)) { + if (has_beamformer_cap) { rtw89_debug(rtwdev, RTW89_DBG_BF, "initialize bfee for new association\n"); - rtw89_mac_init_bfee_be(rtwdev, rtwvif->mac_idx); - rtw89_mac_set_csi_para_reg_be(rtwdev, vif, sta); - rtw89_mac_csi_rrsc_be(rtwdev, vif, sta); + rtw89_mac_init_bfee_be(rtwdev, rtwvif_link->mac_idx); + rtw89_mac_set_csi_para_reg_be(rtwdev, rtwvif_link, rtwsta_link); + rtw89_mac_csi_rrsc_be(rtwdev, rtwvif_link, rtwsta_link); } } @@ -2581,9 +2600,11 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, .fwdl_get_status = fwdl_get_status_be, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_be, + .fwdl_secure_idmem_share_mode = NULL, .parse_efuse_map = rtw89_parse_efuse_map_be, .parse_phycap_map = rtw89_parse_phycap_map_be, .cnv_efuse_state = rtw89_cnv_efuse_state_be, + .efuse_read_fw_secure = rtw89_efuse_read_fw_secure_be, .cfg_plt = rtw89_mac_cfg_plt_be, .get_plt_cnt = rtw89_mac_get_plt_cnt_be, diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 5aef7fa37878..f923bec03d41 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -2358,13 +2358,15 @@ static int rtw89_pci_deglitch_setting(struct rtw89_dev *rtwdev) return 0; } -static void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev) +static void rtw89_pci_disable_eq_ax(struct rtw89_dev *rtwdev) { u16 g1_oobs, g2_oobs; u32 backup_aspm; u32 phy_offset; + u16 offset_cal; u16 oobs_val; int ret; + u8 gen; if (rtwdev->chip->chip_id != RTL8852C) return; @@ -2400,6 +2402,28 @@ static void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev) rtw89_write16_set(rtwdev, R_RAC_DIRECT_OFFSET_G2 + RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL); + /* offset K */ + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_G1 : + R_RAC_DIRECT_OFFSET_G2; + + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT, + B_PCIE_BIT_RD_SEL); + } + + offset_cal = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_G1 + + RAC_ANA1F * RAC_MULT, OFFSET_CAL_MASK); + + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_G1 : + R_RAC_DIRECT_OFFSET_G2; + + rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA0B * RAC_MULT, + MANUAL_LVL_MASK, offset_cal); + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT, + OFFSET_CAL_MODE); + } + out: rtw89_write32(rtwdev, R_AX_PCIE_MIX_CFG_V1, backup_aspm); } @@ -2647,9 +2671,10 @@ static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev) static int rtw89_pci_poll_txdma_ch_idle_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; - u32 ret, check, dma_busy; u32 dma_busy1 = info->dma_busy1.addr; u32 dma_busy2 = info->dma_busy2_reg; + u32 check, dma_busy; + int ret; check = info->dma_busy1.mask; @@ -2674,8 +2699,9 @@ static int rtw89_pci_poll_txdma_ch_idle_ax(struct rtw89_dev *rtwdev) static int rtw89_pci_poll_rxdma_ch_idle_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; - u32 ret, check, dma_busy; u32 dma_busy3 = info->dma_busy3_reg; + u32 check, dma_busy; + int ret; check = B_AX_RXQ_BUSY | B_AX_RPQ_BUSY; @@ -3758,19 +3784,16 @@ static void rtw89_pci_free_irq(struct rtw89_dev *rtwdev, pci_free_irq_vectors(pdev); } -static u16 gray_code_to_bin(u16 gray_code, u32 bit_num) +static u16 gray_code_to_bin(u16 gray_code) { - u16 bin = 0, gray_bit; - u32 bit_idx; + u16 binary = gray_code; - for (bit_idx = 0; bit_idx < bit_num; bit_idx++) { - gray_bit = (gray_code >> bit_idx) & 0x1; - if (bit_num - bit_idx > 1) - gray_bit ^= (gray_code >> (bit_idx + 1)) & 0x1; - bin |= (gray_bit << bit_idx); + while (gray_code) { + gray_code >>= 1; + binary ^= gray_code; } - return bin; + return binary; } static int rtw89_pci_filter_out(struct rtw89_dev *rtwdev) @@ -3806,7 +3829,7 @@ static int rtw89_pci_filter_out(struct rtw89_dev *rtwdev) val16 = rtw89_read16_mask(rtwdev, phy_offset + RAC_ANA1F * RAC_MULT, FILTER_OUT_EQ_MASK); - val16 = gray_code_to_bin(val16, hweight16(val16)); + val16 = gray_code_to_bin(val16); filter_out_val = rtw89_read16(rtwdev, phy_offset + RAC_ANA24 * RAC_MULT); filter_out_val &= ~REG_FILTER_OUT_MASK; @@ -4188,6 +4211,36 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) return work_done; } +static +void rtw89_check_pci_ssid_quirks(struct rtw89_dev *rtwdev, + struct pci_dev *pdev, + const struct rtw89_pci_ssid_quirk *ssid_quirks) +{ + int i; + + if (!ssid_quirks) + return; + + for (i = 0; i < 200; i++, ssid_quirks++) { + if (ssid_quirks->vendor == 0 && ssid_quirks->device == 0) + break; + + if (ssid_quirks->vendor != pdev->vendor || + ssid_quirks->device != pdev->device || + ssid_quirks->subsystem_vendor != pdev->subsystem_vendor || + ssid_quirks->subsystem_device != pdev->subsystem_device) + continue; + + bitmap_or(rtwdev->quirks, rtwdev->quirks, &ssid_quirks->bitmap, + NUM_OF_RTW89_QUIRKS); + rtwdev->custid = ssid_quirks->custid; + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_HCI, "quirks=%*ph custid=%d\n", + (int)sizeof(rtwdev->quirks), rtwdev->quirks, rtwdev->custid); +} + static int __maybe_unused rtw89_pci_suspend(struct device *dev) { struct ieee80211_hw *hw = dev_get_drvdata(dev); @@ -4222,6 +4275,17 @@ static void rtw89_pci_l2_hci_ldo(struct rtw89_dev *rtwdev) RTW89_PCIE_BIT_CFG_RST_MSTATE); } +void rtw89_pci_basic_cfg(struct rtw89_dev *rtwdev, bool resume) +{ + if (resume) + rtw89_pci_cfg_dac(rtwdev); + + rtw89_pci_disable_eq(rtwdev); + rtw89_pci_filter_out(rtwdev); + rtw89_pci_link_cfg(rtwdev); + rtw89_pci_l1ss_cfg(rtwdev); +} + static int __maybe_unused rtw89_pci_resume(struct device *dev) { struct ieee80211_hw *hw = dev_get_drvdata(dev); @@ -4243,11 +4307,8 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) B_AX_SEL_REQ_ENTR_L1); } rtw89_pci_l2_hci_ldo(rtwdev); - rtw89_pci_disable_eq(rtwdev); - rtw89_pci_cfg_dac(rtwdev); - rtw89_pci_filter_out(rtwdev); - rtw89_pci_link_cfg(rtwdev); - rtw89_pci_l1ss_cfg(rtwdev); + + rtw89_pci_basic_cfg(rtwdev, true); return 0; } @@ -4280,6 +4341,8 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .aspm_set = rtw89_pci_aspm_set_ax, .clkreq_set = rtw89_pci_clkreq_set_ax, .l1ss_set = rtw89_pci_l1ss_set_ax, + + .disable_eq = rtw89_pci_disable_eq_ax, }; EXPORT_SYMBOL(rtw89_pci_gen_ax); @@ -4352,6 +4415,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) rtwdev->hci.cpwm_addr = pci_info->cpwm_addr; rtw89_check_quirks(rtwdev, info->quirks); + rtw89_check_pci_ssid_quirks(rtwdev, pdev, pci_info->ssid_quirks); SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev); @@ -4379,10 +4443,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_clear_resource; } - rtw89_pci_disable_eq(rtwdev); - rtw89_pci_filter_out(rtwdev); - rtw89_pci_link_cfg(rtwdev); - rtw89_pci_l1ss_cfg(rtwdev); + rtw89_pci_basic_cfg(rtwdev, false); ret = rtw89_core_napi_init(rtwdev); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 48c3ab735db2..b68e2d82eea9 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -18,11 +18,16 @@ #define BAC_OOBS_SEL BIT(4) #define RAC_ANA0A 0x0A #define B_BAC_EQ_SEL BIT(5) +#define RAC_ANA0B 0x0B +#define MANUAL_LVL_MASK GENMASK(8, 5) #define RAC_ANA0C 0x0C #define B_PCIE_BIT_PSAVE BIT(15) #define RAC_ANA0D 0x0D +#define OFFSET_CAL_MODE BIT(13) #define BAC_RX_TEST_EN BIT(6) #define RAC_ANA10 0x10 +#define ADDR_SEL_MASK GENMASK(9, 4) +#define ADDR_SEL_VAL 0x3C #define ADDR_SEL_PINOUT_DIS_VAL 0x3C4 #define B_PCIE_BIT_PINOUT_DIS BIT(3) #define RAC_REG_REV2 0x1B @@ -38,6 +43,7 @@ #define RAC_ANA1E_G2_VAL 0x6EEA #define RAC_ANA1F 0x1F #define OOBS_LEVEL_MASK GENMASK(12, 8) +#define OFFSET_CAL_MASK GENMASK(7, 4) #define RAC_ANA24 0x24 #define B_AX_DEGLITCH GENMASK(11, 8) #define RAC_ANA26 0x26 @@ -134,6 +140,11 @@ #define REG_FILTER_OUT_MASK GENMASK(6, 2) #define RAC_MULT 2 +#define R_RAC_DIRECT_OFFSET_BE_LANE0_G1 0x3800 +#define R_RAC_DIRECT_OFFSET_BE_LANE1_G1 0x3880 +#define R_RAC_DIRECT_OFFSET_BE_LANE0_G2 0x3900 +#define R_RAC_DIRECT_OFFSET_BE_LANE1_G2 0x3980 + #define RTW89_PCI_WR_RETRY_CNT 20 /* Interrupts */ @@ -299,6 +310,7 @@ #define B_BE_L1SS_TIMEOUT_CTRL BIT(18) #define B_BE_ASPM_CTRL_L1 BIT(17) #define B_BE_ASPM_CTRL_L0 BIT(16) +#define B_BE_RTK_ASPM_CTRL_MASK GENMASK(17, 16) #define B_BE_XFER_PENDING_FW BIT(11) #define B_BE_XFER_PENDING BIT(10) #define B_BE_REQ_EXIT_L1 BIT(9) @@ -1276,6 +1288,21 @@ struct rtw89_pci_gen_def { void (*aspm_set)(struct rtw89_dev *rtwdev, bool enable); void (*clkreq_set)(struct rtw89_dev *rtwdev, bool enable); void (*l1ss_set)(struct rtw89_dev *rtwdev, bool enable); + + void (*disable_eq)(struct rtw89_dev *rtwdev); +}; + +#define RTW89_PCI_SSID(v, d, ssv, ssd, cust) \ + .vendor = v, .device = d, .subsystem_vendor = ssv, .subsystem_device = ssd, \ + .custid = RTW89_CUSTID_ ##cust + +struct rtw89_pci_ssid_quirk { + unsigned short vendor; + unsigned short device; + unsigned short subsystem_vendor; + unsigned short subsystem_device; + enum rtw89_custid custid; + unsigned long bitmap; /* bitmap of rtw89_quirks */ }; struct rtw89_pci_info { @@ -1331,6 +1358,8 @@ struct rtw89_pci_info { void (*recognize_intrs)(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); + + const struct rtw89_pci_ssid_quirk *ssid_quirks; }; struct rtw89_pci_tx_data { @@ -1600,6 +1629,7 @@ struct pci_device_id; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtw89_pci_remove(struct pci_dev *pdev); +void rtw89_pci_basic_cfg(struct rtw89_dev *rtwdev, bool resume); void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev); int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en); int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en); @@ -1766,4 +1796,13 @@ static inline int rtw89_pci_poll_txdma_ch_idle(struct rtw89_dev *rtwdev) return gen_def->poll_txdma_ch_idle(rtwdev); } + +static inline void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + gen_def->disable_eq(rtwdev); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 7cc328222965..34154506f5d4 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -550,6 +550,79 @@ static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev) return 0; } +static void rtw89_pci_disable_eq_be(struct rtw89_dev *rtwdev) +{ + u32 backup_aspm, phy_offset; + u16 oobs_val, offset_cal; + u16 g1_oobs, g2_oobs; + u8 gen; + + if (rtwdev->chip->chip_id != RTL8922A) + return; + + g1_oobs = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 + + RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL); + g2_oobs = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G2 + + RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL); + if (g1_oobs && g2_oobs) + return; + + backup_aspm = rtw89_read32(rtwdev, R_BE_PCIE_MIX_CFG); + rtw89_write32_clr(rtwdev, R_BE_PCIE_MIX_CFG, B_BE_RTK_ASPM_CTRL_MASK); + + /* offset K */ + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 : + R_RAC_DIRECT_OFFSET_BE_LANE0_G2; + + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT, + B_PCIE_BIT_RD_SEL); + } + + offset_cal = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 + + RAC_ANA1F * RAC_MULT, OFFSET_CAL_MASK); + + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 : + R_RAC_DIRECT_OFFSET_BE_LANE0_G2; + + rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA0B * RAC_MULT, + MANUAL_LVL_MASK, offset_cal); + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT, + OFFSET_CAL_MODE); + } + + /* OOBS */ + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 : + R_RAC_DIRECT_OFFSET_BE_LANE0_G2; + + rtw89_write16_set(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT, + BAC_RX_TEST_EN); + rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT, + ADDR_SEL_MASK, ADDR_SEL_VAL); + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT, + B_PCIE_BIT_PINOUT_DIS); + rtw89_write16_set(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT, + B_PCIE_BIT_RD_SEL); + } + + oobs_val = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 + + RAC_ANA1F * RAC_MULT, OOBS_LEVEL_MASK); + + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 : + R_RAC_DIRECT_OFFSET_BE_LANE0_G2; + + rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA03 * RAC_MULT, + OOBS_SEN_MASK, oobs_val); + rtw89_write16_set(rtwdev, phy_offset + RAC_ANA09 * RAC_MULT, + BAC_OOBS_SEL); + } + + rtw89_write32(rtwdev, R_BE_PCIE_MIX_CFG, backup_aspm); +} + static int __maybe_unused rtw89_pci_suspend_be(struct device *dev) { struct ieee80211_hw *hw = dev_get_drvdata(dev); @@ -584,6 +657,8 @@ static int __maybe_unused rtw89_pci_resume_be(struct device *dev) rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); rtw89_write32_set(rtwdev, R_BE_REG_PL1_MASK, B_BE_SER_PM_MASTER_IMR); + rtw89_pci_basic_cfg(rtwdev, true); + return 0; } @@ -614,5 +689,7 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .aspm_set = rtw89_pci_aspm_set_be, .clkreq_set = rtw89_pci_clkreq_set_be, .l1ss_set = rtw89_pci_l1ss_set_be, + + .disable_eq = rtw89_pci_disable_eq_be, }; EXPORT_SYMBOL(rtw89_pci_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index c7165e757842..f24aca663cf0 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -75,12 +75,12 @@ static u64 get_mcs_ra_mask(u16 mcs_map, u8 highest_mcs, u8 gap) return ra_mask; } -static u64 get_he_ra_mask(struct ieee80211_sta *sta) +static u64 get_he_ra_mask(struct ieee80211_link_sta *link_sta) { - struct ieee80211_sta_he_cap cap = sta->deflink.he_cap; + struct ieee80211_sta_he_cap cap = link_sta->he_cap; u16 mcs_map; - switch (sta->deflink.bandwidth) { + switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_160: if (cap.he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) @@ -118,14 +118,14 @@ static u64 get_eht_mcs_ra_mask(u8 *max_nss, u8 start_mcs, u8 n_nss) return mask; } -static u64 get_eht_ra_mask(struct ieee80211_sta *sta) +static u64 get_eht_ra_mask(struct ieee80211_link_sta *link_sta) { - struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; struct ieee80211_eht_mcs_nss_supp_20mhz_only *mcs_nss_20mhz; struct ieee80211_eht_mcs_nss_supp_bw *mcs_nss; - u8 *he_phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info; + u8 *he_phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info; - switch (sta->deflink.bandwidth) { + switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_320: mcs_nss = &eht_cap->eht_mcs_nss_supp.bw._320; /* MCS 9, 11, 13 */ @@ -195,15 +195,16 @@ static u64 rtw89_phy_ra_mask_recover(u64 ra_mask, u64 ra_mask_bak) return ra_mask; } -static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link, + struct ieee80211_link_sta *link_sta, const struct rtw89_chan *chan) { - struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); - struct cfg80211_bitrate_mask *mask = &rtwsta->mask; + struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask; enum nl80211_band band; u64 cfg_mask; - if (!rtwsta->use_cfg_mask) + if (!rtwsta_link->use_cfg_mask) return -1; switch (chan->band_type) { @@ -227,17 +228,17 @@ static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtw return -1; } - if (sta->deflink.he_cap.has_he) { + if (link_sta->he_cap.has_he) { cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[0], RA_MASK_HE_1SS_RATES); cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[1], RA_MASK_HE_2SS_RATES); - } else if (sta->deflink.vht_cap.vht_supported) { + } else if (link_sta->vht_cap.vht_supported) { cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0], RA_MASK_VHT_1SS_RATES); cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1], RA_MASK_VHT_2SS_RATES); - } else if (sta->deflink.ht_cap.ht_supported) { + } else if (link_sta->ht_cap.ht_supported) { cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0], RA_MASK_HT_1SS_RATES); cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1], @@ -261,17 +262,17 @@ rtw89_ra_mask_eht_rates[4] = {RA_MASK_EHT_1SS_RATES, RA_MASK_EHT_2SS_RATES, RA_MASK_EHT_3SS_RATES, RA_MASK_EHT_4SS_RATES}; static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, + struct rtw89_sta_link *rtwsta_link, const struct rtw89_chan *chan, bool *fix_giltf_en, u8 *fix_giltf) { - struct cfg80211_bitrate_mask *mask = &rtwsta->mask; + struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask; u8 band = chan->band_type; enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band); u8 he_gi = mask->control[nl_band].he_gi; u8 he_ltf = mask->control[nl_band].he_ltf; - if (!rtwsta->use_cfg_mask) + if (!rtwsta_link->use_cfg_mask) return; if (he_ltf == 2 && he_gi == 2) { @@ -295,17 +296,17 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev, } static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, bool csi) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct ieee80211_link_sta *link_sta, + bool p2p, bool csi) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; - struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern; - struct rtw89_ra_info *ra = &rtwsta->ra; + struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern; + struct rtw89_ra_info *ra = &rtwsta_link->ra; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif); + rtwvif_link->chanctx_idx); const u64 *high_rate_masks = rtw89_ra_mask_ht_rates; - u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi); + u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi); u64 ra_mask = 0; u64 ra_mask_bak; u8 mode = 0; @@ -320,65 +321,65 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, memset(ra, 0, sizeof(*ra)); /* Set the ra mask from sta's capability */ - if (sta->deflink.eht_cap.has_eht) { + if (link_sta->eht_cap.has_eht) { mode |= RTW89_RA_MODE_EHT; - ra_mask |= get_eht_ra_mask(sta); + ra_mask |= get_eht_ra_mask(link_sta); high_rate_masks = rtw89_ra_mask_eht_rates; - } else if (sta->deflink.he_cap.has_he) { + } else if (link_sta->he_cap.has_he) { mode |= RTW89_RA_MODE_HE; csi_mode = RTW89_RA_RPT_MODE_HE; - ra_mask |= get_he_ra_mask(sta); + ra_mask |= get_he_ra_mask(link_sta); high_rate_masks = rtw89_ra_mask_he_rates; - if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[2] & + if (link_sta->he_cap.he_cap_elem.phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) stbc_en = 1; - if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[1] & + if (link_sta->he_cap.he_cap_elem.phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) ldpc_en = 1; - rtw89_phy_ra_gi_ltf(rtwdev, rtwsta, chan, &fix_giltf_en, &fix_giltf); - } else if (sta->deflink.vht_cap.vht_supported) { - u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); + rtw89_phy_ra_gi_ltf(rtwdev, rtwsta_link, chan, &fix_giltf_en, &fix_giltf); + } else if (link_sta->vht_cap.vht_supported) { + u16 mcs_map = le16_to_cpu(link_sta->vht_cap.vht_mcs.rx_mcs_map); mode |= RTW89_RA_MODE_VHT; csi_mode = RTW89_RA_RPT_MODE_VHT; /* MCS9 (non-20MHz), MCS8, MCS7 */ - if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) + if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20) ra_mask |= get_mcs_ra_mask(mcs_map, 8, 1); else ra_mask |= get_mcs_ra_mask(mcs_map, 9, 1); high_rate_masks = rtw89_ra_mask_vht_rates; - if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) + if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) stbc_en = 1; - if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) + if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) ldpc_en = 1; - } else if (sta->deflink.ht_cap.ht_supported) { + } else if (link_sta->ht_cap.ht_supported) { mode |= RTW89_RA_MODE_HT; csi_mode = RTW89_RA_RPT_MODE_HT; - ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 48) | - ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 36) | - ((u64)sta->deflink.ht_cap.mcs.rx_mask[1] << 24) | - ((u64)sta->deflink.ht_cap.mcs.rx_mask[0] << 12); + ra_mask |= ((u64)link_sta->ht_cap.mcs.rx_mask[3] << 48) | + ((u64)link_sta->ht_cap.mcs.rx_mask[2] << 36) | + ((u64)link_sta->ht_cap.mcs.rx_mask[1] << 24) | + ((u64)link_sta->ht_cap.mcs.rx_mask[0] << 12); high_rate_masks = rtw89_ra_mask_ht_rates; - if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) + if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) stbc_en = 1; - if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) + if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) ldpc_en = 1; } switch (chan->band_type) { case RTW89_BAND_2G: - ra_mask |= sta->deflink.supp_rates[NL80211_BAND_2GHZ]; - if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xf) + ra_mask |= link_sta->supp_rates[NL80211_BAND_2GHZ]; + if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xf) mode |= RTW89_RA_MODE_CCK; - if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xff0) + if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xff0) mode |= RTW89_RA_MODE_OFDM; break; case RTW89_BAND_5G: - ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4; + ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_5GHZ] << 4; mode |= RTW89_RA_MODE_OFDM; break; case RTW89_BAND_6G: - ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_6GHZ] << 4; + ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_6GHZ] << 4; mode |= RTW89_RA_MODE_OFDM; break; default: @@ -405,48 +406,48 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, ra_mask &= rtw89_phy_ra_mask_rssi(rtwdev, rssi, 0); ra_mask = rtw89_phy_ra_mask_recover(ra_mask, ra_mask_bak); - ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta, chan); + ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan); - switch (sta->deflink.bandwidth) { + switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_160: bw_mode = RTW89_CHANNEL_WIDTH_160; - sgi = sta->deflink.vht_cap.vht_supported && - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); + sgi = link_sta->vht_cap.vht_supported && + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); break; case IEEE80211_STA_RX_BW_80: bw_mode = RTW89_CHANNEL_WIDTH_80; - sgi = sta->deflink.vht_cap.vht_supported && - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); + sgi = link_sta->vht_cap.vht_supported && + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); break; case IEEE80211_STA_RX_BW_40: bw_mode = RTW89_CHANNEL_WIDTH_40; - sgi = sta->deflink.ht_cap.ht_supported && - (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40); + sgi = link_sta->ht_cap.ht_supported && + (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); break; default: bw_mode = RTW89_CHANNEL_WIDTH_20; - sgi = sta->deflink.ht_cap.ht_supported && - (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20); + sgi = link_sta->ht_cap.ht_supported && + (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); break; } - if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] & + if (link_sta->he_cap.he_cap_elem.phy_cap_info[3] & IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM) ra->dcm_cap = 1; - if (rate_pattern->enable && !vif->p2p) { - ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta, chan); + if (rate_pattern->enable && !p2p) { + ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan); ra_mask &= rate_pattern->ra_mask; mode = rate_pattern->ra_mode; } ra->bw_cap = bw_mode; - ra->er_cap = rtwsta->er_cap; + ra->er_cap = rtwsta_link->er_cap; ra->mode_ctrl = mode; - ra->macid = rtwsta->mac_id; + ra->macid = rtwsta_link->mac_id; ra->stbc_cap = stbc_en; ra->ldpc_cap = ldpc_en; - ra->ss_num = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; + ra->ss_num = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1; ra->en_sgi = sgi; ra->ra_mask = ra_mask; ra->fix_giltf_en = fix_giltf_en; @@ -458,20 +459,29 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, ra->fixed_csi_rate_en = false; ra->ra_csi_rate_en = true; ra->cr_tbl_sel = false; - ra->band_num = rtwvif->phy_idx; + ra->band_num = rtwvif_link->phy_idx; ra->csi_bw = bw_mode; ra->csi_gi_ltf = RTW89_GILTF_LGI_4XHE32; ra->csi_mcs_ss_idx = 5; ra->csi_mode = csi_mode; } -void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, - u32 changed) +static void __rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + u32 changed) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_ra_info *ra = &rtwsta->ra; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_ra_info *ra = &rtwsta_link->ra; + struct ieee80211_link_sta *link_sta; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link, + link_sta, vif->p2p, false); - rtw89_phy_ra_sta_update(rtwdev, sta, false); + rcu_read_unlock(); if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) ra->upd_mask = 1; @@ -489,6 +499,20 @@ void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta rtw89_fw_h2c_ra(rtwdev, ra, false); } +void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, + u32 changed) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + __rtw89_phy_ra_update_sta(rtwdev, rtwvif_link, rtwsta_link, changed); + } +} + static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next, u16 rate_base, u64 ra_mask, u8 ra_mode, u32 rate_ctrl, u32 ctrl_skip, bool force) @@ -523,15 +547,15 @@ static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next, [RTW89_CHIP_BE] = RTW89_HW_RATE_V1_ ## rate, \ } -void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - const struct cfg80211_bitrate_mask *mask) +static +void __rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + const struct cfg80211_bitrate_mask *mask) { struct ieee80211_supported_band *sband; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_phy_rate_pattern next_pattern = {0}; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); static const u16 hw_rate_he[][RTW89_CHIP_GEN_NUM] = { RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS1_MCS0), RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS2_MCS0), @@ -600,7 +624,7 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, if (!next_pattern.enable) goto out; - rtwvif->rate_pattern = next_pattern; + rtwvif_link->rate_pattern = next_pattern; rtw89_debug(rtwdev, RTW89_DBG_RA, "configure pattern: rate 0x%x, mask 0x%llx, mode 0x%x\n", next_pattern.rate, @@ -609,10 +633,22 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, return; out: - rtwvif->rate_pattern.enable = false; + rtwvif_link->rate_pattern.enable = false; rtw89_debug(rtwdev, RTW89_DBG_RA, "unset rate pattern\n"); } +void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + __rtw89_phy_rate_pattern_vif(rtwdev, rtwvif_link, mask); +} + static void rtw89_phy_ra_update_sta_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_dev *rtwdev = (struct rtw89_dev *)data; @@ -627,14 +663,24 @@ void rtw89_phy_ra_update(struct rtw89_dev *rtwdev) rtwdev); } -void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta) +void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_ra_info *ra = &rtwsta->ra; - u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR; - bool csi = rtw89_sta_has_beamformer_cap(sta); + struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_ra_info *ra = &rtwsta_link->ra; + u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR; + struct ieee80211_link_sta *link_sta; + bool csi; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + csi = rtw89_sta_has_beamformer_cap(link_sta); - rtw89_phy_ra_sta_update(rtwdev, sta, csi); + rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link, + link_sta, vif->p2p, csi); + + rcu_read_unlock(); if (rssi > 40) ra->init_rate_lv = 1; @@ -1068,14 +1114,21 @@ static bool rtw89_chip_rf_v1(struct rtw89_dev *rtwdev) return rtwdev->chip->ops->write_rf == rtw89_phy_write_rf_v1; } -static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx phy_idx) +static void __rtw89_phy_bb_reset(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; chip->ops->bb_reset(rtwdev, phy_idx); } +static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev) +{ + __rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0); + if (rtwdev->dbcc_en) + __rtw89_phy_bb_reset(rtwdev, RTW89_PHY_1); +} + static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg, enum rtw89_rf_path rf_path, @@ -1621,13 +1674,15 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev) if (rtwdev->dbcc_en) rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, (void *)RTW89_PHY_1); - rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0); + + rtw89_chip_init_txpwr_unit(rtwdev); bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table; if (bb_gain_table) rtw89_phy_init_reg(rtwdev, bb_gain_table, chip->phy_def->config_bb_gain, NULL); - rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0); + + rtw89_phy_bb_reset(rtwdev); } static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev) @@ -1747,6 +1802,24 @@ void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, } EXPORT_SYMBOL(rtw89_phy_write32_idx); +void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits, + enum rtw89_phy_idx phy_idx) +{ + if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1) + addr += rtw89_phy0_phy1_offset(rtwdev, addr); + rtw89_phy_write32_set(rtwdev, addr, bits); +} +EXPORT_SYMBOL(rtw89_phy_write32_idx_set); + +void rtw89_phy_write32_idx_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bits, + enum rtw89_phy_idx phy_idx) +{ + if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1) + addr += rtw89_phy0_phy1_offset(rtwdev, addr); + rtw89_phy_write32_clr(rtwdev, addr, bits); +} +EXPORT_SYMBOL(rtw89_phy_write32_idx_clr); + u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, enum rtw89_phy_idx phy_idx) { @@ -2553,14 +2626,14 @@ struct rtw89_phy_iter_ra_data { struct sk_buff *c2h; }; -static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) +static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link, + struct ieee80211_link_sta *link_sta, + struct rtw89_phy_iter_ra_data *ra_data) { - struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data; struct rtw89_dev *rtwdev = ra_data->rtwdev; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; const struct rtw89_c2h_ra_rpt *c2h = (const struct rtw89_c2h_ra_rpt *)ra_data->c2h->data; - struct rtw89_ra_report *ra_report = &rtwsta->ra_report; + struct rtw89_ra_report *ra_report = &rtwsta_link->ra_report; const struct rtw89_chip_info *chip = rtwdev->chip; bool format_v1 = chip->chip_gen == RTW89_CHIP_BE; u8 mode, rate, bw, giltf, mac_id; @@ -2570,7 +2643,7 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) u8 t; mac_id = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MACID); - if (mac_id != rtwsta->mac_id) + if (mac_id != rtwsta_link->mac_id) return; rate = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MCSNSS); @@ -2661,8 +2734,26 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) u16_encode_bits(mode, RTW89_HW_RATE_MASK_MOD) | u16_encode_bits(rate, RTW89_HW_RATE_MASK_VAL); ra_report->might_fallback_legacy = mcs <= 2; - sta->deflink.agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report); - rtwsta->max_agg_wait = sta->deflink.agg.max_rc_amsdu_len / 1500 - 1; + link_sta->agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report); + rtwsta_link->max_agg_wait = link_sta->agg.max_rc_amsdu_len / 1500 - 1; +} + +static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; + + rcu_read_lock(); + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + __rtw89_phy_c2h_ra_rpt_iter(rtwsta_link, link_sta, ra_data); + } + + rcu_read_unlock(); } static void @@ -2692,9 +2783,85 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, struct rtw89_c2h_rf_txgapk_rpt_log *txgapk; struct rtw89_c2h_rf_rxdck_rpt_log *rxdck; struct rtw89_c2h_rf_dack_rpt_log *dack; + struct rtw89_c2h_rf_tssi_rpt_log *tssi; struct rtw89_c2h_rf_dpk_rpt_log *dpk; + struct rtw89_c2h_rf_iqk_rpt_log *iqk; + int i, j, k; switch (func) { + case RTW89_PHY_C2H_RFK_LOG_FUNC_IQK: + if (len != sizeof(*iqk)) + goto out; + + iqk = content; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_iqk_init = %x\n", iqk->is_iqk_init); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_reload = %x\n", iqk->is_reload); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_nbiqk = %x\n", iqk->is_nbiqk); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->txiqk_en = %x\n", iqk->txiqk_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->rxiqk_en = %x\n", iqk->rxiqk_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->lok_en = %x\n", iqk->lok_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->iqk_xym_en = %x\n", iqk->iqk_xym_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->iqk_sram_en = %x\n", iqk->iqk_sram_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->iqk_fft_en = %x\n", iqk->iqk_fft_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_fw_iqk = %x\n", iqk->is_fw_iqk); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_iqk_enable = %x\n", iqk->is_iqk_enable); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->iqk_cfir_en = %x\n", iqk->iqk_cfir_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->thermal_rek_en = %x\n", iqk->thermal_rek_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->version = %x\n", iqk->version); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->phy = %x\n", iqk->phy); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->fwk_status = %x\n", iqk->fwk_status); + + for (i = 0; i < 2; i++) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] ======== Path %x ========\n", i); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_band[%d] = %x\n", + i, iqk->iqk_band[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_ch[%d] = %x\n", + i, iqk->iqk_ch[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_bw[%d] = %x\n", + i, iqk->iqk_bw[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_idac[%d] = %x\n", + i, le32_to_cpu(iqk->lok_idac[i])); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_vbuf[%d] = %x\n", + i, le32_to_cpu(iqk->lok_vbuf[i])); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_tx_fail[%d] = %x\n", + i, iqk->iqk_tx_fail[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_rx_fail[%d] = %x\n", + i, iqk->iqk_rx_fail[i]); + for (j = 0; j < 4; j++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->rftxgain[%d][%d] = %x\n", + i, j, le32_to_cpu(iqk->rftxgain[i][j])); + for (j = 0; j < 4; j++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->tx_xym[%d][%d] = %x\n", + i, j, le32_to_cpu(iqk->tx_xym[i][j])); + for (j = 0; j < 4; j++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->rfrxgain[%d][%d] = %x\n", + i, j, le32_to_cpu(iqk->rfrxgain[i][j])); + for (j = 0; j < 4; j++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->rx_xym[%d][%d] = %x\n", + i, j, le32_to_cpu(iqk->rx_xym[i][j])); + } + return; case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK: if (len != sizeof(*dpk)) goto out; @@ -2716,8 +2883,23 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, dack = content; - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]ver=0x%x 0x%x\n", - dack->fwdack_ver, dack->fwdack_rpt_ver); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]FWDACK SUMMARY!!!!!\n"); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]FWDACK ver = 0x%x, FWDACK rpt_ver = 0x%x, driver rpt_ver = 0x%x\n", + dack->fwdack_ver, dack->fwdack_info_ver, 0x2); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]timeout code = [0x%x 0x%x 0x%x 0x%x 0x%x]\n", + dack->addck_timeout, dack->cdack_timeout, dack->dadck_timeout, + dack->adgaink_timeout, dack->msbk_timeout); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]DACK fail = 0x%x\n", dack->dack_fail); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S0 WBADCK = [0x%x]\n", dack->wbdck_d[0]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S1 WBADCK = [0x%x]\n", dack->wbdck_d[1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]DRCK = [0x%x]\n", dack->rck_d); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK ic = [0x%x, 0x%x]\n", dack->cdack_d[0][0][0], dack->cdack_d[0][0][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK qc = [0x%x, 0x%x]\n", @@ -2728,13 +2910,17 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, dack->cdack_d[1][1][0], dack->cdack_d[1][1][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK ic = [0x%x, 0x%x]\n", - dack->addck2_d[0][0][0], dack->addck2_d[0][0][1]); + ((u32)dack->addck2_hd[0][0][0] << 8) | dack->addck2_ld[0][0][0], + ((u32)dack->addck2_hd[0][0][1] << 8) | dack->addck2_ld[0][0][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK qc = [0x%x, 0x%x]\n", - dack->addck2_d[0][1][0], dack->addck2_d[0][1][1]); + ((u32)dack->addck2_hd[0][1][0] << 8) | dack->addck2_ld[0][1][0], + ((u32)dack->addck2_hd[0][1][1] << 8) | dack->addck2_ld[0][1][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK ic = [0x%x, 0x%x]\n", - dack->addck2_d[1][0][0], dack->addck2_d[1][0][1]); + ((u32)dack->addck2_hd[1][0][0] << 8) | dack->addck2_ld[1][0][0], + ((u32)dack->addck2_hd[1][0][1] << 8) | dack->addck2_ld[1][0][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK qc = [0x%x, 0x%x]\n", - dack->addck2_d[1][1][0], dack->addck2_d[1][1][1]); + ((u32)dack->addck2_hd[1][1][0] << 8) | dack->addck2_ld[1][1][0], + ((u32)dack->addck2_hd[1][1][1] << 8) | dack->addck2_ld[1][1][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_GAINK ic = 0x%x, qc = 0x%x\n", dack->adgaink_d[0][0], dack->adgaink_d[0][1]); @@ -2747,18 +2933,29 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, dack->dadck_d[1][0], dack->dadck_d[1][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 biask iqc = 0x%x\n", - dack->biask_d[0][0]); + ((u32)dack->biask_hd[0][0] << 8) | dack->biask_ld[0][0]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 biask iqc = 0x%x\n", - dack->biask_d[1][0]); - - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic: %*ph\n", - (int)sizeof(dack->msbk_d[0][0]), dack->msbk_d[0][0]); - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc: %*ph\n", - (int)sizeof(dack->msbk_d[0][1]), dack->msbk_d[0][1]); - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic: %*ph\n", - (int)sizeof(dack->msbk_d[1][0]), dack->msbk_d[1][0]); - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc: %*ph\n", - (int)sizeof(dack->msbk_d[1][1]), dack->msbk_d[1][1]); + ((u32)dack->biask_hd[1][0] << 8) | dack->biask_ld[1][0]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic:\n"); + for (i = 0; i < 0x10; i++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", + dack->msbk_d[0][0][i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc:\n"); + for (i = 0; i < 0x10; i++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", + dack->msbk_d[0][1][i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic:\n"); + for (i = 0; i < 0x10; i++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", + dack->msbk_d[1][0][i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc:\n"); + for (i = 0; i < 0x10; i++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", + dack->msbk_d[1][1][i]); return; case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK: if (len != sizeof(*rxdck)) @@ -2770,6 +2967,39 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, rxdck->ver, rxdck->band, rxdck->bw, rxdck->ch, rxdck->timeout); return; + case RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI: + if (len != sizeof(*tssi)) + goto out; + + tssi = content; + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 4; k++) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] alignment_power_cw_h[%d][%d][%d]=%d\n", + i, j, k, tssi->alignment_power_cw_h[i][j][k]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] alignment_power_cw_l[%d][%d][%d]=%d\n", + i, j, k, tssi->alignment_power_cw_l[i][j][k]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] alignment_power[%d][%d][%d]=%d\n", + i, j, k, tssi->alignment_power[i][j][k]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] alignment_power_cw[%d][%d][%d]=%d\n", + i, j, k, + (tssi->alignment_power_cw_h[i][j][k] << 8) + + tssi->alignment_power_cw_l[i][j][k]); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] tssi_alimk_state[%d][%d]=%d\n", + i, j, tssi->tssi_alimk_state[i][j]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] default_txagc_offset[%d]=%d\n", + j, tssi->default_txagc_offset[0][j]); + } + } + return; case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK: if (len != sizeof(*txgapk)) goto out; @@ -3171,13 +3401,13 @@ EXPORT_SYMBOL(rtw89_phy_rfk_dack_and_wait); int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, - unsigned int ms) + bool is_chl_k, unsigned int ms) { int ret; rtw89_phy_rfk_report_prep(rtwdev); - ret = rtw89_fw_h2c_rf_rxdck(rtwdev, phy_idx, chan); + ret = rtw89_fw_h2c_rf_rxdck(rtwdev, phy_idx, chan, is_chl_k); if (ret) return ret; @@ -4290,33 +4520,33 @@ void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val, cfo->packet_count++; } -void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info; if (!chip->ul_tb_waveform_ctrl) return; - rtwvif->def_tri_idx = + rtwvif_link->def_tri_idx = rtw89_phy_read32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG); if (chip->chip_id == RTL8852B && rtwdev->hal.cv > CHIP_CBV) - rtwvif->dyn_tb_bedge_en = false; + rtwvif_link->dyn_tb_bedge_en = false; else if (chan->band_type >= RTW89_BAND_5G && chan->band_width >= RTW89_CHANNEL_WIDTH_40) - rtwvif->dyn_tb_bedge_en = true; + rtwvif_link->dyn_tb_bedge_en = true; else - rtwvif->dyn_tb_bedge_en = false; + rtwvif_link->dyn_tb_bedge_en = false; rtw89_debug(rtwdev, RTW89_DBG_UL_TB, "[ULTB] def_if_bandedge=%d, def_tri_idx=%d\n", - ul_tb_info->def_if_bandedge, rtwvif->def_tri_idx); + ul_tb_info->def_if_bandedge, rtwvif_link->def_tri_idx); rtw89_debug(rtwdev, RTW89_DBG_UL_TB, "[ULTB] dyn_tb_begde_en=%d, dyn_tb_tri_en=%d\n", - rtwvif->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en); + rtwvif_link->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en); } struct rtw89_phy_ul_tb_check_data { @@ -4338,7 +4568,7 @@ struct rtw89_phy_power_diff { }; static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { static const struct rtw89_phy_power_diff table[2] = { {0x0, 0x0, 0x0, 0x0, 0xf4, 0x3, 0x3}, @@ -4350,13 +4580,13 @@ static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev, if (!rtwdev->chip->ul_tb_pwr_diff) return; - if (rtwvif->pwr_diff_en == rtwvif->pre_pwr_diff_en) { - rtwvif->pwr_diff_en = false; + if (rtwvif_link->pwr_diff_en == rtwvif_link->pre_pwr_diff_en) { + rtwvif_link->pwr_diff_en = false; return; } - rtwvif->pre_pwr_diff_en = rtwvif->pwr_diff_en; - param = &table[rtwvif->pwr_diff_en]; + rtwvif_link->pre_pwr_diff_en = rtwvif_link->pwr_diff_en; + param = &table[rtwvif_link->pwr_diff_en]; rtw89_phy_write32_mask(rtwdev, R_Q_MATRIX_00, B_Q_MATRIX_00_REAL, param->q_00); @@ -4365,32 +4595,32 @@ static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev, rtw89_phy_write32_mask(rtwdev, R_CUSTOMIZE_Q_MATRIX, B_CUSTOMIZE_Q_MATRIX_EN, param->q_matrix_en); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_NORM_BW160, param->ultb_1t_norm_160); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_NORM_BW160, param->ultb_2t_norm_160); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM1, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM1, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_PATH_COM1_NORM_1STS, param->com1_norm_1sts); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM2, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM2, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_PATH_COM2_RESP_1STS_PATH, param->com2_resp_1sts_path); } static void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct rtw89_phy_ul_tb_check_data *ul_tb_data) { struct rtw89_traffic_stats *stats = &rtwdev->stats; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION) + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION) return; if (!vif->cfg.assoc) @@ -4403,11 +4633,11 @@ void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev, ul_tb_data->low_tf_client = true; ul_tb_data->valid = true; - ul_tb_data->def_tri_idx = rtwvif->def_tri_idx; - ul_tb_data->dyn_tb_bedge_en = rtwvif->dyn_tb_bedge_en; + ul_tb_data->def_tri_idx = rtwvif_link->def_tri_idx; + ul_tb_data->dyn_tb_bedge_en = rtwvif_link->dyn_tb_bedge_en; } - rtw89_phy_ofdma_power_diff(rtwdev, rtwvif); + rtw89_phy_ofdma_power_diff(rtwdev, rtwvif_link); } static void rtw89_phy_ul_tb_waveform_ctrl(struct rtw89_dev *rtwdev, @@ -4453,7 +4683,9 @@ void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_phy_ul_tb_check_data ul_tb_data = {}; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; if (!chip->ul_tb_waveform_ctrl && !chip->ul_tb_pwr_diff) return; @@ -4462,7 +4694,8 @@ void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev) return; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif, &ul_tb_data); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif_link, &ul_tb_data); if (!ul_tb_data.valid) return; @@ -4603,11 +4836,36 @@ static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev) rtw89_phy_antdiv_reg_init(rtwdev); } +static void rtw89_phy_thermal_protect(struct rtw89_dev *rtwdev) +{ + struct rtw89_phy_stat *phystat = &rtwdev->phystat; + struct rtw89_hal *hal = &rtwdev->hal; + u8 th_max = phystat->last_thermal_max; + u8 lv = hal->thermal_prot_lv; + + if (!hal->thermal_prot_th || + (hal->disabled_dm_bitmap & BIT(RTW89_DM_THERMAL_PROTECT))) + return; + + if (th_max > hal->thermal_prot_th && lv < RTW89_THERMAL_PROT_LV_MAX) + lv++; + else if (th_max < hal->thermal_prot_th - 2 && lv > 0) + lv--; + else + return; + + hal->thermal_prot_lv = lv; + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "thermal protection lv=%d\n", lv); + + rtw89_fw_h2c_tx_duty(rtwdev, hal->thermal_prot_lv); +} + static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev) { struct rtw89_phy_stat *phystat = &rtwdev->phystat; + u8 th, th_max = 0; int i; - u8 th; for (i = 0; i < rtwdev->chip->rf_path_num; i++) { th = rtw89_chip_get_thermal(rtwdev, i); @@ -4617,7 +4875,11 @@ static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "path(%d) thermal cur=%u avg=%ld", i, th, ewma_thermal_read(&phystat->avg_thermal[i])); + + th_max = max(th_max, th); } + + phystat->last_thermal_max = th_max; } struct rtw89_phy_iter_rssi_data { @@ -4626,30 +4888,42 @@ struct rtw89_phy_iter_rssi_data { bool rssi_changed; }; -static void rtw89_phy_stat_rssi_update_iter(void *data, - struct ieee80211_sta *sta) +static +void __rtw89_phy_stat_rssi_update_iter(struct rtw89_sta_link *rtwsta_link, + struct rtw89_phy_iter_rssi_data *rssi_data) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_phy_iter_rssi_data *rssi_data = - (struct rtw89_phy_iter_rssi_data *)data; struct rtw89_phy_ch_info *ch_info = rssi_data->ch_info; unsigned long rssi_curr; - rssi_curr = ewma_rssi_read(&rtwsta->avg_rssi); + rssi_curr = ewma_rssi_read(&rtwsta_link->avg_rssi); if (rssi_curr < ch_info->rssi_min) { ch_info->rssi_min = rssi_curr; - ch_info->rssi_min_macid = rtwsta->mac_id; + ch_info->rssi_min_macid = rtwsta_link->mac_id; } - if (rtwsta->prev_rssi == 0) { - rtwsta->prev_rssi = rssi_curr; - } else if (abs((int)rtwsta->prev_rssi - (int)rssi_curr) > (3 << RSSI_FACTOR)) { - rtwsta->prev_rssi = rssi_curr; + if (rtwsta_link->prev_rssi == 0) { + rtwsta_link->prev_rssi = rssi_curr; + } else if (abs((int)rtwsta_link->prev_rssi - (int)rssi_curr) > + (3 << RSSI_FACTOR)) { + rtwsta_link->prev_rssi = rssi_curr; rssi_data->rssi_changed = true; } } +static void rtw89_phy_stat_rssi_update_iter(void *data, + struct ieee80211_sta *sta) +{ + struct rtw89_phy_iter_rssi_data *rssi_data = + (struct rtw89_phy_iter_rssi_data *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) + __rtw89_phy_stat_rssi_update_iter(rtwsta_link, rssi_data); +} + static void rtw89_phy_stat_rssi_update(struct rtw89_dev *rtwdev) { struct rtw89_phy_iter_rssi_data rssi_data = {0}; @@ -4676,6 +4950,10 @@ static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev) memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat)); memset(&phystat->last_pkt_stat, 0, sizeof(phystat->last_pkt_stat)); + + ewma_rssi_init(&phystat->bcn_rssi); + + rtwdev->hal.thermal_prot_lv = 0; } void rtw89_phy_stat_track(struct rtw89_dev *rtwdev) @@ -4683,6 +4961,7 @@ void rtw89_phy_stat_track(struct rtw89_dev *rtwdev) struct rtw89_phy_stat *phystat = &rtwdev->phystat; rtw89_phy_stat_thermal_update(rtwdev); + rtw89_phy_thermal_protect(rtwdev); rtw89_phy_stat_rssi_update(rtwdev); phystat->last_pkt_stat = phystat->cur_pkt_stat; @@ -5188,7 +5467,8 @@ static u32 rtw89_phy_get_ie_bitmap_addr(enum rtw89_phy_status_bitmap ie_page) } static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev, - enum rtw89_phy_status_bitmap ie_page) + enum rtw89_phy_status_bitmap ie_page, + enum rtw89_phy_idx phy_idx) { u32 addr; @@ -5197,12 +5477,12 @@ static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev, addr = rtw89_phy_get_ie_bitmap_addr(ie_page); - return rtw89_phy_read32(rtwdev, addr); + return rtw89_phy_read32_idx(rtwdev, addr, MASKDWORD, phy_idx); } static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, enum rtw89_phy_status_bitmap ie_page, - u32 val) + u32 val, enum rtw89_phy_idx phy_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; u32 addr; @@ -5214,22 +5494,22 @@ static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, val &= B_PHY_STS_BITMAP_MSK_52A; addr = rtw89_phy_get_ie_bitmap_addr(ie_page); - rtw89_phy_write32(rtwdev, addr, val); + rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx); } static void rtw89_physts_enable_ie_bitmap(struct rtw89_dev *rtwdev, enum rtw89_phy_status_bitmap bitmap, enum rtw89_phy_status_ie_type ie, - bool enable) + bool enable, enum rtw89_phy_idx phy_idx) { - u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap); + u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap, phy_idx); if (enable) val |= BIT(ie); else val &= ~BIT(ie); - rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val); + rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val, phy_idx); } static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, @@ -5240,44 +5520,52 @@ static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, const struct rtw89_physts_regs *physts = phy->physts; if (enable) { - rtw89_phy_write32_clr(rtwdev, physts->setting_addr, - physts->dis_trigger_fail_mask); - rtw89_phy_write32_clr(rtwdev, physts->setting_addr, - physts->dis_trigger_brk_mask); + rtw89_phy_write32_idx_clr(rtwdev, physts->setting_addr, + physts->dis_trigger_fail_mask, phy_idx); + rtw89_phy_write32_idx_clr(rtwdev, physts->setting_addr, + physts->dis_trigger_brk_mask, phy_idx); } else { - rtw89_phy_write32_set(rtwdev, physts->setting_addr, - physts->dis_trigger_fail_mask); - rtw89_phy_write32_set(rtwdev, physts->setting_addr, - physts->dis_trigger_brk_mask); + rtw89_phy_write32_idx_set(rtwdev, physts->setting_addr, + physts->dis_trigger_fail_mask, phy_idx); + rtw89_phy_write32_idx_set(rtwdev, physts->setting_addr, + physts->dis_trigger_brk_mask, phy_idx); } } -static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) +static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) { u8 i; - rtw89_physts_enable_fail_report(rtwdev, false, RTW89_PHY_0); + rtw89_physts_enable_fail_report(rtwdev, false, phy_idx); for (i = 0; i < RTW89_PHYSTS_BITMAP_NUM; i++) { if (i >= RTW89_CCK_PKT) rtw89_physts_enable_ie_bitmap(rtwdev, i, RTW89_PHYSTS_IE09_FTR_0, - true); + true, phy_idx); if ((i >= RTW89_CCK_BRK && i <= RTW89_VHT_MU) || (i >= RTW89_RSVD_9 && i <= RTW89_CCK_PKT)) continue; rtw89_physts_enable_ie_bitmap(rtwdev, i, RTW89_PHYSTS_IE24_OFDM_TD_PATH_A, - true); + true, phy_idx); } rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_VHT_PKT, - RTW89_PHYSTS_IE13_DL_MU_DEF, true); + RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx); rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_HE_PKT, - RTW89_PHYSTS_IE13_DL_MU_DEF, true); + RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx); /* force IE01 for channel index, only channel field is valid */ rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_CCK_PKT, - RTW89_PHYSTS_IE01_CMN_OFDM, true); + RTW89_PHYSTS_IE01_CMN_OFDM, true, phy_idx); +} + +static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) +{ + __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_0); + if (rtwdev->dbcc_en) + __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_1); } static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev, int type) @@ -5753,26 +6041,15 @@ void rtw89_phy_dig(struct rtw89_dev *rtwdev) rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, false); } -static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta) +static void __rtw89_phy_tx_path_div_sta_iter(struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_dev *rtwdev = rtwsta->rtwdev; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_hal *hal = &rtwdev->hal; - bool *done = data; u8 rssi_a, rssi_b; u32 candidate; - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION || sta->tdls) - return; - - if (*done) - return; - - *done = true; - - rssi_a = ewma_rssi_read(&rtwsta->rssi[RF_PATH_A]); - rssi_b = ewma_rssi_read(&rtwsta->rssi[RF_PATH_B]); + rssi_a = ewma_rssi_read(&rtwsta_link->rssi[RF_PATH_A]); + rssi_b = ewma_rssi_read(&rtwsta_link->rssi[RF_PATH_B]); if (rssi_a > rssi_b + RTW89_TX_DIV_RSSI_RAW_TH) candidate = RF_A; @@ -5785,7 +6062,7 @@ static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta return; hal->antenna_tx = candidate; - rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta); + rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta_link); if (hal->antenna_tx == RF_A) { rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, B_P0_RFMODE_MUX, 0x12); @@ -5796,6 +6073,37 @@ static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta } } +static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + bool *done = data; + + if (WARN(ieee80211_vif_is_mld(vif), "MLD mix path_div\n")) + return; + + if (sta->tdls) + return; + + if (*done) + return; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION) + continue; + + *done = true; + __rtw89_phy_tx_path_div_sta_iter(rtwdev, rtwsta_link); + return; + } +} + void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; @@ -6002,17 +6310,27 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_chip_cfg_txrx_path(rtwdev); } -void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_reg_def *bss_clr_vld = &chip->bss_clr_vld; - enum rtw89_phy_idx phy_idx = RTW89_PHY_0; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; + struct ieee80211_bss_conf *bss_conf; u8 bss_color; - if (!vif->bss_conf.he_support || !vif->cfg.assoc) + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->he_support || !vif->cfg.assoc) { + rcu_read_unlock(); return; + } + + bss_color = bss_conf->he_bss_color.color; - bss_color = vif->bss_conf.he_bss_color.color; + rcu_read_unlock(); rtw89_phy_write32_idx(rtwdev, bss_clr_vld->addr, bss_clr_vld->mask, 0x1, phy_idx); diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 6dd8ec46939a..c683f4d7d29b 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -815,6 +815,10 @@ void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev, void rtw89_phy_dm_init(struct rtw89_dev *rtwdev); void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 data, enum rtw89_phy_idx phy_idx); +void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits, + enum rtw89_phy_idx phy_idx); +void rtw89_phy_write32_idx_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bits, + enum rtw89_phy_idx phy_idx); u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, enum rtw89_phy_idx phy_idx); s8 *rtw89_phy_raw_byr_seek(struct rtw89_dev *rtwdev, @@ -892,7 +896,7 @@ void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev, phy->set_txpwr_limit_ru(rtwdev, chan, phy_idx); } -void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta); +void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); void rtw89_phy_ra_update(struct rtw89_dev *rtwdev); void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, u32 changed); @@ -929,7 +933,7 @@ int rtw89_phy_rfk_dack_and_wait(struct rtw89_dev *rtwdev, int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, - unsigned int ms); + bool is_chl_k, unsigned int ms); void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, const struct rtw89_chan *chan, @@ -953,11 +957,12 @@ void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu); void rtw89_phy_antdiv_track(struct rtw89_dev *rtwdev); void rtw89_phy_antdiv_work(struct work_struct *work); -void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, enum rtw89_tssi_bandedge_cfg bandedge_cfg); -void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev); u8 rtw89_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band); void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx, diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index 72eda9bbd3ae..37d8f254ae32 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -398,10 +398,9 @@ static void rtw89_phy_bb_wrap_ul_pwr(struct rtw89_dev *rtwdev) } } -static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) +static void __rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx) { - enum rtw89_mac_idx mac_idx = RTW89_MAC_0; - rtw89_phy_bb_wrap_pwr_by_macid_init(rtwdev); rtw89_phy_bb_wrap_tx_path_by_macid_init(rtwdev); rtw89_phy_bb_wrap_listen_path_en_init(rtwdev); @@ -411,6 +410,13 @@ static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) rtw89_phy_bb_wrap_ul_pwr(rtwdev); } +static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) +{ + __rtw89_phy_bb_wrap_init_be(rtwdev, RTW89_MAC_0); + if (rtwdev->dbcc_en) + __rtw89_phy_bb_wrap_init_be(rtwdev, RTW89_MAC_1); +} + static void rtw89_phy_ch_info_init_be(struct rtw89_dev *rtwdev) { rtw89_phy_write32_mask(rtwdev, R_CHINFO_SEG, B_CHINFO_SEG_LEN, 0x0); diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index aebd6404f802..c1c12abc2ea9 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -62,9 +62,9 @@ static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter) rtw89_mac_power_mode_change(rtwdev, enter); } -void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) + if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) return; if (!rtwdev->ps_mode) @@ -85,23 +85,25 @@ void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) rtw89_ps_power_mode_change(rtwdev, false); } -static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_lps_parm lps_param = { - .macid = rtwvif->mac_id, + .macid = rtwvif_link->mac_id, .psmode = RTW89_MAC_AX_PS_MODE_LEGACY, .lastrpwm = RTW89_LAST_RPWM_PS, }; rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL); rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); - rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif); + rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif_link); } -static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_lps_parm lps_param = { - .macid = rtwvif->mac_id, + .macid = rtwvif_link->mac_id, .psmode = RTW89_MAC_AX_PS_MODE_ACTIVE, .lastrpwm = RTW89_LAST_RPWM_ACTIVE, }; @@ -109,7 +111,7 @@ static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); rtw89_fw_leave_lps_check(rtwdev, 0); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); - rtw89_chip_digital_pwr_comp(rtwdev, rtwvif->phy_idx); + rtw89_chip_digital_pwr_comp(rtwdev, rtwvif_link->phy_idx); } void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) @@ -119,7 +121,7 @@ void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) __rtw89_leave_ps_mode(rtwdev); } -void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool ps_mode) { lockdep_assert_held(&rtwdev->mutex); @@ -127,23 +129,26 @@ void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) return; - __rtw89_enter_lps(rtwdev, rtwvif); + __rtw89_enter_lps(rtwdev, rtwvif_link); if (ps_mode) - __rtw89_enter_ps_mode(rtwdev, rtwvif); + __rtw89_enter_ps_mode(rtwdev, rtwvif_link); } -static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION && - rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) return; - __rtw89_leave_lps(rtwdev, rtwvif); + __rtw89_leave_lps(rtwdev, rtwvif_link); } void rtw89_leave_lps(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; lockdep_assert_held(&rtwdev->mutex); @@ -153,12 +158,15 @@ void rtw89_leave_lps(struct rtw89_dev *rtwdev) __rtw89_leave_ps_mode(rtwdev); rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_leave_lps_vif(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_leave_lps_vif(rtwdev, rtwvif_link); } void rtw89_enter_ips(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); @@ -166,14 +174,17 @@ void rtw89_enter_ips(struct rtw89_dev *rtwdev) return; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_vif_deinit(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_vif_deinit(rtwdev, rtwvif_link); rtw89_core_stop(rtwdev); } void rtw89_leave_ips(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; int ret; if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) @@ -186,7 +197,8 @@ void rtw89_leave_ips(struct rtw89_dev *rtwdev) rtw89_set_channel(rtwdev); rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_vif_init(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_vif_init(rtwdev, rtwvif_link); clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); } @@ -197,48 +209,50 @@ void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl) rtw89_leave_lps(rtwdev); } -static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, enum rtw89_p2pps_action act) { if (act == RTW89_P2P_ACT_UPDATE || act == RTW89_P2P_ACT_REMOVE) return; if (act == RTW89_P2P_ACT_INIT) - rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, true); + rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif_link, true); else if (act == RTW89_P2P_ACT_TERMINATE) - rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, false); + rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif_link, false); } static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif) + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; enum rtw89_p2pps_action act; u8 noa_id; - if (rtwvif->last_noa_nr == 0) + if (rtwvif_link->last_noa_nr == 0) return; - for (noa_id = 0; noa_id < rtwvif->last_noa_nr; noa_id++) { - if (noa_id == rtwvif->last_noa_nr - 1) + for (noa_id = 0; noa_id < rtwvif_link->last_noa_nr; noa_id++) { + if (noa_id == rtwvif_link->last_noa_nr - 1) act = RTW89_P2P_ACT_TERMINATE; else act = RTW89_P2P_ACT_REMOVE; - rtw89_tsf32_toggle(rtwdev, rtwvif, act); - rtw89_fw_h2c_p2p_act(rtwdev, vif, NULL, act, noa_id); + rtw89_tsf32_toggle(rtwdev, rtwvif_link, act); + rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf, + NULL, act, noa_id); } } static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif) + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct ieee80211_p2p_noa_desc *desc; enum rtw89_p2pps_action act; u8 noa_id; for (noa_id = 0; noa_id < RTW89_P2P_MAX_NOA_NUM; noa_id++) { - desc = &vif->bss_conf.p2p_noa_attr.desc[noa_id]; + desc = &bss_conf->p2p_noa_attr.desc[noa_id]; if (!desc->count || !desc->duration) break; @@ -246,16 +260,19 @@ static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev, act = RTW89_P2P_ACT_INIT; else act = RTW89_P2P_ACT_UPDATE; - rtw89_tsf32_toggle(rtwdev, rtwvif, act); - rtw89_fw_h2c_p2p_act(rtwdev, vif, desc, act, noa_id); + rtw89_tsf32_toggle(rtwdev, rtwvif_link, act); + rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf, + desc, act, noa_id); } - rtwvif->last_noa_nr = noa_id; + rtwvif_link->last_noa_nr = noa_id; } -void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { - rtw89_p2p_disable_all_noa(rtwdev, vif); - rtw89_p2p_update_noa(rtwdev, vif); + rtw89_p2p_disable_all_noa(rtwdev, rtwvif_link, bss_conf); + rtw89_p2p_update_noa(rtwdev, rtwvif_link, bss_conf); } void rtw89_recalc_lps(struct rtw89_dev *rtwdev) @@ -265,6 +282,12 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev) enum rtw89_entity_mode mode; int count = 0; + /* FIXME: Fix rtw89_enter_lps() and __rtw89_enter_ps_mode() + * to take MLO cases into account before doing the following. + */ + if (rtwdev->support_mlo) + goto disable_lps; + mode = rtw89_get_entity_mode(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) goto disable_lps; @@ -291,9 +314,9 @@ disable_lps: rtwdev->lps_enabled = false; } -void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif) +void rtw89_p2p_noa_renew(struct rtw89_vif_link *rtwvif_link) { - struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa; + struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa; struct rtw89_p2p_noa_ie *ie = &setter->ie; struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head; struct rtw89_noa_attr_head *noa_head = &ie->noa_head; @@ -318,10 +341,10 @@ void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif) noa_head->oppps_ctwindow = 0; } -void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif, +void rtw89_p2p_noa_append(struct rtw89_vif_link *rtwvif_link, const struct ieee80211_p2p_noa_desc *desc) { - struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa; + struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa; struct rtw89_p2p_noa_ie *ie = &setter->ie; struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head; struct rtw89_noa_attr_head *noa_head = &ie->noa_head; @@ -338,9 +361,9 @@ void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif, ie->noa_desc[setter->noa_count++] = *desc; } -u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data) +u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data) { - struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa; + struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa; struct rtw89_p2p_noa_ie *ie = &setter->ie; void *tail; diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h index 54486e4550b6..cdd712966b09 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.h +++ b/drivers/net/wireless/realtek/rtw89/ps.h @@ -5,21 +5,23 @@ #ifndef __RTW89_PS_H_ #define __RTW89_PS_H_ -void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool ps_mode); void rtw89_leave_lps(struct rtw89_dev *rtwdev); void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); -void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); void rtw89_enter_ips(struct rtw89_dev *rtwdev); void rtw89_leave_ips(struct rtw89_dev *rtwdev); void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl); -void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf); void rtw89_recalc_lps(struct rtw89_dev *rtwdev); -void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif); -void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif, +void rtw89_p2p_noa_renew(struct rtw89_vif_link *rtwvif_link); +void rtw89_p2p_noa_append(struct rtw89_vif_link *rtwvif_link, const struct ieee80211_p2p_noa_desc *desc); -u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data); +u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data); static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 69678eab2309..18ec7c0252fb 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -196,6 +196,8 @@ #define R_AX_HALT_C2H 0x016C #define R_AX_WCPU_FW_CTRL 0x01E0 +#define B_AX_IDMEM_SHARE_MODE_RECORD_MASK GENMASK(27, 24) +#define B_AX_IDMEM_SHARE_MODE_RECORD_VALID BIT(23) #define B_AX_WCPU_FWDL_STS_MASK GENMASK(7, 5) #define B_AX_FWDL_PATH_RDY BIT(2) #define B_AX_H2C_PATH_RDY BIT(1) diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index a7720a1f17a7..cad5189708e7 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -646,22 +646,44 @@ static void rtw89_regd_apply_policy_unii4(struct rtw89_dev *rtwdev, sband->channels[i].flags |= IEEE80211_CHAN_DISABLED; } -static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev, - struct wiphy *wiphy) +static bool regd_is_6ghz_blocked(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; const struct rtw89_regd *regd = regulatory->regd; - struct ieee80211_supported_band *sband; u8 index; - int i; index = rtw89_regd_get_index(regd); if (index != RTW89_REGD_MAX_COUNTRY_NUM && !test_bit(index, regulatory->block_6ghz)) - return; + return false; rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is blocked by policy\n", regd->alpha2[0], regd->alpha2[1]); + return true; +} + +static bool regd_is_6ghz_not_applicable(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *regd = regulatory->regd; + + if (regd->txpwr_regd[RTW89_BAND_6G] != RTW89_NA) + return false; + + rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is N/A in regd map\n", + regd->alpha2[0], regd->alpha2[1]); + return true; +} + +static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev, + struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + int i; + + if (!regd_is_6ghz_blocked(rtwdev) && + !regd_is_6ghz_not_applicable(rtwdev)) + return; sband = wiphy->bands[NL80211_BAND_6GHZ]; if (!sband) @@ -793,22 +815,26 @@ static bool __rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; struct rtw89_reg_6ghz_tpe new = {}; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; bool changed = false; rtw89_for_each_rtwvif(rtwdev, rtwvif) { const struct rtw89_reg_6ghz_tpe *tmp; const struct rtw89_chan *chan; - chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); - if (chan->band_type != RTW89_BAND_6G) - continue; + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + if (chan->band_type != RTW89_BAND_6G) + continue; - tmp = &rtwvif->reg_6ghz_tpe; - if (!tmp->valid) - continue; + tmp = &rtwvif_link->reg_6ghz_tpe; + if (!tmp->valid) + continue; - tpe_intersect_constraint(&new, tmp->constraint); + tpe_intersect_constraint(&new, tmp->constraint); + } } if (memcmp(®ulatory->reg_6ghz_tpe, &new, @@ -831,19 +857,24 @@ static bool __rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev) } static int rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool active, + struct rtw89_vif_link *rtwvif_link, bool active, unsigned int *changed) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct rtw89_reg_6ghz_tpe *tpe = &rtwvif->reg_6ghz_tpe; + struct rtw89_reg_6ghz_tpe *tpe = &rtwvif_link->reg_6ghz_tpe; + struct ieee80211_bss_conf *bss_conf; memset(tpe, 0, sizeof(*tpe)); - if (!active || rtwvif->reg_6ghz_power != RTW89_REG_6GHZ_POWER_STD) + if (!active || rtwvif_link->reg_6ghz_power != RTW89_REG_6GHZ_POWER_STD) goto bottom; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); rtw89_calculate_tpe(rtwdev, tpe, &bss_conf->tpe); + + rcu_read_unlock(); + if (!tpe->valid) goto bottom; @@ -867,20 +898,24 @@ static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) const struct rtw89_regd *regd = regulatory->regd; enum rtw89_reg_6ghz_power sel; const struct rtw89_chan *chan; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; int count = 0; u8 index; rtw89_for_each_rtwvif(rtwdev, rtwvif) { - chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); - if (chan->band_type != RTW89_BAND_6G) - continue; + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + if (chan->band_type != RTW89_BAND_6G) + continue; - if (count != 0 && rtwvif->reg_6ghz_power == sel) - continue; + if (count != 0 && rtwvif_link->reg_6ghz_power == sel) + continue; - sel = rtwvif->reg_6ghz_power; - count++; + sel = rtwvif_link->reg_6ghz_power; + count++; + } } if (count != 1) @@ -908,35 +943,41 @@ static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) } static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool active, + struct rtw89_vif_link *rtwvif_link, bool active, unsigned int *changed) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); if (active) { - switch (vif->bss_conf.power_type) { + switch (bss_conf->power_type) { case IEEE80211_REG_VLP_AP: - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_VLP; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_VLP; break; case IEEE80211_REG_LPI_AP: - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_LPI; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_LPI; break; case IEEE80211_REG_SP_AP: - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_STD; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_STD; break; default: - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; break; } } else { - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; } + rcu_read_unlock(); + *changed += __rtw89_reg_6ghz_power_recalc(rtwdev); return 0; } -int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool active) { unsigned int changed = 0; @@ -948,11 +989,11 @@ int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, * so must do reg_6ghz_tpe_recalc() after reg_6ghz_power_recalc(). */ - ret = rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, active, &changed); + ret = rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif_link, active, &changed); if (ret) return ret; - ret = rtw89_reg_6ghz_tpe_recalc(rtwdev, rtwvif, active, &changed); + ret = rtw89_reg_6ghz_tpe_recalc(rtwdev, rtwvif_link, active, &changed); if (ret) return ret; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 1679bd408ef3..68c67a763f4d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -282,7 +282,7 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; u8 val8; - u32 ret; + int ret; rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_AFSM_WLSUS_EN | B_AX_AFSM_PCIE_SUS_EN); @@ -401,7 +401,7 @@ static void rtw8851b_patch_swr_pfm2pwm(struct rtw89_dev *rtwdev) static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF, XTAL_SI_RFC2RF); @@ -1590,10 +1590,11 @@ static void rtw8851b_rfk_init(struct rtw89_dev *rtwdev) rtw8851b_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); } -static void rtw8851b_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8851b_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8851b_rx_dck(rtwdev, phy_idx, chanctx_idx); rtw8851b_iqk(rtwdev, phy_idx, chanctx_idx); @@ -1608,10 +1609,12 @@ static void rtw8851b_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8851b_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8851b_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8851b_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8851b_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx); + rtw8851b_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx, + rtwvif_link->chanctx_idx); } static void rtw8851b_rfk_track(struct rtw89_dev *rtwdev) @@ -2451,6 +2454,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = &rtw89_8851b_phy_bb_table, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index d334924faec8..651cbce1dd7e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, .recognize_intrs = rtw89_pci_recognize_intrs, + + .ssid_quirks = NULL, }; static const struct rtw89_driver_info rtw89_8851be_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index dde96bd63021..e647759ebd69 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -1350,10 +1350,11 @@ static void rtw8852a_rfk_init(struct rtw89_dev *rtwdev) rtw8852a_rx_dck(rtwdev, RTW89_PHY_0, true, RTW89_CHANCTX_0); } -static void rtw8852a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8852a_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8852a_rx_dck(rtwdev, phy_idx, true, chanctx_idx); rtw8852a_iqk(rtwdev, phy_idx, chanctx_idx); @@ -1368,10 +1369,11 @@ static void rtw8852a_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8852a_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8852a_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8852a_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8852a_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx); + rtw8852a_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx); } static void rtw8852a_rfk_track(struct rtw89_dev *rtwdev) @@ -2168,6 +2170,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xc000, 0xd000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = pwr_on_seq_8852a, .pwr_off_seq = pwr_off_seq_8852a, .bb_table = &rtw89_8852a_phy_bb_table, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index 9a675e2193bc..701187d69e14 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -58,6 +58,8 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, .recognize_intrs = rtw89_pci_recognize_intrs, + + .ssid_quirks = NULL, }; static const struct rtw89_driver_info rtw89_8852ae_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 12be52f76427..49a319128316 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -254,7 +254,7 @@ static void rtw8852b_pwr_sps_ana(struct rtw89_dev *rtwdev) static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; rtw8852b_pwr_sps_ana(rtwdev); @@ -383,7 +383,7 @@ func_en: static int rtw8852b_pwr_off_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; rtw8852b_pwr_sps_ana(rtwdev); @@ -562,10 +562,11 @@ static void rtw8852b_rfk_init(struct rtw89_dev *rtwdev) rtw8852b_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); } -static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8852b_rx_dck(rtwdev, phy_idx, chanctx_idx); rtw8852b_iqk(rtwdev, phy_idx, chanctx_idx); @@ -580,10 +581,12 @@ static void rtw8852b_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8852b_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8852b_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8852b_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8852b_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx); + rtw8852b_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx, + rtwvif_link->chanctx_idx); } static void rtw8852b_rfk_track(struct rtw89_dev *rtwdev) @@ -805,6 +808,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = &rtw89_8852b_phy_bb_table, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index ede0ca5426ae..f4aa4437fb75 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -905,7 +905,6 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 rx_path_0; - u32 val; rx_path_0 = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, phy_idx); @@ -985,12 +984,11 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, pri_ch, phy_idx); - /*Set RF mode at A */ - val = chip_id == RTL8852BT ? 0x333 : 0xaaa; + /*Set RF mode at 3 */ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, val, phy_idx); + B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, val, phy_idx); + B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); break; default: rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri ch:%d)\n", bw, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index d8f9d92ca0fb..a13ea1cce4a7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, .recognize_intrs = rtw89_pci_recognize_intrs, + + .ssid_quirks = NULL, }; static const struct rtw89_driver_info rtw89_8852be_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 7dfdcb5964e1..876725133228 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -244,7 +244,7 @@ static const u8 rtw89_btc_8852bt_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30, static int rtw8852bt_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; rtw89_write32_set(rtwdev, R_AX_LDO_AON_CTRL0, B_AX_PD_REGU_L); rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_AFSM_WLSUS_EN | @@ -357,7 +357,7 @@ func_en: static int rtw8852bt_pwr_off_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF, XTAL_SI_RFC2RF); @@ -535,10 +535,11 @@ static void rtw8852bt_rfk_init(struct rtw89_dev *rtwdev) rtw8852bt_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); } -static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8852bt_rx_dck(rtwdev, phy_idx, chanctx_idx); rtw8852bt_iqk(rtwdev, phy_idx, chanctx_idx); @@ -553,10 +554,12 @@ static void rtw8852bt_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8852bt_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8852bt_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8852bt_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8852bt_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx); + rtw8852bt_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx, + rtwvif_link->chanctx_idx); } static void rtw8852bt_rfk_track(struct rtw89_dev *rtwdev) @@ -739,6 +742,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c index 702948119646..e4f40c2e287d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c @@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8852bt_pci_info = { .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, .recognize_intrs = rtw89_pci_recognize_intrs, + + .ssid_quirks = NULL, }; static const struct rtw89_driver_info rtw89_8852bte_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 1c6e89ab0f4b..cde34f8e1e67 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -203,7 +203,7 @@ static void rtw8852c_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev, u8 tx_path, static int rtw8852c_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; val32 = rtw89_read32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_PAD_HCI_SEL_V2_MASK); if (val32 == MAC_AX_HCI_SEL_PCIE_USB) @@ -324,7 +324,7 @@ static int rtw8852c_pwr_on_func(struct rtw89_dev *rtwdev) static int rtw8852c_pwr_off_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF, XTAL_SI_RFC2RF); @@ -1846,10 +1846,11 @@ static void rtw8852c_rfk_init(struct rtw89_dev *rtwdev) rtw8852c_rx_dck(rtwdev, RTW89_PHY_0, false); } -static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8852c_mcc_get_ch_info(rtwdev, phy_idx); rtw8852c_rx_dck(rtwdev, phy_idx, false); @@ -1866,10 +1867,11 @@ static void rtw8852c_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8852c_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8852c_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8852c_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8852c_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx); + rtw8852c_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx); } static void rtw8852c_rfk_track(struct rtw89_dev *rtwdev) @@ -2945,6 +2947,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xe000, 0xf000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = &rtw89_8852c_phy_bb_table, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c index 211c051c2967..bd17c0a1c684 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c @@ -1065,7 +1065,7 @@ static bool _iqk_nbtxk(struct rtw89_dev *rtwdev, static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; u8 idx = rfk_mcc->table_idx; bool is_fail1, is_fail2; @@ -1408,7 +1408,7 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; u8 idx = 0; idx = rfk_mcc->table_idx; @@ -2350,7 +2350,7 @@ static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, if (dgain > 0x5fc || dgain < 0x556) { _dpk_one_shot(rtwdev, phy, path, D_SYNC); - dgain = _dpk_dgain_read(rtwdev); + _dpk_dgain_read(rtwdev); } if (agc_cnt == 0) { @@ -4105,7 +4105,7 @@ void rtw8852c_set_channel_rf(struct rtw89_dev *rtwdev, void rtw8852c_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; const struct rtw89_chan *chan; enum rtw89_entity_mode mode; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 8aaad7d58c0d..1a46878be96b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -67,6 +67,8 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .enable_intr = rtw89_pci_enable_intr_v1, .disable_intr = rtw89_pci_disable_intr_v1, .recognize_intrs = rtw89_pci_recognize_intrs_v1, + + .ssid_quirks = NULL, }; static const struct dmi_system_id rtw8852c_pci_quirks[] = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 63b1ff2f98ed..9a4db04a1967 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2,6 +2,7 @@ /* Copyright(c) 2023 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "efuse.h" @@ -13,7 +14,7 @@ #include "rtw8922a_rfk.h" #include "util.h" -#define RTW8922A_FW_FORMAT_MAX 1 +#define RTW8922A_FW_FORMAT_MAX 2 #define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" #define RTW8922A_MODULE_FIRMWARE \ RTW8922A_FW_BASENAME "-" __stringify(RTW8922A_FW_FORMAT_MAX) ".bin" @@ -398,9 +399,6 @@ static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN | B_BE_FEN_BBPLAT_RSTB); - if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) - rtw89_efuse_read_fw_secure_be(rtwdev); - return 0; } @@ -965,6 +963,42 @@ static const struct rtw8922a_bb_gain bb_gain_tia[TIA_GAIN_NUM] = { .gain_g_mask = 0x1FF, .gain_a_mask = 0x3FE00 }, }; +static const struct rtw8922a_bb_gain bb_op1db_lna[LNA_GAIN_NUM] = { + { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x4078, 0x4478}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF000000}, + { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x407c, 0x447c}, + .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF}, + { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x407c, 0x447c}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF00}, + { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x407c, 0x447c}, + .gain_g_mask = 0xFF, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x407c, 0x447c}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF000000}, + { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x4080, 0x4480}, + .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF}, + { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x4080, 0x4480}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF00}, +}; + +static const struct rtw8922a_bb_gain bb_op1db_tia_lna[TIA_LNA_OP1DB_NUM] = { + { .gain_g = {0x40b4, 0x44b4}, .gain_a = {0x4080, 0x4480}, + .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF000000}, + { .gain_g = {0x40b4, 0x44b4}, .gain_a = {0x4084, 0x4484}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF}, + { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484}, + .gain_g_mask = 0xFF, .gain_a_mask = 0xFF00}, + { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484}, + .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF000000}, + { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4088, 0x4488}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF}, + { .gain_g = {0x40bc, 0x44bc}, .gain_a = {0x4088, 0x4488}, + .gain_g_mask = 0xFF, .gain_a_mask = 0xFF00}, + { .gain_g = {0x40bc, 0x44bc}, .gain_a = {0x4088, 0x4488}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF0000}, +}; + struct rtw8922a_bb_gain_bypass { u32 gain_g[BB_PATH_NUM_8922A]; u32 gain_a[BB_PATH_NUM_8922A]; @@ -1056,6 +1090,30 @@ static void rtw8922a_set_lna_tia_gain(struct rtw89_dev *rtwdev, val = gain->tia_gain[gain_band][bw_type][path][i]; rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); } + + for (i = 0; i < LNA_GAIN_NUM; i++) { + if (chan->band_type == RTW89_BAND_2G) { + reg = bb_op1db_lna[i].gain_g[path]; + mask = bb_op1db_lna[i].gain_g_mask; + } else { + reg = bb_op1db_lna[i].gain_a[path]; + mask = bb_op1db_lna[i].gain_a_mask; + } + val = gain->lna_op1db[gain_band][bw_type][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < TIA_LNA_OP1DB_NUM; i++) { + if (chan->band_type == RTW89_BAND_2G) { + reg = bb_op1db_tia_lna[i].gain_g[path]; + mask = bb_op1db_tia_lna[i].gain_g_mask; + } else { + reg = bb_op1db_tia_lna[i].gain_a[path]; + mask = bb_op1db_tia_lna[i].gain_a_mask; + } + val = gain->tia_lna_op1db[gain_band][bw_type][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } } static void rtw8922a_set_gain(struct rtw89_dev *rtwdev, @@ -1745,7 +1803,7 @@ static void rtw8922a_digital_pwr_comp(struct rtw89_dev *rtwdev, static int rtw8922a_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode mode) { - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); + const struct rtw89_chan *chan0, *chan1; if (mode == MLO_1_PLUS_1_1RF || mode == DBCC_LEGACY) { rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x1); @@ -1758,13 +1816,20 @@ static int rtw8922a_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode return -EOPNOTSUPP; } - if (mode == MLO_2_PLUS_0_1RF) { - rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_A); - rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_B); + if (mode == MLO_1_PLUS_1_1RF) { + chan0 = rtw89_mgnt_chan_get(rtwdev, 0); + chan1 = rtw89_mgnt_chan_get(rtwdev, 1); + } else if (mode == MLO_0_PLUS_2_1RF) { + chan1 = rtw89_mgnt_chan_get(rtwdev, 1); + chan0 = chan1; } else { - rtw89_warn(rtwdev, "unsupported MLO mode %d\n", mode); + chan0 = rtw89_mgnt_chan_get(rtwdev, 0); + chan1 = chan0; } + rtw8922a_ctrl_afe_dac(rtwdev, chan0->band_width, RF_PATH_A); + rtw8922a_ctrl_afe_dac(rtwdev, chan1->band_width, RF_PATH_B); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x6180); if (mode == MLO_2_PLUS_0_1RF) { @@ -1991,14 +2056,23 @@ static void rtw8922a_rfk_init(struct rtw89_dev *rtwdev) memset(rfk_mcc, 0, sizeof(*rfk_mcc)); } +static void __rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + const struct rtw89_chan *chan) +{ + rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5); + + rtw89_phy_rfk_dack_and_wait(rtwdev, phy_idx, chan, 58); + rtw89_phy_rfk_rxdck_and_wait(rtwdev, phy_idx, chan, false, 32); +} + static void rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); - rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, RTW89_PHY_0, 5); - - rtw89_phy_rfk_dack_and_wait(rtwdev, RTW89_PHY_0, chan, 58); - rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, 32); + __rtw8922a_rfk_init_late(rtwdev, RTW89_PHY_0, chan); + if (rtwdev->dbcc_en) + __rtw8922a_rfk_init_late(rtwdev, RTW89_PHY_1, chan); } static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) @@ -2020,11 +2094,12 @@ static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) } } -static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB, chanctx_idx); u32 tx_en; @@ -2035,9 +2110,9 @@ static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtw rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5); rtw89_phy_rfk_txgapk_and_wait(rtwdev, phy_idx, chan, 54); rtw89_phy_rfk_iqk_and_wait(rtwdev, phy_idx, chan, 84); - rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 6); + rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 20); rtw89_phy_rfk_dpk_and_wait(rtwdev, phy_idx, chan, 34); - rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, 32); + rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, true, 32); rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_STOP); @@ -2050,7 +2125,8 @@ static void rtw8922a_rfk_band_changed(struct rtw89_dev *rtwdev, rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_SCAN, 6); } -static void rtw8922a_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8922a_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { } @@ -2207,10 +2283,12 @@ static void rtw8922a_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) static u8 rtw8922a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) { struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + struct rtw89_hal *hal = &rtwdev->hal; int th; - /* read thermal only if debugging */ - if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_CFO | RTW89_DBG_RFK_TRACK)) + /* read thermal only if debugging or thermal protection enabled */ + if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_CFO | RTW89_DBG_RFK_TRACK) && + !hal->thermal_prot_th) return 80; rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); @@ -2641,6 +2719,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, + .thermal_th = {0xad, 0xb4}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index 28907df7407d..c4c93f836a2f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -252,49 +252,58 @@ static void rtw8922a_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx) } } -static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) +static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 path) { struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {}; - enum rtw89_chanctx_idx chanctx_idx; - const struct rtw89_chan *chan; - enum rtw89_entity_mode mode; - u8 s0_tbl, s1_tbl; u8 tbl_sel; - mode = rtw89_get_entity_mode(rtwdev); - switch (mode) { - case RTW89_ENTITY_MODE_MCC_PREPARE: - chanctx_idx = RTW89_CHANCTX_1; - break; - default: - chanctx_idx = RTW89_CHANCTX_0; - break; - } - - chan = rtw89_chan_get(rtwdev, chanctx_idx); - for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) { struct rtw89_rfk_chan_desc *p = &desc[tbl_sel]; - p->ch = rfk_mcc->ch[tbl_sel]; + p->ch = rfk_mcc->data[path].ch[tbl_sel]; p->has_band = true; - p->band = rfk_mcc->band[tbl_sel]; + p->band = rfk_mcc->data[path].band[tbl_sel]; p->has_bw = true; - p->bw = rfk_mcc->bw[tbl_sel]; + p->bw = rfk_mcc->data[path].bw[tbl_sel]; } tbl_sel = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); - rfk_mcc->ch[tbl_sel] = chan->channel; - rfk_mcc->band[tbl_sel] = chan->band_type; - rfk_mcc->bw[tbl_sel] = chan->band_width; - rfk_mcc->table_idx = tbl_sel; + rfk_mcc->data[path].ch[tbl_sel] = chan->channel; + rfk_mcc->data[path].band[tbl_sel] = chan->band_type; + rfk_mcc->data[path].bw[tbl_sel] = chan->band_width; + rfk_mcc->data[path].table_idx = tbl_sel; + + return tbl_sel; +} + +static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chan *chan0, *chan1; + u8 s0_tbl, s1_tbl; + + switch (rtwdev->mlo_dbcc_mode) { + default: + case MLO_2_PLUS_0_1RF: + chan0 = rtw89_mgnt_chan_get(rtwdev, 0); + chan1 = chan0; + break; + case MLO_0_PLUS_2_1RF: + chan1 = rtw89_mgnt_chan_get(rtwdev, 1); + chan0 = chan1; + break; + case MLO_1_PLUS_1_1RF: + chan0 = rtw89_mgnt_chan_get(rtwdev, 0); + chan1 = rtw89_mgnt_chan_get(rtwdev, 1); + break; + } - s0_tbl = tbl_sel; - s1_tbl = tbl_sel; + s0_tbl = rtw8922a_chlk_reload_sel_tbl(rtwdev, chan0, 0); + s1_tbl = rtw8922a_chlk_reload_sel_tbl(rtwdev, chan1, 1); rtw8922a_chlk_ktbl_sel(rtwdev, RF_A, s0_tbl); rtw8922a_chlk_ktbl_sel(rtwdev, RF_B, s1_tbl); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 47f855a7a268..edfb1f220af0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -9,6 +9,12 @@ #include "reg.h" #include "rtw8922a.h" +static const struct rtw89_pci_ssid_quirk rtw8922a_pci_ssid_quirks[] = { + {RTW89_PCI_SSID(PCI_VENDOR_ID_REALTEK, 0x8922, 0x10EC, 0xA891, DELL), + .bitmap = BIT(RTW89_QUIRK_THERMAL_PROT_120C)}, + {}, +}; + static const struct rtw89_pci_info rtw8922a_pci_info = { .gen_def = &rtw89_pci_gen_be, .txbd_trunc_mode = MAC_AX_BD_TRUNC, @@ -58,6 +64,8 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .enable_intr = rtw89_pci_enable_intr_v2, .disable_intr = rtw89_pci_disable_intr_v2, .recognize_intrs = rtw89_pci_recognize_intrs_v2, + + .ssid_quirks = rtw8922a_pci_ssid_quirks, }; static const struct rtw89_driver_info rtw89_8922ae_info = { diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c index 27826d909785..bcc287771b2a 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -27,8 +27,8 @@ static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev, return RTW89_SAR_5GHZ_SUBBAND_1_2; case 5500 ... 5720: return RTW89_SAR_5GHZ_SUBBAND_2_E; - case 5745 ... 5825: - return RTW89_SAR_5GHZ_SUBBAND_3; + case 5745 ... 5885: + return RTW89_SAR_5GHZ_SUBBAND_3_4; case 5955 ... 6155: return RTW89_SAR_6GHZ_SUBBAND_5_L; case 6175 ... 6415: @@ -295,7 +295,7 @@ static const struct cfg80211_sar_freq_ranges rtw89_common_sar_freq_ranges[] = { { .start_freq = 2412, .end_freq = 2484, }, { .start_freq = 5180, .end_freq = 5320, }, { .start_freq = 5500, .end_freq = 5720, }, - { .start_freq = 5745, .end_freq = 5825, }, + { .start_freq = 5745, .end_freq = 5885, }, { .start_freq = 5955, .end_freq = 6155, }, { .start_freq = 6175, .end_freq = 6415, }, { .start_freq = 6435, .end_freq = 6515, }, diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 5fc2faa9ba5a..7b203bb7f151 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -300,37 +300,54 @@ static void drv_resume_rx(struct rtw89_ser *ser) static void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); - rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; - rtwvif->trigger = false; + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + rtwvif->tdls_peer = 0; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif_link->port); + rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK; + rtwvif_link->trigger = false; + } } static void ser_sta_deinit_cam_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_vif *target_rtwvif = (struct rtw89_vif *)data; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; if (rtwvif != target_rtwvif) return; - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) - rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam); - if (sta->tdls) - rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam); + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; - INIT_LIST_HEAD(&rtwsta->ba_cam_list); + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) + rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta_link->addr_cam); + if (sta->tdls) + rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta_link->bssid_cam); + + INIT_LIST_HEAD(&rtwsta_link->ba_cam_list); + } } static void ser_deinit_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + ieee80211_iterate_stations_atomic(rtwdev->hw, ser_sta_deinit_cam_iter, rtwvif); - rtw89_cam_deinit(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_cam_deinit(rtwdev, rtwvif_link); bitmap_zero(rtwdev->cam_info.ba_cam_map, RTW89_MAX_BA_CAM_NUM); } diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 86e24e07780d..3e81fd974ec1 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -421,7 +421,8 @@ static void rtw89_wow_construct_key_info(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_key_info *key_info = &rtw_wow->key_info; - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); bool err = false; rcu_read_lock(); @@ -596,7 +597,8 @@ static int rtw89_wow_get_aoac_rpt(struct rtw89_dev *rtwdev, bool rx_ready) static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev, u32 cipher, u8 keyidx, u8 *gtk) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); const struct rtw89_cipher_info *cipher_info; struct ieee80211_key_conf *rekey_conf; struct ieee80211_key_conf *key; @@ -632,11 +634,13 @@ static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev, static void rtw89_wow_update_key_info(struct rtw89_dev *rtwdev, bool rx_ready) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt; struct rtw89_set_key_info_iter_data data = {.error = false, .rx_ready = rx_ready}; + struct ieee80211_bss_conf *bss_conf; struct ieee80211_key_conf *key; rcu_read_lock(); @@ -669,9 +673,15 @@ static void rtw89_wow_update_key_info(struct rtw89_dev *rtwdev, bool rx_ready) return; rtw89_rx_pn_set_pmf(rtwdev, key, aoac_rpt->igtk_ipn); - ieee80211_gtk_rekey_notify(wow_vif, wow_vif->bss_conf.bssid, + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ieee80211_gtk_rekey_notify(wow_vif, bss_conf->bssid, aoac_rpt->eapol_key_replay_count, - GFP_KERNEL); + GFP_ATOMIC); + + rcu_read_unlock(); } static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev) @@ -681,27 +691,24 @@ static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev) static void rtw89_wow_enter_deep_ps(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; - __rtw89_enter_ps_mode(rtwdev, rtwvif); + __rtw89_enter_ps_mode(rtwdev, rtwvif_link); } static void rtw89_wow_enter_ps(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; if (rtw89_wow_mgd_linked(rtwdev)) - rtw89_enter_lps(rtwdev, rtwvif, false); + rtw89_enter_lps(rtwdev, rtwvif_link, false); else if (rtw89_wow_no_link(rtwdev)) - rtw89_fw_h2c_fwips(rtwdev, rtwvif, true); + rtw89_fw_h2c_fwips(rtwdev, rtwvif_link, true); } static void rtw89_wow_leave_ps(struct rtw89_dev *rtwdev, bool enable_wow) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; if (rtw89_wow_mgd_linked(rtwdev)) { rtw89_leave_lps(rtwdev); @@ -709,7 +716,7 @@ static void rtw89_wow_leave_ps(struct rtw89_dev *rtwdev, bool enable_wow) if (enable_wow) rtw89_leave_ips(rtwdev); else - rtw89_fw_h2c_fwips(rtwdev, rtwvif, false); + rtw89_fw_h2c_fwips(rtwdev, rtwvif_link, false); } } @@ -734,6 +741,8 @@ static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable) static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt; struct cfg80211_wowlan_nd_info nd_info; @@ -780,35 +789,34 @@ static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) break; default: rtw89_warn(rtwdev, "Unknown wakeup reason %x\n", reason); - ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL, - GFP_KERNEL); + ieee80211_report_wowlan_wakeup(wow_vif, NULL, GFP_KERNEL); return; } - ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup, - GFP_KERNEL); + ieee80211_report_wowlan_wakeup(wow_vif, &wakeup, GFP_KERNEL); } -static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); /* Current WoWLAN function support setting of only vif in * infra mode or no link mode. When one suitable vif is found, * stop the iteration. */ - if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION) + if (rtw_wow->rtwvif_link || vif->type != NL80211_IFTYPE_STATION) return; - switch (rtwvif->net_type) { + switch (rtwvif_link->net_type) { case RTW89_NET_TYPE_INFRA: if (rtw_wow_has_mgd_features(rtwdev)) - rtw_wow->wow_vif = vif; + rtw_wow->rtwvif_link = rtwvif_link; break; case RTW89_NET_TYPE_NO_LINK: if (rtw_wow->pno_inited) - rtw_wow->wow_vif = vif; + rtw_wow->rtwvif_link = rtwvif_link; break; default: break; @@ -865,7 +873,7 @@ static u16 rtw89_calc_crc(u8 *pdata, int length) return ~crc; } -static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, +static int rtw89_wow_pattern_get_type(struct rtw89_vif_link *rtwvif_link, struct rtw89_wow_cam_info *rtw_pattern, const u8 *pattern, u8 da_mask) { @@ -885,7 +893,7 @@ static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, rtw_pattern->bc = true; else if (is_multicast_ether_addr(da)) rtw_pattern->mc = true; - else if (ether_addr_equal(da, rtwvif->mac_addr) && + else if (ether_addr_equal(da, rtwvif_link->mac_addr) && da_mask == GENMASK(5, 0)) rtw_pattern->uc = true; else if (!da_mask) /*da_mask == 0 mean wildcard*/ @@ -897,7 +905,7 @@ static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, } static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, const struct cfg80211_pkt_pattern *pkt_pattern, struct rtw89_wow_cam_info *rtw_pattern) { @@ -916,7 +924,7 @@ static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, mask_len = DIV_ROUND_UP(len, 8); memset(rtw_pattern, 0, sizeof(*rtw_pattern)); - ret = rtw89_wow_pattern_get_type(rtwvif, rtw_pattern, pattern, + ret = rtw89_wow_pattern_get_type(rtwvif_link, rtw_pattern, pattern, mask[0] & GENMASK(5, 0)); if (ret) return ret; @@ -970,7 +978,7 @@ static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, } static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct cfg80211_wowlan *wowlan) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; @@ -983,7 +991,7 @@ static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev, for (i = 0; i < wowlan->n_patterns; i++) { rtw_pattern = &rtw_wow->patterns[i]; - ret = rtw89_wow_pattern_generate(rtwdev, rtwvif, + ret = rtw89_wow_pattern_generate(rtwdev, rtwvif_link, &wowlan->patterns[i], rtw_pattern); if (ret) { @@ -1040,7 +1048,7 @@ static void rtw89_wow_clear_wakeups(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - rtw_wow->wow_vif = NULL; + rtw_wow->rtwvif_link = NULL; rtw89_core_release_all_bits_map(rtw_wow->flags, RTW89_WOW_FLAG_NUM); rtw_wow->pattern_cnt = 0; rtw_wow->pno_inited = false; @@ -1066,6 +1074,7 @@ static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; if (wowlan->disconnect) @@ -1078,36 +1087,40 @@ static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev, if (wowlan->nd_config) rtw89_wow_init_pno(rtwdev, wowlan->nd_config); - rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_wow_vif_iter(rtwdev, rtwvif); + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + /* use the link on HW-0 to do wow flow */ + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (!rtwvif_link) + continue; + + rtw89_wow_vif_iter(rtwdev, rtwvif_link); + } - if (!rtw_wow->wow_vif) + rtwvif_link = rtw_wow->rtwvif_link; + if (!rtwvif_link) return -EPERM; - rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; - return rtw89_wow_parse_patterns(rtwdev, rtwvif, wowlan); + return rtw89_wow_parse_patterns(rtwdev, rtwvif_link, wowlan); } static int rtw89_wow_cfg_wake_pno(struct rtw89_dev *rtwdev, bool wow) { - struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; int ret; - ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif_link, true); if (ret) { rtw89_err(rtwdev, "failed to config pno\n"); return ret; } - ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow); + ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif_link, wow); if (ret) { rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n"); return ret; } - ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow); + ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif_link, wow); if (ret) { rtw89_err(rtwdev, "failed to fw wow global\n"); return ret; @@ -1119,34 +1132,39 @@ static int rtw89_wow_cfg_wake_pno(struct rtw89_dev *rtwdev, bool wow) static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); struct ieee80211_sta *wow_sta; - struct rtw89_sta *rtwsta = NULL; + struct rtw89_sta_link *rtwsta_link = NULL; + struct rtw89_sta *rtwsta; int ret; - wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); - if (wow_sta) - rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; + wow_sta = ieee80211_find_sta(wow_vif, wow_vif->cfg.ap_addr); + if (wow_sta) { + rtwsta = sta_to_rtwsta(wow_sta); + rtwsta_link = rtwsta->links[rtwvif_link->link_id]; + if (!rtwsta_link) + return -ENOLINK; + } if (wow) { if (rtw_wow->pattern_cnt) - rtwvif->wowlan_pattern = true; + rtwvif_link->wowlan_pattern = true; if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) - rtwvif->wowlan_magic = true; + rtwvif_link->wowlan_magic = true; } else { - rtwvif->wowlan_pattern = false; - rtwvif->wowlan_magic = false; + rtwvif_link->wowlan_pattern = false; + rtwvif_link->wowlan_magic = false; } - ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow); + ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif_link, wow); if (ret) { rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n"); return ret; } if (wow) { - ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n", ret); @@ -1154,13 +1172,13 @@ static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) } } - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; } - ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow); + ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif_link, wow); if (ret) { rtw89_err(rtwdev, "failed to fw wow global\n"); return ret; @@ -1190,25 +1208,30 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) enum rtw89_fw_type fw_type = wow ? RTW89_FW_WOWLAN : RTW89_FW_NORMAL; enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; const struct rtw89_chip_info *chip = rtwdev->chip; bool include_bb = !!chip->bbmcu_nr; bool disable_intr_for_dlfw = false; struct ieee80211_sta *wow_sta; - struct rtw89_sta *rtwsta = NULL; + struct rtw89_sta_link *rtwsta_link = NULL; + struct rtw89_sta *rtwsta; bool is_conn = true; int ret; if (chip_id == RTL8852C || chip_id == RTL8922A) disable_intr_for_dlfw = true; - wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); - if (wow_sta) - rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; - else + wow_sta = ieee80211_find_sta(wow_vif, wow_vif->cfg.ap_addr); + if (wow_sta) { + rtwsta = sta_to_rtwsta(wow_sta); + rtwsta_link = rtwsta->links[rtwvif_link->link_id]; + if (!rtwsta_link) + return -ENOLINK; + } else { is_conn = false; + } if (disable_intr_for_dlfw) rtw89_hci_disable_intr(rtwdev); @@ -1224,14 +1247,14 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) rtw89_phy_init_rf_reg(rtwdev, true); - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link, RTW89_ROLE_FW_RESTORE); if (ret) { rtw89_warn(rtwdev, "failed to send h2c role maintain\n"); return ret; } - ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n"); return ret; @@ -1240,27 +1263,27 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) if (!is_conn) rtw89_cam_reset_keys(rtwdev); - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn); + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, !is_conn); if (ret) { rtw89_warn(rtwdev, "failed to send h2c join info\n"); return ret; } - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; } if (is_conn) { - ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id); + ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id); if (ret) { rtw89_warn(rtwdev, "failed to send h2c general packet\n"); return ret; } - rtw89_phy_ra_assoc(rtwdev, wow_sta); - rtw89_phy_set_bss_color(rtwdev, wow_vif); - rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif); + rtw89_phy_ra_assoc(rtwdev, rtwsta_link); + rtw89_phy_set_bss_color(rtwdev, rtwvif_link); + rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, rtwvif_link); } if (chip_gen == RTW89_CHIP_BE) @@ -1363,21 +1386,20 @@ static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev) static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev) { - struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *vif = rtw_wow->wow_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; int ret; ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); if (ret) rtw89_err(rtwdev, "cfg ppdu status\n"); - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); return ret; } static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct list_head *pkt_list = &rtw_wow->pno_pkt_list; @@ -1391,7 +1413,7 @@ static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev, } static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; @@ -1401,7 +1423,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, int ret; for (i = 0; i < num; i++) { - skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr, + skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, nd_config->match_sets[i].ssid.ssid, nd_config->match_sets[i].ssid.ssid_len, nd_config->ie_len); @@ -1413,7 +1435,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { kfree_skb(skb); - rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif); + rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link); return -ENOMEM; } @@ -1421,7 +1443,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, if (ret) { kfree_skb(skb); kfree(info); - rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif); + rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link); return ret; } @@ -1436,20 +1458,19 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; int interval = rtw_wow->nd_config->scan_plans[0].interval; struct rtw89_scan_option opt = {}; int ret; if (enable) { - ret = rtw89_pno_scan_update_probe_req(rtwdev, rtwvif); + ret = rtw89_pno_scan_update_probe_req(rtwdev, rtwvif_link); if (ret) { rtw89_err(rtwdev, "Update probe request failed\n"); return ret; } - ret = mac->add_chan_list_pno(rtwdev, rtwvif); + ret = mac->add_chan_list_pno(rtwdev, rtwvif_link); if (ret) { rtw89_err(rtwdev, "Update channel list failed\n"); return ret; @@ -1471,7 +1492,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) opt.opch_end = RTW89_CHAN_INVALID; } - mac->scan_offload(rtwdev, &opt, rtwvif, true); + mac->scan_offload(rtwdev, &opt, rtwvif_link, true); return 0; } @@ -1479,8 +1500,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link; int ret; if (rtw89_wow_no_link(rtwdev)) { @@ -1499,25 +1519,25 @@ static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) rtw89_wow_pattern_write(rtwdev); rtw89_wow_construct_key_info(rtwdev); - ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif_link, true); if (ret) { rtw89_err(rtwdev, "wow: failed to enable keep alive\n"); return ret; } - ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif_link, true); if (ret) { rtw89_err(rtwdev, "wow: failed to enable disconnect detect\n"); return ret; } - ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif_link, true); if (ret) { rtw89_err(rtwdev, "wow: failed to enable GTK offload\n"); return ret; } - ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif_link, true); if (ret) rtw89_warn(rtwdev, "wow: failed to enable arp offload\n"); } @@ -1548,8 +1568,7 @@ static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link; int ret; if (rtw89_wow_no_link(rtwdev)) { @@ -1559,35 +1578,35 @@ static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) return ret; } - ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif_link, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable pno\n"); return ret; } - rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif); + rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link); } else { rtw89_wow_pattern_clear(rtwdev); - ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif_link, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable keep alive\n"); return ret; } - ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif_link, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n"); return ret; } - ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif_link, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable GTK offload\n"); return ret; } - ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif_link, false); if (ret) rtw89_warn(rtwdev, "wow: failed to disable arp offload\n"); diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index 3fbc2b87c058..f91991e8f2e3 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -97,18 +97,16 @@ static inline int rtw89_wow_get_sec_hdr_len(struct rtw89_dev *rtwdev) #ifdef CONFIG_PM static inline bool rtw89_wow_mgd_linked(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; - return rtwvif->net_type == RTW89_NET_TYPE_INFRA; + return rtwvif_link->net_type == RTW89_NET_TYPE_INFRA; } static inline bool rtw89_wow_no_link(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; - return rtwvif->net_type == RTW89_NET_TYPE_NO_LINK; + return rtwvif_link->net_type == RTW89_NET_TYPE_NO_LINK; } static inline bool rtw_wow_has_mgd_features(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c index e7198520bdff..64441c8bc460 100644 --- a/drivers/net/wireless/silabs/wfx/main.c +++ b/drivers/net/wireless/silabs/wfx/main.c @@ -480,10 +480,23 @@ static int __init wfx_core_init(void) { int ret = 0; - if (IS_ENABLED(CONFIG_SPI)) + if (IS_ENABLED(CONFIG_SPI)) { ret = spi_register_driver(&wfx_spi_driver); - if (IS_ENABLED(CONFIG_MMC) && !ret) + if (ret) + goto out; + } + if (IS_ENABLED(CONFIG_MMC)) { ret = sdio_register_driver(&wfx_sdio_driver); + if (ret) + goto unregister_spi; + } + + return 0; + +unregister_spi: + if (IS_ENABLED(CONFIG_SPI)) + spi_unregister_driver(&wfx_spi_driver); +out: return ret; } module_init(wfx_core_init); diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index 4f346fb977a9..862964a8cc87 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -450,7 +450,7 @@ static int __maybe_unused cw1200_spi_suspend(struct device *dev) { struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev)); - if (!cw1200_can_suspend(self->core)) + if (self && !cw1200_can_suspend(self->core)) return -EAGAIN; /* XXX notify host that we have to keep CW1200 powered on? */ diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c index 805a3c1bf8fe..259739e53fc1 100644 --- a/drivers/net/wireless/st/cw1200/queue.c +++ b/drivers/net/wireless/st/cw1200/queue.c @@ -411,33 +411,6 @@ int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id) return ret; } -int cw1200_queue_requeue_all(struct cw1200_queue *queue) -{ - struct cw1200_queue_item *item, *tmp; - struct cw1200_queue_stats *stats = queue->stats; - spin_lock_bh(&queue->lock); - - list_for_each_entry_safe_reverse(item, tmp, &queue->pending, head) { - --queue->num_pending; - ++queue->link_map_cache[item->txpriv.link_id]; - - spin_lock_bh(&stats->lock); - ++stats->num_queued; - ++stats->link_map_cache[item->txpriv.link_id]; - spin_unlock_bh(&stats->lock); - - ++item->generation; - item->packet_id = cw1200_queue_mk_packet_id(queue->generation, - queue->queue_id, - item->generation, - item - queue->pool); - list_move(&item->head, &queue->queue); - } - spin_unlock_bh(&queue->lock); - - return 0; -} - int cw1200_queue_remove(struct cw1200_queue *queue, u32 packet_id) { int ret = 0; diff --git a/drivers/net/wireless/st/cw1200/queue.h b/drivers/net/wireless/st/cw1200/queue.h index 96ac69ae97de..d46304b58747 100644 --- a/drivers/net/wireless/st/cw1200/queue.h +++ b/drivers/net/wireless/st/cw1200/queue.h @@ -85,7 +85,6 @@ int cw1200_queue_get(struct cw1200_queue *queue, struct ieee80211_tx_info **tx_info, const struct cw1200_txpriv **txpriv); int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id); -int cw1200_queue_requeue_all(struct cw1200_queue *queue); int cw1200_queue_remove(struct cw1200_queue *queue, u32 packet_id); int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packet_id, diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index c705081249d6..b45050243129 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c @@ -233,8 +233,8 @@ static int wl1251_sdio_probe(struct sdio_func *func, } if (wl->irq) { - irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); - ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); + ret = request_irq(wl->irq, wl1251_line_irq, IRQF_NO_AUTOEN, + "wl1251", wl); if (ret < 0) { wl1251_error("request_irq() failed: %d", ret); goto disable; diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index b26d42b4e3cc..ffbf54776330 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1939,7 +1939,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table); static struct platform_driver wl12xx_driver = { .probe = wl12xx_probe, - .remove_new = wl12xx_remove, + .remove = wl12xx_remove, .id_table = wl12xx_id_table, .driver = { .name = "wl12xx_driver", diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 39d8eebb9b6e..4be1110bac88 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -2097,9 +2097,9 @@ MODULE_DEVICE_TABLE(platform, wl18xx_id_table); static struct platform_driver wl18xx_driver = { .probe = wl18xx_probe, - .remove_new = wlcore_remove, + .remove = wlcore_remove, .id_table = wl18xx_id_table, - .driver = { + .driver = { .name = "wl18xx_driver", } }; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 0c77b8524160..986b07bfa0ee 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5789,9 +5789,10 @@ static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw, static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update"); @@ -6052,7 +6053,7 @@ static const struct ieee80211_ops wl1271_ops = { .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, .switch_vif_chanctx = wlcore_op_switch_vif_chanctx, - .sta_rc_update = wlcore_op_sta_rc_update, + .link_sta_rc_update = wlcore_op_sta_rc_update, .sta_statistics = wlcore_op_sta_statistics, .get_expected_throughput = wlcore_op_get_expected_throughput, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 92fb5b8dcdae..a73207bbe5d7 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -323,17 +323,12 @@ static int wl1271_probe(struct sdio_func *func, memset(res, 0x00, sizeof(res)); - res[0].start = irq; - res[0].flags = IORESOURCE_IRQ | - irqd_get_trigger_type(irq_get_irq_data(irq)); - res[0].name = "irq"; - + res[0] = DEFINE_RES_IRQ_NAMED(irq, "irq"); + res[0].flags |= irq_get_trigger_type(irq); if (wakeirq > 0) { - res[1].start = wakeirq; - res[1].flags = IORESOURCE_IRQ | - irqd_get_trigger_type(irq_get_irq_data(wakeirq)); - res[1].name = "wakeirq"; + res[1] = DEFINE_RES_IRQ_NAMED(wakeirq, "wakeirq"); + res[1].flags |= irq_get_trigger_type(wakeirq); num_irqs = 2; } else { num_irqs = 1; diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 3f424f14de4e..347a15544afe 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2442,7 +2442,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) if (!data->started || !link_data->beacon_int) { hrtimer_cancel(&link_data->beacon_timer); - } else if (!hrtimer_is_queued(&link_data->beacon_timer)) { + } else if (!hrtimer_active(&link_data->beacon_timer)) { u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); u32 bcn_int = link_data->beacon_int; u64 until_tbtt = bcn_int - do_div(tsf, bcn_int); @@ -2537,7 +2537,7 @@ static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, info->enable_beacon, info->beacon_int); vp->bcn_en = info->enable_beacon; if (data->started && - !hrtimer_is_queued(&link_data->beacon_timer) && + !hrtimer_active(&link_data->beacon_timer) && info->enable_beacon) { u64 tsf, until_tbtt; u32 bcn_int; @@ -2594,10 +2594,11 @@ static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, static void mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_sta *sta = link_sta->sta; u32 bw = U32_MAX; int link_id; @@ -2607,7 +2608,6 @@ mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, link_id++) { enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; struct ieee80211_bss_conf *vif_conf; - struct ieee80211_link_sta *link_sta; link_sta = rcu_dereference(sta->link[link_id]); @@ -2659,7 +2659,7 @@ static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, hwsim_check_magic(vif); hwsim_set_sta_magic(sta); - mac80211_hwsim_sta_rc_update(hw, vif, sta, 0); + mac80211_hwsim_sta_rc_update(hw, vif, &sta->deflink, 0); if (sta->valid_links) { WARN(hweight16(sta->valid_links) > 1, @@ -3961,7 +3961,7 @@ out: .link_info_changed = mac80211_hwsim_link_info_changed, \ .tx_last_beacon = mac80211_hwsim_tx_last_beacon, \ .sta_notify = mac80211_hwsim_sta_notify, \ - .sta_rc_update = mac80211_hwsim_sta_rc_update, \ + .link_sta_rc_update = mac80211_hwsim_sta_rc_update, \ .conf_tx = mac80211_hwsim_conf_tx, \ .get_survey = mac80211_hwsim_get_survey, \ CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \ |