diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-01-30 06:17:42 +0300 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-01-30 06:17:43 +0300 |
| commit | 303c1a66a22068517793284524dd1d24b7316d1b (patch) | |
| tree | 6610d11e4b386449668edb50dff882d63d08ac02 | |
| parent | 6f1769ec5892ac41d82e820d94dcdc68e904aa99 (diff) | |
| parent | c30e188bd2a886258be5facb970a804d8ef549b5 (diff) | |
| download | linux-303c1a66a22068517793284524dd1d24b7316d1b.tar.xz | |
Merge tag 'wireless-next-2026-01-29' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says:
====================
Another fairly large set of changes, notably:
- cfg80211/mac80211
- most of EPPKE/802.1X over auth frames support
- additional FTM capabilities
- split up drop reasons better, removing generic RX_DROP
- NAN cleanups/fixes
- ath11k:
- support for Channel Frequency Response measurement
- ath12k:
- support for the QCC2072 chipset
- iwlwifi:
- partial NAN support
- UNII-9 support
- some UHR/802.11bn FW APIs
- remove most of MLO/EHT from iwlmvm
(such devices use iwlmld)
- rtw89:
- preparations for RTL8922DE support
* tag 'wireless-next-2026-01-29' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (184 commits)
wifi: iwlegacy: add missing mutex protection in il4965_store_tx_power()
wifi: iwlegacy: add missing mutex protection in il3945_store_measurement()
wifi: mac80211: use u64_stats_t with u64_stats_sync properly
wifi: p54: Fix memory leak in p54_beacon_update()
wifi: cfg80211: treat deprecated INDOOR_SP_AP_OLD control value as LPI mode
wifi: rtw88: sdio: Migrate to use sdio specific shutdown function
wifi: rsi: sdio: Migrate to use sdio specific shutdown function
sdio: Provide a bustype shutdown function
wifi: nl80211/cfg80211: support operating as RSTA in PMSR FTM request
wifi: nl80211/cfg80211: add negotiated burst period to FTM result
wifi: nl80211/cfg80211: clarify periodic FTM parameters for non-EDCA based ranging
wifi: nl80211/cfg80211: add new FTM capabilities
wifi: iwlwifi: rename struct iwl_mcc_allowed_ap_type_cmd::offset_map
wifi: iwlwifi: mvm: Remove link_id from time_events
wifi: iwlwifi: mld: change cluster_id type to u8 array
wifi: iwlwifi: support V13 of iwl_lari_config_change_cmd
wifi: iwlwifi: split bios_value_u32 to separate the header
wifi: iwlwifi: uefi: cache the DSM functions
wifi: iwlwifi: acpi: cache the DSM functions
wifi: iwlwifi: mvm: Cleanup MLO code
...
====================
Link: https://patch.msgid.link/20260129110136.176980-39-johannes@sipsolutions.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
194 files changed, 8869 insertions, 1678 deletions
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml index c089677702cf..0cc1dbf2beef 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml @@ -214,15 +214,6 @@ allOf: - const: wbm2host-tx-completions-ring2 - const: wbm2host-tx-completions-ring1 - const: tcl2host-status-ring - - - if: - properties: - compatible: - contains: - enum: - - qcom,ipq8074-wifi - - qcom,ipq6018-wifi - then: required: - interrupt-names diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 10799772494a..6e5bdc2f0cc8 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -232,6 +232,15 @@ static void sdio_bus_remove(struct device *dev) pm_runtime_put_sync(dev); } +static void sdio_bus_shutdown(struct device *dev) +{ + struct sdio_driver *drv = to_sdio_driver(dev->driver); + struct sdio_func *func = dev_to_sdio_func(dev); + + if (dev->driver && drv->shutdown) + drv->shutdown(func); +} + static const struct dev_pm_ops sdio_bus_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume) SET_RUNTIME_PM_OPS( @@ -248,6 +257,7 @@ static const struct bus_type sdio_bus_type = { .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, .remove = sdio_bus_remove, + .shutdown = sdio_bus_shutdown, .pm = &sdio_bus_pm_ops, }; @@ -261,6 +271,14 @@ void sdio_unregister_bus(void) bus_unregister(&sdio_bus_type); } +static void sdio_legacy_shutdown(struct sdio_func *func) +{ + struct device *dev = &func->dev; + struct device_driver *driver = dev->driver; + + driver->shutdown(dev); +} + /** * __sdio_register_driver - register a function driver * @drv: SDIO function driver @@ -272,6 +290,13 @@ int __sdio_register_driver(struct sdio_driver *drv, struct module *owner) drv->drv.bus = &sdio_bus_type; drv->drv.owner = owner; + /* + * This driver needs updating. Note that driver_register() warns about + * this, so we're not adding another warning here. + */ + if (!drv->shutdown && drv->drv.shutdown) + drv->shutdown = sdio_legacy_shutdown; + return driver_register(&drv->drv); } EXPORT_SYMBOL_GPL(__sdio_register_driver); diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index 659ef134ef16..47dfd39caa89 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -58,3 +58,14 @@ config ATH11K_SPECTRAL Enable ath11k spectral scan support Say Y to enable access to the FFT/spectral data via debugfs. + +config ATH11K_CFR + bool "ath11k channel frequency response support" + depends on ATH11K_DEBUGFS + depends on RELAY + help + Enable ath11k channel frequency response dump support. + This option exposes debugfs nodes that will allow the user + to enable, disable, and dump data. + + Say Y to enable CFR data dump collection via debugfs. diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index d9092414b362..b1435fcf3e1b 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -28,6 +28,7 @@ ath11k-$(CONFIG_THERMAL) += thermal.o ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o ath11k-$(CONFIG_PM) += wow.o ath11k-$(CONFIG_DEV_COREDUMP) += coredump.o +ath11k-$(CONFIG_ATH11K_CFR) += cfr.o obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o ath11k_ahb-y += ahb.o diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c new file mode 100644 index 000000000000..61bf1c0884f7 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/cfr.c @@ -0,0 +1,1023 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/relay.h> +#include "core.h" +#include "debug.h" + +struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar) +{ + if (ar->cfr_enabled) + return &ar->cfr.rx_ring; + + return NULL; +} + +static int ath11k_cfr_calculate_tones_from_dma_hdr(struct ath11k_cfr_dma_hdr *hdr) +{ + u8 bw = FIELD_GET(CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW, hdr->info1); + u8 preamble = FIELD_GET(CFIR_DMA_HDR_INFO1_PREAMBLE_TYPE, hdr->info1); + + switch (preamble) { + case ATH11K_CFR_PREAMBLE_TYPE_LEGACY: + fallthrough; + case ATH11K_CFR_PREAMBLE_TYPE_VHT: + switch (bw) { + case 0: + return TONES_IN_20MHZ; + case 1: /* DUP40/VHT40 */ + return TONES_IN_40MHZ; + case 2: /* DUP80/VHT80 */ + return TONES_IN_80MHZ; + case 3: /* DUP160/VHT160 */ + return TONES_IN_160MHZ; + default: + return TONES_INVALID; + } + case ATH11K_CFR_PREAMBLE_TYPE_HT: + switch (bw) { + case 0: + return TONES_IN_20MHZ; + case 1: + return TONES_IN_40MHZ; + default: + return TONES_INVALID; + } + default: + return TONES_INVALID; + } +} + +void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut) +{ + memset(lut, 0, sizeof(*lut)); +} + +static void ath11k_cfr_rfs_write(struct ath11k *ar, const void *head, + u32 head_len, const void *data, u32 data_len, + const void *tail, int tail_data) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + if (!cfr->rfs_cfr_capture) + return; + + relay_write(cfr->rfs_cfr_capture, head, head_len); + relay_write(cfr->rfs_cfr_capture, data, data_len); + relay_write(cfr->rfs_cfr_capture, tail, tail_data); + relay_flush(cfr->rfs_cfr_capture); +} + +static void ath11k_cfr_free_pending_dbr_events(struct ath11k *ar) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct ath11k_look_up_table *lut; + int i; + + if (!cfr->lut) + return; + + for (i = 0; i < cfr->lut_num; i++) { + lut = &cfr->lut[i]; + if (lut->dbr_recv && !lut->tx_recv && + lut->dbr_tstamp < cfr->last_success_tstamp) { + ath11k_dbring_bufs_replenish(ar, &cfr->rx_ring, lut->buff, + WMI_DIRECT_BUF_CFR); + ath11k_cfr_release_lut_entry(lut); + cfr->flush_dbr_cnt++; + } + } +} + +/** + * ath11k_cfr_correlate_and_relay() - Correlate and relay CFR events + * @ar: Pointer to ath11k structure + * @lut: Lookup table for correlation + * @event_type: Type of event received (TX or DBR) + * + * Correlates WMI_PDEV_DMA_RING_BUF_RELEASE_EVENT (DBR) and + * WMI_PEER_CFR_CAPTURE_EVENT (TX capture) by PPDU ID. If both events + * are present and the PPDU IDs match, returns CORRELATE_STATUS_RELEASE + * to relay thecorrelated data to userspace. Otherwise returns + * CORRELATE_STATUS_HOLD to wait for the other event. + * + * Also checks pending DBR events and clears them when no corresponding TX + * capture event is received for the PPDU. + * + * Return: CORRELATE_STATUS_RELEASE or CORRELATE_STATUS_HOLD + */ + +static enum ath11k_cfr_correlate_status +ath11k_cfr_correlate_and_relay(struct ath11k *ar, + struct ath11k_look_up_table *lut, + u8 event_type) +{ + enum ath11k_cfr_correlate_status status; + struct ath11k_cfr *cfr = &ar->cfr; + u64 diff; + + if (event_type == ATH11K_CORRELATE_TX_EVENT) { + if (lut->tx_recv) + cfr->cfr_dma_aborts++; + cfr->tx_evt_cnt++; + lut->tx_recv = true; + } else if (event_type == ATH11K_CORRELATE_DBR_EVENT) { + cfr->dbr_evt_cnt++; + lut->dbr_recv = true; + } + + if (lut->dbr_recv && lut->tx_recv) { + if (lut->dbr_ppdu_id == lut->tx_ppdu_id) { + /* + * 64-bit counters make wraparound highly improbable, + * wraparound handling is omitted. + */ + cfr->last_success_tstamp = lut->dbr_tstamp; + if (lut->dbr_tstamp > lut->txrx_tstamp) { + diff = lut->dbr_tstamp - lut->txrx_tstamp; + ath11k_dbg(ar->ab, ATH11K_DBG_CFR, + "txrx event -> dbr event delay = %u ms", + jiffies_to_msecs(diff)); + } else if (lut->txrx_tstamp > lut->dbr_tstamp) { + diff = lut->txrx_tstamp - lut->dbr_tstamp; + ath11k_dbg(ar->ab, ATH11K_DBG_CFR, + "dbr event -> txrx event delay = %u ms", + jiffies_to_msecs(diff)); + } + + ath11k_cfr_free_pending_dbr_events(ar); + + cfr->release_cnt++; + status = ATH11K_CORRELATE_STATUS_RELEASE; + } else { + /* + * Discard TXRX event on PPDU ID mismatch because multiple PPDUs + * may share the same DMA address due to ucode aborts. + */ + + ath11k_dbg(ar->ab, ATH11K_DBG_CFR, + "Received dbr event twice for the same lut entry"); + lut->tx_recv = false; + lut->tx_ppdu_id = 0; + cfr->clear_txrx_event++; + cfr->cfr_dma_aborts++; + status = ATH11K_CORRELATE_STATUS_HOLD; + } + } else { + status = ATH11K_CORRELATE_STATUS_HOLD; + } + + return status; +} + +static int ath11k_cfr_process_data(struct ath11k *ar, + struct ath11k_dbring_data *param) +{ + u32 end_magic = ATH11K_CFR_END_MAGIC; + struct ath11k_csi_cfr_header *header; + struct ath11k_cfr_dma_hdr *dma_hdr; + struct ath11k_cfr *cfr = &ar->cfr; + struct ath11k_look_up_table *lut; + struct ath11k_base *ab = ar->ab; + u32 buf_id, tones, length; + u8 num_chains; + int status; + u8 *data; + + data = param->data; + buf_id = param->buf_id; + + if (param->data_sz < sizeof(*dma_hdr)) + return -EINVAL; + + dma_hdr = (struct ath11k_cfr_dma_hdr *)data; + + tones = ath11k_cfr_calculate_tones_from_dma_hdr(dma_hdr); + if (tones == TONES_INVALID) { + ath11k_warn(ar->ab, "Number of tones received is invalid\n"); + return -EINVAL; + } + + num_chains = FIELD_GET(CFIR_DMA_HDR_INFO1_NUM_CHAINS, + dma_hdr->info1); + + length = sizeof(*dma_hdr); + length += tones * (num_chains + 1); + + spin_lock_bh(&cfr->lut_lock); + + if (!cfr->lut) { + spin_unlock_bh(&cfr->lut_lock); + return -EINVAL; + } + + lut = &cfr->lut[buf_id]; + + ath11k_dbg_dump(ab, ATH11K_DBG_CFR_DUMP, "data_from_buf_rel:", "", + data, length); + + lut->buff = param->buff; + lut->data = data; + lut->data_len = length; + lut->dbr_ppdu_id = dma_hdr->phy_ppdu_id; + lut->dbr_tstamp = jiffies; + + memcpy(&lut->hdr, dma_hdr, sizeof(*dma_hdr)); + + header = &lut->header; + header->meta_data.channel_bw = FIELD_GET(CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW, + dma_hdr->info1); + header->meta_data.length = length; + + status = ath11k_cfr_correlate_and_relay(ar, lut, + ATH11K_CORRELATE_DBR_EVENT); + if (status == ATH11K_CORRELATE_STATUS_RELEASE) { + ath11k_dbg(ab, ATH11K_DBG_CFR, + "releasing CFR data to user space"); + ath11k_cfr_rfs_write(ar, &lut->header, + sizeof(struct ath11k_csi_cfr_header), + lut->data, lut->data_len, + &end_magic, sizeof(u32)); + ath11k_cfr_release_lut_entry(lut); + } else if (status == ATH11K_CORRELATE_STATUS_HOLD) { + ath11k_dbg(ab, ATH11K_DBG_CFR, + "tx event is not yet received holding the buf"); + } + + spin_unlock_bh(&cfr->lut_lock); + + return status; +} + +static void ath11k_cfr_fill_hdr_info(struct ath11k *ar, + struct ath11k_csi_cfr_header *header, + struct ath11k_cfr_peer_tx_param *params) +{ + struct ath11k_cfr *cfr; + + cfr = &ar->cfr; + header->cfr_metadata_version = ATH11K_CFR_META_VERSION_4; + header->cfr_data_version = ATH11K_CFR_DATA_VERSION_1; + header->cfr_metadata_len = sizeof(struct cfr_metadata); + header->chip_type = ar->ab->hw_rev; + header->meta_data.status = FIELD_GET(WMI_CFR_PEER_CAPTURE_STATUS, + params->status); + header->meta_data.capture_bw = params->bandwidth; + + /* + * FW reports phymode will always be HE mode. + * Replace it with cached phy mode during peer assoc + */ + header->meta_data.phy_mode = cfr->phymode; + + header->meta_data.prim20_chan = params->primary_20mhz_chan; + header->meta_data.center_freq1 = params->band_center_freq1; + header->meta_data.center_freq2 = params->band_center_freq2; + + /* + * CFR capture is triggered by the ACK of a QoS Null frame: + * - 20 MHz: Legacy ACK + * - 40/80/160 MHz: DUP Legacy ACK + */ + header->meta_data.capture_mode = params->bandwidth ? + ATH11K_CFR_CAPTURE_DUP_LEGACY_ACK : ATH11K_CFR_CAPTURE_LEGACY_ACK; + header->meta_data.capture_type = params->capture_method; + header->meta_data.num_rx_chain = ar->num_rx_chains; + header->meta_data.sts_count = params->spatial_streams; + header->meta_data.timestamp = params->timestamp_us; + ether_addr_copy(header->meta_data.peer_addr, params->peer_mac_addr); + memcpy(header->meta_data.chain_rssi, params->chain_rssi, + sizeof(params->chain_rssi)); + memcpy(header->meta_data.chain_phase, params->chain_phase, + sizeof(params->chain_phase)); + memcpy(header->meta_data.agc_gain, params->agc_gain, + sizeof(params->agc_gain)); +} + +int ath11k_process_cfr_capture_event(struct ath11k_base *ab, + struct ath11k_cfr_peer_tx_param *params) +{ + struct ath11k_look_up_table *lut = NULL; + u32 end_magic = ATH11K_CFR_END_MAGIC; + struct ath11k_csi_cfr_header *header; + struct ath11k_dbring_element *buff; + struct ath11k_cfr *cfr; + dma_addr_t buf_addr; + struct ath11k *ar; + u8 tx_status; + int status; + int i; + + rcu_read_lock(); + ar = ath11k_mac_get_ar_by_vdev_id(ab, params->vdev_id); + if (!ar) { + rcu_read_unlock(); + ath11k_warn(ab, "Failed to get ar for vdev id %d\n", + params->vdev_id); + return -ENOENT; + } + + cfr = &ar->cfr; + rcu_read_unlock(); + + if (WMI_CFR_CAPTURE_STATUS_PEER_PS & params->status) { + ath11k_warn(ab, "CFR capture failed as peer %pM is in powersave", + params->peer_mac_addr); + return -EINVAL; + } + + if (!(WMI_CFR_PEER_CAPTURE_STATUS & params->status)) { + ath11k_warn(ab, "CFR capture failed for the peer : %pM", + params->peer_mac_addr); + cfr->tx_peer_status_cfr_fail++; + return -EINVAL; + } + + tx_status = FIELD_GET(WMI_CFR_FRAME_TX_STATUS, params->status); + if (tx_status != WMI_FRAME_TX_STATUS_OK) { + ath11k_warn(ab, "WMI tx status %d for the peer %pM", + tx_status, params->peer_mac_addr); + cfr->tx_evt_status_cfr_fail++; + return -EINVAL; + } + + buf_addr = (((u64)FIELD_GET(WMI_CFR_CORRELATION_INFO2_BUF_ADDR_HIGH, + params->correlation_info_2)) << 32) | + params->correlation_info_1; + + spin_lock_bh(&cfr->lut_lock); + + if (!cfr->lut) { + spin_unlock_bh(&cfr->lut_lock); + return -EINVAL; + } + + for (i = 0; i < cfr->lut_num; i++) { + struct ath11k_look_up_table *temp = &cfr->lut[i]; + + if (temp->dbr_address == buf_addr) { + lut = &cfr->lut[i]; + break; + } + } + + if (!lut) { + spin_unlock_bh(&cfr->lut_lock); + ath11k_warn(ab, "lut failure to process tx event\n"); + cfr->tx_dbr_lookup_fail++; + return -EINVAL; + } + + lut->tx_ppdu_id = FIELD_GET(WMI_CFR_CORRELATION_INFO2_PPDU_ID, + params->correlation_info_2); + lut->txrx_tstamp = jiffies; + + header = &lut->header; + header->start_magic_num = ATH11K_CFR_START_MAGIC; + header->vendorid = VENDOR_QCA; + header->platform_type = PLATFORM_TYPE_ARM; + + ath11k_cfr_fill_hdr_info(ar, header, params); + + status = ath11k_cfr_correlate_and_relay(ar, lut, + ATH11K_CORRELATE_TX_EVENT); + if (status == ATH11K_CORRELATE_STATUS_RELEASE) { + ath11k_dbg(ab, ATH11K_DBG_CFR, + "Releasing CFR data to user space"); + ath11k_cfr_rfs_write(ar, &lut->header, + sizeof(struct ath11k_csi_cfr_header), + lut->data, lut->data_len, + &end_magic, sizeof(u32)); + buff = lut->buff; + ath11k_cfr_release_lut_entry(lut); + + ath11k_dbring_bufs_replenish(ar, &cfr->rx_ring, buff, + WMI_DIRECT_BUF_CFR); + } else if (status == ATH11K_CORRELATE_STATUS_HOLD) { + ath11k_dbg(ab, ATH11K_DBG_CFR, + "dbr event is not yet received holding buf\n"); + } + + spin_unlock_bh(&cfr->lut_lock); + + return 0; +} + +/* Helper function to check whether the given peer mac address + * is in unassociated peer pool or not. + */ +bool ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar, const u8 *peer_mac) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + int i; + + if (!ar->cfr_enabled) + return false; + + spin_lock_bh(&cfr->lock); + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (!entry->is_valid) + continue; + + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + spin_unlock_bh(&cfr->lock); + return true; + } + } + + spin_unlock_bh(&cfr->lock); + + return false; +} + +void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar, + const u8 *peer_mac) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + int i; + + spin_lock_bh(&cfr->lock); + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (!entry->is_valid) + continue; + + if (ether_addr_equal(peer_mac, entry->peer_mac) && + entry->period == 0) { + memset(entry->peer_mac, 0, ETH_ALEN); + entry->is_valid = false; + cfr->cfr_enabled_peer_cnt--; + break; + } + } + + spin_unlock_bh(&cfr->lock); +} + +void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + spin_lock_bh(&cfr->lock); + + if (arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&cfr->lock); +} + +static enum ath11k_wmi_cfr_capture_bw +ath11k_cfr_bw_to_fw_cfr_bw(enum ath11k_cfr_capture_bw bw) +{ + switch (bw) { + case ATH11K_CFR_CAPTURE_BW_20: + return WMI_PEER_CFR_CAPTURE_BW_20; + case ATH11K_CFR_CAPTURE_BW_40: + return WMI_PEER_CFR_CAPTURE_BW_40; + case ATH11K_CFR_CAPTURE_BW_80: + return WMI_PEER_CFR_CAPTURE_BW_80; + default: + return WMI_PEER_CFR_CAPTURE_BW_MAX; + } +} + +static enum ath11k_wmi_cfr_capture_method +ath11k_cfr_method_to_fw_cfr_method(enum ath11k_cfr_capture_method method) +{ + switch (method) { + case ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME: + return WMI_CFR_CAPTURE_METHOD_NULL_FRAME; + case ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE: + return WMI_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE; + case ATH11K_CFR_CAPTURE_METHOD_PROBE_RESP: + return WMI_CFR_CAPTURE_METHOD_PROBE_RESP; + default: + return WMI_CFR_CAPTURE_METHOD_MAX; + } +} + +int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct wmi_peer_cfr_capture_conf_arg arg; + enum ath11k_wmi_cfr_capture_bw bw; + enum ath11k_wmi_cfr_capture_method method; + int ret = 0; + + if (cfr->cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS && + !arsta->cfr_capture.cfr_enable) { + ath11k_err(ar->ab, "CFR enable peer threshold reached %u\n", + cfr->cfr_enabled_peer_cnt); + return -ENOSPC; + } + + if (params->cfr_enable == arsta->cfr_capture.cfr_enable && + params->cfr_period == arsta->cfr_capture.cfr_period && + params->cfr_method == arsta->cfr_capture.cfr_method && + params->cfr_bw == arsta->cfr_capture.cfr_bw) + return ret; + + if (!params->cfr_enable && !arsta->cfr_capture.cfr_enable) + return ret; + + bw = ath11k_cfr_bw_to_fw_cfr_bw(params->cfr_bw); + if (bw >= WMI_PEER_CFR_CAPTURE_BW_MAX) { + ath11k_warn(ar->ab, "FW doesn't support configured bw %d\n", + params->cfr_bw); + return -EINVAL; + } + + method = ath11k_cfr_method_to_fw_cfr_method(params->cfr_method); + if (method >= WMI_CFR_CAPTURE_METHOD_MAX) { + ath11k_warn(ar->ab, "FW doesn't support configured method %d\n", + params->cfr_method); + return -EINVAL; + } + + arg.request = params->cfr_enable; + arg.periodicity = params->cfr_period; + arg.bw = bw; + arg.method = method; + + ret = ath11k_wmi_peer_set_cfr_capture_conf(ar, arsta->arvif->vdev_id, + peer_mac, &arg); + if (ret) { + ath11k_warn(ar->ab, + "failed to send cfr capture info: vdev_id %u peer %pM: %d\n", + arsta->arvif->vdev_id, peer_mac, ret); + return ret; + } + + spin_lock_bh(&cfr->lock); + + if (params->cfr_enable && + params->cfr_enable != arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt++; + else if (!params->cfr_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&cfr->lock); + + arsta->cfr_capture.cfr_enable = params->cfr_enable; + arsta->cfr_capture.cfr_period = params->cfr_period; + arsta->cfr_capture.cfr_method = params->cfr_method; + arsta->cfr_capture.cfr_bw = params->cfr_bw; + + return ret; +} + +void ath11k_cfr_update_unassoc_pool(struct ath11k *ar, + struct ath11k_per_peer_cfr_capture *params, + u8 *peer_mac) +{ + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + int available_idx = -1; + int i; + + guard(spinlock_bh)(&cfr->lock); + + if (!params->cfr_enable) { + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + memset(entry->peer_mac, 0, ETH_ALEN); + entry->is_valid = false; + cfr->cfr_enabled_peer_cnt--; + break; + } + } + return; + } + + if (cfr->cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS) { + ath11k_info(ar->ab, "Max cfr peer threshold reached\n"); + return; + } + + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + ath11k_info(ar->ab, + "peer entry already present updating params\n"); + entry->period = params->cfr_period; + available_idx = -1; + break; + } + + if (available_idx < 0 && !entry->is_valid) + available_idx = i; + } + + if (available_idx >= 0) { + entry = &cfr->unassoc_pool[available_idx]; + ether_addr_copy(entry->peer_mac, peer_mac); + entry->period = params->cfr_period; + entry->is_valid = true; + cfr->cfr_enabled_peer_cnt++; + } +} + +static ssize_t ath11k_read_file_enable_cfr(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + char buf[32] = {}; + size_t len; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf), "%d\n", ar->cfr_enabled); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath11k_write_file_enable_cfr(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + u32 enable_cfr; + int ret; + + if (kstrtouint_from_user(ubuf, count, 0, &enable_cfr)) + return -EINVAL; + + guard(mutex)(&ar->conf_mutex); + + if (ar->state != ATH11K_STATE_ON) + return -ENETDOWN; + + if (enable_cfr > 1) + return -EINVAL; + + if (ar->cfr_enabled == enable_cfr) + return count; + + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PER_PEER_CFR_ENABLE, + enable_cfr, ar->pdev->pdev_id); + if (ret) { + ath11k_warn(ar->ab, + "Failed to enable/disable per peer cfr %d\n", ret); + return ret; + } + + ar->cfr_enabled = enable_cfr; + + return count; +} + +static const struct file_operations fops_enable_cfr = { + .read = ath11k_read_file_enable_cfr, + .write = ath11k_write_file_enable_cfr, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath11k_write_file_cfr_unassoc(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + char buf[64] = {}; + u8 peer_mac[6]; + u32 cfr_capture_enable; + u32 cfr_capture_period; + int available_idx = -1; + int ret, i; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); + + guard(mutex)(&ar->conf_mutex); + guard(spinlock_bh)(&cfr->lock); + + if (ar->state != ATH11K_STATE_ON) + return -ENETDOWN; + + if (!ar->cfr_enabled) { + ath11k_err(ar->ab, "CFR is not enabled on this pdev %d\n", + ar->pdev_idx); + return -EINVAL; + } + + ret = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %u %u", + &peer_mac[0], &peer_mac[1], &peer_mac[2], &peer_mac[3], + &peer_mac[4], &peer_mac[5], &cfr_capture_enable, + &cfr_capture_period); + + if (ret < 1) + return -EINVAL; + + if (cfr_capture_enable && ret != 8) + return -EINVAL; + + if (!cfr_capture_enable) { + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + memset(entry->peer_mac, 0, ETH_ALEN); + entry->is_valid = false; + cfr->cfr_enabled_peer_cnt--; + } + } + + return count; + } + + if (cfr->cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS) { + ath11k_info(ar->ab, "Max cfr peer threshold reached\n"); + return count; + } + + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + + if (available_idx < 0 && !entry->is_valid) + available_idx = i; + + if (ether_addr_equal(peer_mac, entry->peer_mac)) { + ath11k_info(ar->ab, + "peer entry already present updating params\n"); + entry->period = cfr_capture_period; + return count; + } + } + + if (available_idx >= 0) { + entry = &cfr->unassoc_pool[available_idx]; + ether_addr_copy(entry->peer_mac, peer_mac); + entry->period = cfr_capture_period; + entry->is_valid = true; + cfr->cfr_enabled_peer_cnt++; + } + + return count; +} + +static ssize_t ath11k_read_file_cfr_unassoc(struct file *file, + char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + struct ath11k_cfr *cfr = &ar->cfr; + struct cfr_unassoc_pool_entry *entry; + char buf[512] = {}; + int len = 0, i; + + spin_lock_bh(&cfr->lock); + + for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) { + entry = &cfr->unassoc_pool[i]; + if (entry->is_valid) + len += scnprintf(buf + len, sizeof(buf) - len, + "peer: %pM period: %u\n", + entry->peer_mac, entry->period); + } + + spin_unlock_bh(&cfr->lock); + + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + +static const struct file_operations fops_configure_cfr_unassoc = { + .write = ath11k_write_file_cfr_unassoc, + .read = ath11k_read_file_cfr_unassoc, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static void ath11k_cfr_debug_unregister(struct ath11k *ar) +{ + debugfs_remove(ar->cfr.enable_cfr); + ar->cfr.enable_cfr = NULL; + debugfs_remove(ar->cfr.cfr_unassoc); + ar->cfr.cfr_unassoc = NULL; + + relay_close(ar->cfr.rfs_cfr_capture); + ar->cfr.rfs_cfr_capture = NULL; +} + +static struct dentry *ath11k_cfr_create_buf_file_handler(const char *filename, + struct dentry *parent, + umode_t mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *buf_file; + + buf_file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + *is_global = 1; + return buf_file; +} + +static int ath11k_cfr_remove_buf_file_handler(struct dentry *dentry) +{ + debugfs_remove(dentry); + + return 0; +} + +static const struct rchan_callbacks rfs_cfr_capture_cb = { + .create_buf_file = ath11k_cfr_create_buf_file_handler, + .remove_buf_file = ath11k_cfr_remove_buf_file_handler, +}; + +static void ath11k_cfr_debug_register(struct ath11k *ar) +{ + ar->cfr.rfs_cfr_capture = relay_open("cfr_capture", + ar->debug.debugfs_pdev, + ar->ab->hw_params.cfr_stream_buf_size, + ar->ab->hw_params.cfr_num_stream_bufs, + &rfs_cfr_capture_cb, NULL); + + ar->cfr.enable_cfr = debugfs_create_file("enable_cfr", 0600, + ar->debug.debugfs_pdev, ar, + &fops_enable_cfr); + + ar->cfr.cfr_unassoc = debugfs_create_file("cfr_unassoc", 0600, + ar->debug.debugfs_pdev, ar, + &fops_configure_cfr_unassoc); +} + +void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, + u32 buf_id) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + if (cfr->lut) + cfr->lut[buf_id].dbr_address = paddr; +} + +void ath11k_cfr_update_phymode(struct ath11k *ar, enum wmi_phy_mode phymode) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + cfr->phymode = phymode; +} + +static void ath11k_cfr_ring_free(struct ath11k *ar) +{ + struct ath11k_cfr *cfr = &ar->cfr; + + ath11k_dbring_buf_cleanup(ar, &cfr->rx_ring); + ath11k_dbring_srng_cleanup(ar, &cfr->rx_ring); +} + +static int ath11k_cfr_ring_alloc(struct ath11k *ar, + struct ath11k_dbring_cap *db_cap) +{ + struct ath11k_cfr *cfr = &ar->cfr; + int ret; + + ret = ath11k_dbring_srng_setup(ar, &cfr->rx_ring, + ATH11K_CFR_NUM_RING_ENTRIES, + db_cap->min_elem); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring: %d\n", ret); + return ret; + } + + ath11k_dbring_set_cfg(ar, &cfr->rx_ring, + ATH11K_CFR_NUM_RESP_PER_EVENT, + ATH11K_CFR_EVENT_TIMEOUT_MS, + ath11k_cfr_process_data); + + ret = ath11k_dbring_buf_setup(ar, &cfr->rx_ring, db_cap); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring buffer: %d\n", ret); + goto srng_cleanup; + } + + ret = ath11k_dbring_wmi_cfg_setup(ar, &cfr->rx_ring, WMI_DIRECT_BUF_CFR); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring cfg: %d\n", ret); + goto buffer_cleanup; + } + + return 0; + +buffer_cleanup: + ath11k_dbring_buf_cleanup(ar, &cfr->rx_ring); +srng_cleanup: + ath11k_dbring_srng_cleanup(ar, &cfr->rx_ring); + return ret; +} + +void ath11k_cfr_deinit(struct ath11k_base *ab) +{ + struct ath11k_cfr *cfr; + struct ath11k *ar; + int i; + + if (!test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, ab->wmi_ab.svc_map) || + !ab->hw_params.cfr_support) + return; + + for (i = 0; i < ab->num_radios; i++) { + ar = ab->pdevs[i].ar; + cfr = &ar->cfr; + + if (!cfr->enabled) + continue; + + ath11k_cfr_debug_unregister(ar); + ath11k_cfr_ring_free(ar); + + spin_lock_bh(&cfr->lut_lock); + kfree(cfr->lut); + cfr->lut = NULL; + cfr->enabled = false; + spin_unlock_bh(&cfr->lut_lock); + } +} + +int ath11k_cfr_init(struct ath11k_base *ab) +{ + struct ath11k_dbring_cap db_cap; + struct ath11k_cfr *cfr; + u32 num_lut_entries; + struct ath11k *ar; + int i, ret; + + if (!test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, ab->wmi_ab.svc_map) || + !ab->hw_params.cfr_support) + return 0; + + for (i = 0; i < ab->num_radios; i++) { + ar = ab->pdevs[i].ar; + cfr = &ar->cfr; + + ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx, + WMI_DIRECT_BUF_CFR, &db_cap); + if (ret) + continue; + + idr_init(&cfr->rx_ring.bufs_idr); + spin_lock_init(&cfr->rx_ring.idr_lock); + spin_lock_init(&cfr->lock); + spin_lock_init(&cfr->lut_lock); + + num_lut_entries = min_t(u32, CFR_MAX_LUT_ENTRIES, db_cap.min_elem); + cfr->lut = kcalloc(num_lut_entries, sizeof(*cfr->lut), + GFP_KERNEL); + if (!cfr->lut) { + ret = -ENOMEM; + goto err; + } + + ret = ath11k_cfr_ring_alloc(ar, &db_cap); + if (ret) { + ath11k_warn(ab, "failed to init cfr ring for pdev %d: %d\n", + i, ret); + spin_lock_bh(&cfr->lut_lock); + kfree(cfr->lut); + cfr->lut = NULL; + cfr->enabled = false; + spin_unlock_bh(&cfr->lut_lock); + goto err; + } + + cfr->lut_num = num_lut_entries; + cfr->enabled = true; + + ath11k_cfr_debug_register(ar); + } + + return 0; + +err: + for (i = i - 1; i >= 0; i--) { + ar = ab->pdevs[i].ar; + cfr = &ar->cfr; + + if (!cfr->enabled) + continue; + + ath11k_cfr_debug_unregister(ar); + ath11k_cfr_ring_free(ar); + + spin_lock_bh(&cfr->lut_lock); + kfree(cfr->lut); + cfr->lut = NULL; + cfr->enabled = false; + spin_unlock_bh(&cfr->lut_lock); + } + return ret; +} diff --git a/drivers/net/wireless/ath/ath11k/cfr.h b/drivers/net/wireless/ath/ath11k/cfr.h new file mode 100644 index 000000000000..94fcb706f2ef --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/cfr.h @@ -0,0 +1,308 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef ATH11K_CFR_H +#define ATH11K_CFR_H + +#include "dbring.h" +#include "wmi.h" + +#define ATH11K_CFR_NUM_RESP_PER_EVENT 1 +#define ATH11K_CFR_EVENT_TIMEOUT_MS 1 +#define ATH11K_CFR_NUM_RING_ENTRIES 1 + +#define ATH11K_MAX_CFR_ENABLED_CLIENTS 10 +#define CFR_MAX_LUT_ENTRIES 136 + +#define HOST_MAX_CHAINS 8 + +enum ath11k_cfr_correlate_event_type { + ATH11K_CORRELATE_DBR_EVENT, + ATH11K_CORRELATE_TX_EVENT, +}; + +struct ath11k_sta; +struct ath11k_per_peer_cfr_capture; + +#define ATH11K_CFR_START_MAGIC 0xDEADBEAF +#define ATH11K_CFR_END_MAGIC 0xBEAFDEAD + +#define VENDOR_QCA 0x8cfdf0 +#define PLATFORM_TYPE_ARM 2 + +enum ath11k_cfr_meta_version { + ATH11K_CFR_META_VERSION_NONE, + ATH11K_CFR_META_VERSION_1, + ATH11K_CFR_META_VERSION_2, + ATH11K_CFR_META_VERSION_3, + ATH11K_CFR_META_VERSION_4, + ATH11K_CFR_META_VERSION_MAX = 0xFF, +}; + +enum ath11k_cfr_data_version { + ATH11K_CFR_DATA_VERSION_NONE, + ATH11K_CFR_DATA_VERSION_1, + ATH11K_CFR_DATA_VERSION_MAX = 0xFF, +}; + +enum ath11k_cfr_capture_ack_mode { + ATH11K_CFR_CAPTURE_LEGACY_ACK, + ATH11K_CFR_CAPTURE_DUP_LEGACY_ACK, + ATH11K_CFR_CAPTURE_HT_ACK, + ATH11K_CFR_CAPTURE_VHT_ACK, + + /*Always keep this at last*/ + ATH11K_CFR_CAPTURE_INVALID_ACK +}; + +enum ath11k_cfr_correlate_status { + ATH11K_CORRELATE_STATUS_RELEASE, + ATH11K_CORRELATE_STATUS_HOLD, + ATH11K_CORRELATE_STATUS_ERR, +}; + +enum ath11k_cfr_preamble_type { + ATH11K_CFR_PREAMBLE_TYPE_LEGACY, + ATH11K_CFR_PREAMBLE_TYPE_HT, + ATH11K_CFR_PREAMBLE_TYPE_VHT, +}; + +struct ath11k_cfr_peer_tx_param { + u32 capture_method; + u32 vdev_id; + u8 peer_mac_addr[ETH_ALEN]; + u32 primary_20mhz_chan; + u32 bandwidth; + u32 phy_mode; + u32 band_center_freq1; + u32 band_center_freq2; + u32 spatial_streams; + u32 correlation_info_1; + u32 correlation_info_2; + u32 status; + u32 timestamp_us; + u32 counter; + u32 chain_rssi[WMI_MAX_CHAINS]; + u16 chain_phase[WMI_MAX_CHAINS]; + u32 cfo_measurement; + u8 agc_gain[HOST_MAX_CHAINS]; + u32 rx_start_ts; +}; + +struct cfr_metadata { + u8 peer_addr[ETH_ALEN]; + u8 status; + u8 capture_bw; + u8 channel_bw; + u8 phy_mode; + u16 prim20_chan; + u16 center_freq1; + u16 center_freq2; + u8 capture_mode; + u8 capture_type; + u8 sts_count; + u8 num_rx_chain; + u32 timestamp; + u32 length; + u32 chain_rssi[HOST_MAX_CHAINS]; + u16 chain_phase[HOST_MAX_CHAINS]; + u32 cfo_measurement; + u8 agc_gain[HOST_MAX_CHAINS]; + u32 rx_start_ts; +} __packed; + +struct ath11k_csi_cfr_header { + u32 start_magic_num; + u32 vendorid; + u8 cfr_metadata_version; + u8 cfr_data_version; + u8 chip_type; + u8 platform_type; + u32 cfr_metadata_len; + struct cfr_metadata meta_data; +} __packed; + +#define TONES_IN_20MHZ 256 +#define TONES_IN_40MHZ 512 +#define TONES_IN_80MHZ 1024 +#define TONES_IN_160MHZ 2048 /* 160 MHz isn't supported yet */ +#define TONES_INVALID 0 + +#define CFIR_DMA_HDR_INFO0_TAG GENMASK(7, 0) +#define CFIR_DMA_HDR_INFO0_LEN GENMASK(13, 8) + +#define CFIR_DMA_HDR_INFO1_UPLOAD_DONE GENMASK(0, 0) +#define CFIR_DMA_HDR_INFO1_CAPTURE_TYPE GENMASK(3, 1) +#define CFIR_DMA_HDR_INFO1_PREAMBLE_TYPE GENMASK(5, 4) +#define CFIR_DMA_HDR_INFO1_NSS GENMASK(8, 6) +#define CFIR_DMA_HDR_INFO1_NUM_CHAINS GENMASK(11, 9) +#define CFIR_DMA_HDR_INFO1_UPLOAD_PKT_BW GENMASK(14, 12) +#define CFIR_DMA_HDR_INFO1_SW_PEER_ID_VALID GENMASK(15, 15) + +struct ath11k_cfr_dma_hdr { + u16 info0; + u16 info1; + u16 sw_peer_id; + u16 phy_ppdu_id; +}; + +struct ath11k_look_up_table { + bool dbr_recv; + bool tx_recv; + u8 *data; + u32 data_len; + u16 dbr_ppdu_id; + u16 tx_ppdu_id; + dma_addr_t dbr_address; + struct ath11k_csi_cfr_header header; + struct ath11k_cfr_dma_hdr hdr; + u64 txrx_tstamp; + u64 dbr_tstamp; + u32 header_length; + u32 payload_length; + struct ath11k_dbring_element *buff; +}; + +struct cfr_unassoc_pool_entry { + u8 peer_mac[ETH_ALEN]; + u32 period; + bool is_valid; +}; + +struct ath11k_cfr { + struct ath11k_dbring rx_ring; + /* Protects cfr data */ + spinlock_t lock; + /* Protect for lut entries */ + spinlock_t lut_lock; + struct ath11k_look_up_table *lut; + struct dentry *enable_cfr; + struct dentry *cfr_unassoc; + struct rchan *rfs_cfr_capture; + u8 cfr_enabled_peer_cnt; + u32 lut_num; + u64 tx_evt_cnt; + u64 dbr_evt_cnt; + u64 release_cnt; + u64 tx_peer_status_cfr_fail; + u64 tx_evt_status_cfr_fail; + u64 tx_dbr_lookup_fail; + u64 last_success_tstamp; + u64 flush_dbr_cnt; + u64 clear_txrx_event; + u64 cfr_dma_aborts; + bool enabled; + enum wmi_phy_mode phymode; + struct cfr_unassoc_pool_entry unassoc_pool[ATH11K_MAX_CFR_ENABLED_CLIENTS]; +}; + +enum ath11k_cfr_capture_method { + ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME, + ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE, + ATH11K_CFR_CAPTURE_METHOD_PROBE_RESP, + ATH11K_CFR_CAPTURE_METHOD_MAX, +}; + +enum ath11k_cfr_capture_bw { + ATH11K_CFR_CAPTURE_BW_20, + ATH11K_CFR_CAPTURE_BW_40, + ATH11K_CFR_CAPTURE_BW_80, + ATH11K_CFR_CAPTURE_BW_MAX, +}; + +#ifdef CONFIG_ATH11K_CFR +int ath11k_cfr_init(struct ath11k_base *ab); +void ath11k_cfr_deinit(struct ath11k_base *ab); +void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr, + u32 buf_id); +void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta); +void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar, + const u8 *peer_mac); +bool ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar, + const u8 *peer_mac); +void ath11k_cfr_update_unassoc_pool(struct ath11k *ar, + struct ath11k_per_peer_cfr_capture *params, + u8 *peer_mac); +int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac); +struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar); +void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut); +int ath11k_process_cfr_capture_event(struct ath11k_base *ab, + struct ath11k_cfr_peer_tx_param *params); +void ath11k_cfr_update_phymode(struct ath11k *ar, enum wmi_phy_mode phymode); +#else +static inline void ath11k_cfr_update_phymode(struct ath11k *ar, + enum wmi_phy_mode phymode) +{ +} + +static inline int ath11k_cfr_init(struct ath11k_base *ab) +{ + return 0; +} + +static inline void ath11k_cfr_deinit(struct ath11k_base *ab) +{ +} + +static inline void ath11k_cfr_lut_update_paddr(struct ath11k *ar, + dma_addr_t paddr, u32 buf_id) +{ +} + +static inline void ath11k_cfr_decrement_peer_count(struct ath11k *ar, + struct ath11k_sta *arsta) +{ +} + +static inline void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar, + const u8 *peer_mac) +{ +} + +static inline bool +ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar, const u8 *peer_mac) +{ + return false; +} + +static inline void +ath11k_cfr_update_unassoc_pool(struct ath11k *ar, + struct ath11k_per_peer_cfr_capture *params, + u8 *peer_mac) +{ +} + +static inline int +ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar, + struct ath11k_sta *arsta, + struct ath11k_per_peer_cfr_capture *params, + const u8 *peer_mac) +{ + return 0; +} + +static inline void ath11k_cfr_release_lut_entry(struct ath11k_look_up_table *lut) +{ +} + +static inline +struct ath11k_dbring *ath11k_cfr_get_dbring(struct ath11k *ar) +{ + return NULL; +} + +static inline +int ath11k_process_cfr_capture_event(struct ath11k_base *ab, + struct ath11k_cfr_peer_tx_param *params) +{ + return 0; +} +#endif /* CONFIG_ATH11K_CFR */ +#endif /* ATH11K_CFR_H */ diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 812686173ac8..de84906d1b27 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -100,7 +99,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = false, .fix_l1ss = true, .credit_flow = false, - .max_tx_ring = DP_TCL_NUM_RING_MAX, .hal_params = &ath11k_hw_hal_params_ipq8074, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = true, @@ -126,6 +124,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .smp2p_wow_exit = false, .support_dual_stations = false, .pdev_suspend = false, + .cfr_support = true, + .cfr_num_stream_bufs = 255, + .cfr_stream_buf_size = 8200, }, { .hw_rev = ATH11K_HW_IPQ6018_HW10, @@ -184,7 +185,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = false, .fix_l1ss = true, .credit_flow = false, - .max_tx_ring = DP_TCL_NUM_RING_MAX, .hal_params = &ath11k_hw_hal_params_ipq8074, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = true, @@ -211,6 +211,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = false, .support_dual_stations = false, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "qca6390 hw2.0", @@ -271,7 +274,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = false, .fix_l1ss = true, .credit_flow = true, - .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, .hal_params = &ath11k_hw_hal_params_qca6390, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = false, @@ -301,6 +303,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = true, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "qcn9074 hw1.0", @@ -358,7 +363,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = false, .fix_l1ss = true, .credit_flow = false, - .max_tx_ring = DP_TCL_NUM_RING_MAX, .hal_params = &ath11k_hw_hal_params_ipq8074, .supports_dynamic_smps_6ghz = true, .alloc_cacheable_memory = true, @@ -385,6 +389,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = false, .support_dual_stations = false, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "wcn6855 hw2.0", @@ -445,7 +452,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = true, .fix_l1ss = false, .credit_flow = true, - .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, .hal_params = &ath11k_hw_hal_params_qca6390, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = false, @@ -475,6 +481,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = true, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "wcn6855 hw2.1", @@ -533,7 +542,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = true, .fix_l1ss = false, .credit_flow = true, - .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, .hal_params = &ath11k_hw_hal_params_qca6390, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = false, @@ -563,6 +571,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = true, .pdev_suspend = false, + .cfr_support = true, + .cfr_num_stream_bufs = 255, + .cfr_stream_buf_size = 8200, }, { .name = "wcn6750 hw1.0", @@ -619,7 +630,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = true, .fix_l1ss = false, .credit_flow = true, - .max_tx_ring = DP_TCL_NUM_RING_MAX, .hal_params = &ath11k_hw_hal_params_wcn6750, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = false, @@ -646,6 +656,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = false, .pdev_suspend = true, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .hw_rev = ATH11K_HW_IPQ5018_HW10, @@ -662,7 +675,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074, .ring_mask = &ath11k_hw_ring_mask_ipq8074, .credit_flow = false, - .max_tx_ring = 1, .spectral = { .fft_sz = 2, .fft_pad_sz = 0, @@ -698,7 +710,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = false, .idle_ps = false, .supports_suspend = false, - .hal_params = &ath11k_hw_hal_params_ipq8074, + .hal_params = &ath11k_hw_hal_params_ipq5018, .single_pdev_only = false, .coldboot_cal_mm = true, .coldboot_cal_ftm = true, @@ -729,6 +741,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = false, .support_dual_stations = false, .pdev_suspend = false, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "qca2066 hw2.1", @@ -789,7 +804,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = true, .fix_l1ss = false, .credit_flow = true, - .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, .hal_params = &ath11k_hw_hal_params_qca6390, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = false, @@ -818,6 +832,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .smp2p_wow_exit = false, .support_fw_mac_sequence = true, .support_dual_stations = true, + .cfr_support = false, + .cfr_num_stream_bufs = 0, + .cfr_stream_buf_size = 0, }, { .name = "qca6698aq hw2.1", @@ -876,7 +893,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_regdb = true, .fix_l1ss = false, .credit_flow = true, - .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390, .hal_params = &ath11k_hw_hal_params_qca6390, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = false, @@ -906,6 +922,9 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .support_fw_mac_sequence = true, .support_dual_stations = true, .pdev_suspend = false, + .cfr_support = true, + .cfr_num_stream_bufs = 255, + .cfr_stream_buf_size = 8200, }, }; @@ -994,6 +1013,34 @@ static const struct dmi_system_id ath11k_pm_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "21F9"), }, }, + { + .driver_data = (void *)ATH11K_PM_WOW, + .matches = { /* Z13 G1 */ + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21D2"), + }, + }, + { + .driver_data = (void *)ATH11K_PM_WOW, + .matches = { /* Z13 G1 */ + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21D3"), + }, + }, + { + .driver_data = (void *)ATH11K_PM_WOW, + .matches = { /* Z16 G1 */ + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21D4"), + }, + }, + { + .driver_data = (void *)ATH11K_PM_WOW, + .matches = { /* Z16 G1 */ + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21D5"), + }, + }, {} }; @@ -1987,8 +2034,16 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab) goto err_thermal_unregister; } + ret = ath11k_cfr_init(ab); + if (ret) { + ath11k_err(ab, "failed to init cfr %d\n", ret); + goto err_spectral_unregister; + } + return 0; +err_spectral_unregister: + ath11k_spectral_deinit(ab); err_thermal_unregister: ath11k_thermal_unregister(ab); err_mac_unregister: @@ -2038,6 +2093,7 @@ static void ath11k_core_pdev_suspend_target(struct ath11k_base *ab) static void ath11k_core_pdev_destroy(struct ath11k_base *ab) { + ath11k_cfr_deinit(ab); ath11k_spectral_deinit(ab); ath11k_thermal_unregister(ab); ath11k_mac_unregister(ab); @@ -2250,6 +2306,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab) mutex_lock(&ab->core_lock); ath11k_thermal_unregister(ab); ath11k_dp_pdev_free(ab); + ath11k_cfr_deinit(ab); ath11k_spectral_deinit(ab); ath11k_ce_cleanup_pipes(ab); ath11k_wmi_detach(ab); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index e8780b05ce11..3f41e6569a78 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH11K_CORE_H @@ -35,6 +35,7 @@ #include "wow.h" #include "fw.h" #include "coredump.h" +#include "cfr.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -531,6 +532,13 @@ struct ath11k_per_ppdu_tx_stats { DECLARE_EWMA(avg_rssi, 10, 8) +struct ath11k_per_peer_cfr_capture { + enum ath11k_cfr_capture_method cfr_method; + enum ath11k_cfr_capture_bw cfr_bw; + u32 cfr_enable; + u32 cfr_period; +}; + struct ath11k_sta { struct ath11k_vif *arvif; @@ -571,6 +579,10 @@ struct ath11k_sta { bool peer_current_ps_valid; u32 bw_prev; + +#ifdef CONFIG_ATH11K_CFR + struct ath11k_per_peer_cfr_capture cfr_capture; +#endif }; #define ATH11K_MIN_5G_FREQ 4150 @@ -795,6 +807,11 @@ struct ath11k { bool ps_state_enable; bool ps_timekeeper_enable; s8 max_allowed_tx_power; + +#ifdef CONFIG_ATH11K_CFR + struct ath11k_cfr cfr; +#endif + bool cfr_enabled; }; struct ath11k_band_cap { diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index 520d8b8662a2..d6994ce6ebff 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -37,10 +36,10 @@ static void ath11k_dbring_fill_magic_value(struct ath11k *ar, memset32(buffer, ATH11K_DB_MAGIC_VALUE, size); } -static int ath11k_dbring_bufs_replenish(struct ath11k *ar, - struct ath11k_dbring *ring, - struct ath11k_dbring_element *buff, - enum wmi_direct_buffer_module id) +int ath11k_dbring_bufs_replenish(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_element *buff, + enum wmi_direct_buffer_module id) { struct ath11k_base *ab = ar->ab; struct hal_srng *srng; @@ -80,6 +79,9 @@ static int ath11k_dbring_bufs_replenish(struct ath11k *ar, goto err_idr_remove; } + if (id == WMI_DIRECT_BUF_CFR) + ath11k_cfr_lut_update_paddr(ar, paddr, buf_id); + buff->paddr = paddr; cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, ar->pdev_idx) | @@ -155,12 +157,11 @@ int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, enum wmi_direct_buffer_module id) { struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {}; - int ret; + int ret, i; if (id >= WMI_DIRECT_BUF_MAX) return -EINVAL; - param.pdev_id = DP_SW2HW_MACID(ring->pdev_id); param.module_id = id; param.base_paddr_lo = lower_32_bits(ring->refill_srng.paddr); param.base_paddr_hi = upper_32_bits(ring->refill_srng.paddr); @@ -173,10 +174,23 @@ int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, param.num_resp_per_event = ring->num_resp_per_event; param.event_timeout_ms = ring->event_timeout_ms; - ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m); - if (ret) { - ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); - return ret; + /* For single pdev, 2GHz and 5GHz use one DBR. */ + if (ar->ab->hw_params.single_pdev_only) { + for (i = 0; i < ar->ab->target_pdev_count; i++) { + param.pdev_id = ar->ab->target_pdev_ids[i].pdev_id; + ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); + return ret; + } + } + } else { + param.pdev_id = DP_SW2HW_MACID(ring->pdev_id); + ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); + return ret; + } } return 0; @@ -281,10 +295,15 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, int size; dma_addr_t paddr; int ret = 0; + int status; pdev_idx = ev->fixed.pdev_id; module_id = ev->fixed.module_id; + if (ab->hw_params.single_pdev_only && + pdev_idx < ab->target_pdev_count) + pdev_idx = 0; + if (pdev_idx >= ab->num_radios) { ath11k_warn(ab, "Invalid pdev id %d\n", pdev_idx); return -EINVAL; @@ -310,6 +329,9 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, case WMI_DIRECT_BUF_SPECTRAL: ring = ath11k_spectral_get_dbring(ar); break; + case WMI_DIRECT_BUF_CFR: + ring = ath11k_cfr_get_dbring(ar); + break; default: ring = NULL; ath11k_warn(ab, "Recv dma buffer release ev on unsupp module %d\n", @@ -360,8 +382,12 @@ int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, handler_data.data = PTR_ALIGN(vaddr_unalign, ring->buf_align); handler_data.data_sz = ring->buf_sz; + handler_data.buff = buff; + handler_data.buf_id = buf_id; - ring->handler(ar, &handler_data); + status = ring->handler(ar, &handler_data); + if (status == ATH11K_CORRELATE_STATUS_HOLD) + continue; } buff->paddr = 0; diff --git a/drivers/net/wireless/ath/ath11k/dbring.h b/drivers/net/wireless/ath/ath11k/dbring.h index 2f93b78a50df..e5f244dfa963 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.h +++ b/drivers/net/wireless/ath/ath11k/dbring.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH11K_DBRING_H @@ -21,6 +21,8 @@ struct ath11k_dbring_data { void *data; u32 data_sz; struct wmi_dma_buf_release_meta_data meta; + struct ath11k_dbring_element *buff; + u32 buf_id; }; struct ath11k_dbring_buf_release_event { @@ -61,6 +63,10 @@ int ath11k_dbring_set_cfg(struct ath11k *ar, u32 event_timeout_ms, int (*handler)(struct ath11k *, struct ath11k_dbring_data *)); +int ath11k_dbring_bufs_replenish(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_element *buff, + enum wmi_direct_buffer_module id); int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, struct ath11k_dbring *ring, enum wmi_direct_buffer_module id); diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index cc8934d15697..aaa0034527a5 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _ATH11K_DEBUG_H_ @@ -27,6 +27,8 @@ enum ath11k_debug_mask { ATH11K_DBG_DP_TX = 0x00002000, ATH11K_DBG_DP_RX = 0x00004000, ATH11K_DBG_CE = 0x00008000, + ATH11K_DBG_CFR = 0x00010000, + ATH11K_DBG_CFR_DUMP = 0x00020000, }; static inline const char *ath11k_dbg_str(enum ath11k_debug_mask mask) @@ -64,6 +66,10 @@ static inline const char *ath11k_dbg_str(enum ath11k_debug_mask mask) return "dp_rx"; case ATH11K_DBG_CE: return "ce"; + case ATH11K_DBG_CFR: + return "cfr"; + case ATH11K_DBG_CFR_DUMP: + return "cfr_dump"; /* no default handler to allow compiler to check that the * enum is fully handled diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 977f945b6e66..50f344803e8f 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -707,7 +707,7 @@ static ssize_t ath11k_debugfs_dump_soc_dp_stats(struct file *file, len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n"); len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n"); - for (i = 0; i < ab->hw_params.max_tx_ring; i++) + for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) len += scnprintf(buf + len, size - len, "ring%d: %u\n", i, soc_stats->tx_err.desc_na[i]); diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index d89d0f28d890..621a8a8df4b8 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ @@ -240,6 +239,140 @@ static const struct file_operations fops_tx_stats = { .llseek = default_llseek, }; +#ifdef CONFIG_ATH11K_CFR +static ssize_t ath11k_dbg_sta_write_cfr_capture(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + struct ath11k *ar = arsta->arvif->ar; + struct ath11k_cfr *cfr = &ar->cfr; + struct wmi_peer_cfr_capture_conf_arg arg; + u32 cfr_capture_enable = 0, cfr_capture_bw = 0; + u32 cfr_capture_method = 0, cfr_capture_period = 0; + char buf[64] = {}; + int ret; + + simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + + guard(mutex)(&ar->conf_mutex); + + if (ar->state != ATH11K_STATE_ON) + return -ENETDOWN; + + if (!ar->cfr_enabled) + return -EINVAL; + + ret = sscanf(buf, "%u %u %u %u", &cfr_capture_enable, &cfr_capture_bw, + &cfr_capture_period, &cfr_capture_method); + + if (ret < 1 || (cfr_capture_enable && ret != 4)) + return -EINVAL; + + if (cfr_capture_enable == arsta->cfr_capture.cfr_enable && + (cfr_capture_period && + cfr_capture_period == arsta->cfr_capture.cfr_period) && + cfr_capture_bw == arsta->cfr_capture.cfr_bw && + cfr_capture_method == arsta->cfr_capture.cfr_method) + return count; + + if (!cfr_capture_enable && + cfr_capture_enable == arsta->cfr_capture.cfr_enable) + return count; + + if (cfr_capture_enable > WMI_PEER_CFR_CAPTURE_ENABLE || + cfr_capture_bw > WMI_PEER_CFR_CAPTURE_BW_80 || + cfr_capture_method > ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE || + cfr_capture_period > WMI_PEER_CFR_PERIODICITY_MAX) + return -EINVAL; + + /* Target expects cfr period in multiple of 10 */ + if (cfr_capture_period % 10) { + ath11k_err(ar->ab, "periodicity should be 10x\n"); + return -EINVAL; + } + + if (ar->cfr.cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS && + !arsta->cfr_capture.cfr_enable) { + ath11k_err(ar->ab, "CFR enable peer threshold reached %u\n", + ar->cfr.cfr_enabled_peer_cnt); + return -EINVAL; + } + + if (!cfr_capture_enable) { + cfr_capture_bw = arsta->cfr_capture.cfr_bw; + cfr_capture_period = arsta->cfr_capture.cfr_period; + cfr_capture_method = arsta->cfr_capture.cfr_method; + } + + arg.request = cfr_capture_enable; + arg.periodicity = cfr_capture_period; + arg.bw = cfr_capture_bw; + arg.method = cfr_capture_method; + + ret = ath11k_wmi_peer_set_cfr_capture_conf(ar, arsta->arvif->vdev_id, + sta->addr, &arg); + if (ret) { + ath11k_warn(ar->ab, + "failed to send cfr capture info: vdev_id %u peer %pM: %d\n", + arsta->arvif->vdev_id, sta->addr, ret); + return ret; + } + + spin_lock_bh(&ar->cfr.lock); + + if (cfr_capture_enable && + cfr_capture_enable != arsta->cfr_capture.cfr_enable) + cfr->cfr_enabled_peer_cnt++; + else if (!cfr_capture_enable) + cfr->cfr_enabled_peer_cnt--; + + spin_unlock_bh(&ar->cfr.lock); + + arsta->cfr_capture.cfr_enable = cfr_capture_enable; + arsta->cfr_capture.cfr_period = cfr_capture_period; + arsta->cfr_capture.cfr_bw = cfr_capture_bw; + arsta->cfr_capture.cfr_method = cfr_capture_method; + + return count; +} + +static ssize_t ath11k_dbg_sta_read_cfr_capture(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + struct ath11k *ar = arsta->arvif->ar; + char buf[512] = {}; + int len = 0; + + mutex_lock(&ar->conf_mutex); + + len += scnprintf(buf + len, sizeof(buf) - len, "cfr_enabled = %d\n", + arsta->cfr_capture.cfr_enable); + len += scnprintf(buf + len, sizeof(buf) - len, "bandwidth = %d\n", + arsta->cfr_capture.cfr_bw); + len += scnprintf(buf + len, sizeof(buf) - len, "period = %d\n", + arsta->cfr_capture.cfr_period); + len += scnprintf(buf + len, sizeof(buf) - len, "cfr_method = %d\n", + arsta->cfr_capture.cfr_method); + + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_peer_cfr_capture = { + .write = ath11k_dbg_sta_write_cfr_capture, + .read = ath11k_dbg_sta_read_cfr_capture, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; +#endif /* CONFIG_ATH11K_CFR */ + static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -877,6 +1010,13 @@ void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vi debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta, &fops_htt_peer_stats_reset); +#ifdef CONFIG_ATH11K_CFR + if (test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, + ar->ab->wmi_ab.svc_map)) + debugfs_create_file("cfr_capture", 0600, dir, sta, + &fops_peer_cfr_capture); +#endif/* CONFIG_ATH11K_CFR */ + debugfs_create_file("peer_ps_state", 0400, dir, sta, &fops_peer_ps_state); diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 56b1a657e0b0..c940de285276 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -344,7 +344,7 @@ void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab) if (!ab->hw_params.supports_shadow_regs) return; - for (i = 0; i < ab->hw_params.max_tx_ring; i++) + for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) ath11k_dp_shadow_stop_timer(ab, &ab->dp.tx_ring_timer[i]); ath11k_dp_shadow_stop_timer(ab, &ab->dp.reo_cmd_timer); @@ -359,7 +359,7 @@ static void ath11k_dp_srng_common_cleanup(struct ath11k_base *ab) ath11k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring); ath11k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring); ath11k_dp_srng_cleanup(ab, &dp->tcl_status_ring); - for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) { ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_data_ring); ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_comp_ring); } @@ -400,7 +400,7 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab) goto err; } - for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) { tcl_num = ab->hw_params.hal_params->tcl2wbm_rbm_map[i].tcl_ring_num; wbm_num = ab->hw_params.hal_params->tcl2wbm_rbm_map[i].wbm_ring_num; @@ -782,7 +782,7 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, int i, j; int tot_work_done = 0; - for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) { if (BIT(ab->hw_params.hal_params->tcl2wbm_rbm_map[i].wbm_ring_num) & ab->hw_params.ring_mask->tx[grp_id]) ath11k_dp_tx_completion_handler(ab, i); @@ -1035,7 +1035,7 @@ void ath11k_dp_free(struct ath11k_base *ab) ath11k_dp_reo_cmd_list_cleanup(ab); - for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) { spin_lock_bh(&dp->tx_ring[i].tx_idr_lock); idr_for_each(&dp->tx_ring[i].txbuf_idr, ath11k_dp_tx_pending_cleanup, ab); @@ -1086,7 +1086,7 @@ int ath11k_dp_alloc(struct ath11k_base *ab) size = sizeof(struct hal_wbm_release_ring) * DP_TX_COMP_RING_SIZE; - for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) { idr_init(&dp->tx_ring[i].txbuf_idr); spin_lock_init(&dp->tx_ring[i].tx_idr_lock); dp->tx_ring[i].tcl_data_ring_id = i; diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index 7a55afd33be8..1bd513f68a3c 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -199,7 +199,6 @@ struct ath11k_pdev_dp { #define DP_BA_WIN_SZ_MAX 256 #define DP_TCL_NUM_RING_MAX 3 -#define DP_TCL_NUM_RING_MAX_QCA6390 1 #define DP_IDLE_SCATTER_BUFS_MAX 16 diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 562aba66582f..86e1e6c27b36 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -91,6 +91,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, struct hal_srng *tcl_ring; struct ieee80211_hdr *hdr = (void *)skb->data; struct dp_tx_ring *tx_ring; + size_t num_tx_rings = ab->hw_params.hal_params->num_tx_rings; void *hal_tcl_desc; u8 pool_id; u8 hal_ring_id; @@ -113,7 +114,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, tcl_ring_sel: tcl_ring_retry = false; - ti.ring_id = ring_selector % ab->hw_params.max_tx_ring; + ti.ring_id = ring_selector % num_tx_rings; ti.rbm_id = ab->hw_params.hal_params->tcl2wbm_rbm_map[ti.ring_id].rbm_id; ring_map |= BIT(ti.ring_id); @@ -126,7 +127,7 @@ tcl_ring_sel: spin_unlock_bh(&tx_ring->tx_idr_lock); if (unlikely(ret < 0)) { - if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1) || + if (ring_map == (BIT(num_tx_rings) - 1) || !ab->hw_params.tcl_ring_retry) { atomic_inc(&ab->soc_stats.tx_err.misc_fail); return -ENOSPC; @@ -244,8 +245,8 @@ tcl_ring_sel: * checking this ring earlier for each pkt tx. * Restart ring selection if some rings are not checked yet. */ - if (unlikely(ring_map != (BIT(ab->hw_params.max_tx_ring)) - 1) && - ab->hw_params.tcl_ring_retry && ab->hw_params.max_tx_ring > 1) { + if (unlikely(ring_map != (BIT(num_tx_rings)) - 1) && + ab->hw_params.tcl_ring_retry && num_tx_rings > 1) { tcl_ring_retry = true; ring_selector++; } diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 0c797b8d0a27..e821e5a62c1c 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/dma-mapping.h> @@ -184,7 +183,7 @@ static const struct hal_srng_config hw_srng_config_template[] = { }, { /* RXDMA DIR BUF */ .start_ring_id = HAL_SRNG_RING_ID_RXDMA_DIR_BUF, - .max_rings = 1, + .max_rings = 2, .entry_size = 8 >> 2, /* TODO: Define the struct */ .lmac_ring = true, .ring_dir = HAL_SRNG_DIR_SRC, diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index caa6dc12a790..d19c4b372a2a 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -2707,6 +2707,14 @@ const struct ath11k_hw_regs wcn6750_regs = { .hal_reo1_misc_ctl = 0x000005d8, }; +static const struct ath11k_hw_tcl2wbm_rbm_map ath11k_hw_tcl2wbm_rbm_map_ipq5018[] = { + { + .tcl_ring_num = 0, + .wbm_ring_num = 0, + .rbm_id = HAL_RX_BUF_RBM_SW0_BM, + }, +}; + static const struct ath11k_hw_tcl2wbm_rbm_map ath11k_hw_tcl2wbm_rbm_map_ipq8074[] = { { .tcl_ring_num = 0, @@ -2822,19 +2830,28 @@ const struct ath11k_hw_regs ipq5018_regs = { .hal_wbm1_release_ring_base_lsb = 0x0000097c, }; +const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq5018 = { + .rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM, + .tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_ipq5018, + .num_tx_rings = ARRAY_SIZE(ath11k_hw_tcl2wbm_rbm_map_ipq5018), +}; + const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = { .rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM, .tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_ipq8074, + .num_tx_rings = ARRAY_SIZE(ath11k_hw_tcl2wbm_rbm_map_ipq8074), }; const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390 = { .rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM, - .tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_ipq8074, + .tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_ipq5018, + .num_tx_rings = ARRAY_SIZE(ath11k_hw_tcl2wbm_rbm_map_ipq5018), }; const struct ath11k_hw_hal_params ath11k_hw_hal_params_wcn6750 = { .rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM, .tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_wcn6750, + .num_tx_rings = ARRAY_SIZE(ath11k_hw_tcl2wbm_rbm_map_wcn6750), }; static const struct cfg80211_sar_freq_ranges ath11k_hw_sar_freq_ranges_wcn6855[] = { diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 52d9f4c13b13..4996536fbd14 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH11K_HW_H @@ -134,6 +134,7 @@ struct ath11k_hw_tcl2wbm_rbm_map { struct ath11k_hw_hal_params { enum hal_rx_buf_return_buf_manager rx_buf_rbm; const struct ath11k_hw_tcl2wbm_rbm_map *tcl2wbm_rbm_map; + size_t num_tx_rings; }; struct ath11k_hw_params { @@ -198,7 +199,6 @@ struct ath11k_hw_params { bool supports_regdb; bool fix_l1ss; bool credit_flow; - u8 max_tx_ring; const struct ath11k_hw_hal_params *hal_params; bool supports_dynamic_smps_6ghz; bool alloc_cacheable_memory; @@ -228,6 +228,9 @@ struct ath11k_hw_params { bool support_fw_mac_sequence; bool support_dual_stations; bool pdev_suspend; + bool cfr_support; + u32 cfr_num_stream_bufs; + u32 cfr_stream_buf_size; }; struct ath11k_hw_ops { @@ -291,6 +294,7 @@ extern const struct ce_ie_addr ath11k_ce_ie_addr_ipq5018; extern const struct ce_remap ath11k_ce_remap_ipq5018; +extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq5018; extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074; extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390; extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_wcn6750; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 3276fe443502..4dfd08b58416 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2911,6 +2911,8 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar, arg->peer_phymode = phymode; WARN_ON(phymode == MODE_UNKNOWN); + + ath11k_cfr_update_phymode(ar, phymode); } static void ath11k_peer_assoc_prepare(struct ath11k *ar, @@ -6186,6 +6188,8 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, dma_addr_t paddr; int buf_id; int ret; + bool tx_params_valid = false; + bool peer_in_unassoc_pool; ATH11K_SKB_CB(skb)->ar = ar; @@ -6224,7 +6228,18 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, ATH11K_SKB_CB(skb)->paddr = paddr; - ret = ath11k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb); + peer_in_unassoc_pool = ath11k_cfr_peer_is_in_cfr_unassoc_pool(ar, hdr->addr1); + + if (ar->cfr_enabled && + ieee80211_is_probe_resp(hdr->frame_control) && + peer_in_unassoc_pool) + tx_params_valid = true; + + if (peer_in_unassoc_pool) + ath11k_cfr_update_unassoc_pool_entry(ar, hdr->addr1); + + ret = ath11k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb, + tx_params_valid); if (ret) { ath11k_warn(ar->ab, "failed to send mgmt frame: %d\n", ret); goto err_unmap_buf; @@ -7392,7 +7407,7 @@ err_vdev_del: idr_for_each(&ar->txmgmt_idr, ath11k_mac_vif_txmgmt_idr_remove, vif); - for (i = 0; i < ab->hw_params.max_tx_ring; i++) { + for (i = 0; i < ab->hw_params.hal_params->num_tx_rings; i++) { spin_lock_bh(&ab->dp.tx_ring[i].tx_idr_lock); idr_for_each(&ab->dp.tx_ring[i].txbuf_idr, ath11k_mac_vif_unref, vif); @@ -9979,6 +9994,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, } spin_unlock_bh(&ar->ab->base_lock); mutex_unlock(&ar->ab->tbl_mtx_lock); + + ath11k_cfr_decrement_peer_count(ar, arsta); } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP || @@ -10640,7 +10657,7 @@ static int __ath11k_mac_register(struct ath11k *ar) if (!ab->hw_params.supports_monitor) /* There's a race between calling ieee80211_register_hw() * and here where the monitor mode is enabled for a little - * while. But that time is so short and in practise it make + * while. But that time is so short and in practice it doesn't make * a difference in real life. */ ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index d62a2014315a..49b79648752c 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/rtnetlink.h> @@ -926,8 +926,11 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, */ if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, - (char *)reg_info->alpha2, 2)) - goto retfail; + (char *)reg_info->alpha2, 2) && + power_type == IEEE80211_REG_UNSET_AP) { + ath11k_reg_reset_info(reg_info); + return 0; + } /* Intersect new rules with default regd if a new country setting was * requested, i.e a default regd was already set during initialization diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 110035dae8a6..451cc4c719ae 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -651,11 +651,12 @@ static u32 ath11k_wmi_mgmt_get_freq(struct ath11k *ar, } int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, - struct sk_buff *frame) + struct sk_buff *frame, bool tx_params_valid) { struct ath11k_pdev_wmi *wmi = ar->wmi; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(frame); struct wmi_mgmt_send_cmd *cmd; + struct wmi_mgmt_send_params *params; struct wmi_tlv *frame_tlv; struct sk_buff *skb; u32 buf_len; @@ -665,6 +666,8 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, frame->len : WMI_MGMT_SEND_DOWNLD_LEN; len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4); + if (tx_params_valid) + len += sizeof(*params); skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) @@ -680,7 +683,7 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, cmd->paddr_hi = upper_32_bits(ATH11K_SKB_CB(frame)->paddr); cmd->frame_len = frame->len; cmd->buf_len = buf_len; - cmd->tx_params_valid = 0; + cmd->tx_params_valid = !!tx_params_valid; frame_tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd)); frame_tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | @@ -690,6 +693,15 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, ath11k_ce_byte_swap(frame_tlv->value, buf_len); + if (tx_params_valid) { + params = + (struct wmi_mgmt_send_params *)(skb->data + (len - sizeof(*params))); + params->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TX_SEND_PARAMS) | + FIELD_PREP(WMI_TLV_LEN, + sizeof(*params) - TLV_HDR_SIZE); + params->tx_params_dword1 |= WMI_TX_PARAMS_DWORD1_CFR_CAPTURE; + } + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_MGMT_TX_SEND_CMDID); if (ret) { ath11k_warn(ar->ab, @@ -3941,6 +3953,47 @@ int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar, u32 vdev_id, return 0; } +int ath11k_wmi_peer_set_cfr_capture_conf(struct ath11k *ar, + u32 vdev_id, const u8 *mac_addr, + struct wmi_peer_cfr_capture_conf_arg *arg) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_peer_cfr_capture_cmd_fixed_param *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_peer_cfr_capture_cmd_fixed_param *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_PEER_CFR_CAPTURE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + memcpy(&cmd->mac_addr, mac_addr, ETH_ALEN); + cmd->request = arg->request; + cmd->vdev_id = vdev_id; + cmd->periodicity = arg->periodicity; + cmd->bandwidth = arg->bw; + cmd->capture_method = arg->method; + + ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_PEER_CFR_CAPTURE_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "WMI vdev %d failed to send peer cfr capture cmd: %d\n", + vdev_id, ret); + dev_kfree_skb(skb); + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI peer CFR capture cmd req %u id %u period %u bw %u mode %u\n", + arg->request, vdev_id, arg->periodicity, + arg->bw, arg->method); + + return ret; +} + int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, struct sk_buff *tmpl) { @@ -8752,6 +8805,93 @@ out: kfree(tb); } +static void ath11k_wmi_tlv_cfr_capture_event_fixed_param(const void *ptr, + void *data) +{ + struct ath11k_cfr_peer_tx_param *tx_params = data; + const struct ath11k_wmi_cfr_peer_tx_event_param *params = ptr; + + tx_params->capture_method = params->capture_method; + tx_params->vdev_id = params->vdev_id; + ether_addr_copy(tx_params->peer_mac_addr, params->mac_addr.addr); + tx_params->primary_20mhz_chan = params->chan_mhz; + tx_params->bandwidth = params->bandwidth; + tx_params->phy_mode = params->phy_mode; + tx_params->band_center_freq1 = params->band_center_freq1; + tx_params->band_center_freq2 = params->band_center_freq2; + tx_params->spatial_streams = params->sts_count; + tx_params->correlation_info_1 = params->correlation_info_1; + tx_params->correlation_info_2 = params->correlation_info_2; + tx_params->status = params->status; + tx_params->timestamp_us = params->timestamp_us; + tx_params->counter = params->counter; + tx_params->rx_start_ts = params->rx_start_ts; + + memcpy(tx_params->chain_rssi, params->chain_rssi, + sizeof(tx_params->chain_rssi)); + + if (WMI_CFR_CFO_MEASUREMENT_VALID & params->cfo_measurement) + tx_params->cfo_measurement = FIELD_GET(WMI_CFR_CFO_MEASUREMENT_RAW_DATA, + params->cfo_measurement); +} + +static void ath11k_wmi_tlv_cfr_capture_phase_fixed_param(const void *ptr, + void *data) +{ + struct ath11k_cfr_peer_tx_param *tx_params = data; + const struct ath11k_wmi_cfr_peer_tx_event_phase_param *params = ptr; + int i; + + for (i = 0; i < WMI_MAX_CHAINS; i++) { + tx_params->chain_phase[i] = params->chain_phase[i]; + tx_params->agc_gain[i] = params->agc_gain[i]; + } +} + +static int ath11k_wmi_tlv_cfr_capture_evt_parse(struct ath11k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + switch (tag) { + case WMI_TAG_PEER_CFR_CAPTURE_EVENT: + ath11k_wmi_tlv_cfr_capture_event_fixed_param(ptr, data); + break; + case WMI_TAG_CFR_CAPTURE_PHASE_PARAM: + ath11k_wmi_tlv_cfr_capture_phase_fixed_param(ptr, data); + break; + default: + ath11k_warn(ab, "Invalid tag received tag %d len %d\n", + tag, len); + return -EINVAL; + } + + return 0; +} + +static void ath11k_wmi_parse_cfr_capture_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + struct ath11k_cfr_peer_tx_param params = {}; + int ret; + + ath11k_dbg_dump(ab, ATH11K_DBG_CFR_DUMP, "cfr_dump:", "", + skb->data, skb->len); + + ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len, + ath11k_wmi_tlv_cfr_capture_evt_parse, + ¶ms); + if (ret) { + ath11k_warn(ab, "failed to parse cfr capture event tlv %d\n", + ret); + return; + } + + ret = ath11k_process_cfr_capture_event(ab, ¶ms); + if (ret) + ath11k_dbg(ab, ATH11K_DBG_CFR, + "failed to process cfr capture ret = %d\n", ret); +} + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -8882,6 +9022,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_P2P_NOA_EVENTID: ath11k_wmi_p2p_noa_event(ab, skb); break; + case WMI_PEER_CFR_CAPTURE_EVENTID: + ath11k_wmi_parse_cfr_capture_event(ab, skb); + break; default: ath11k_dbg(ab, ATH11K_DBG_WMI, "unsupported event id 0x%x\n", id); break; diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 0f0de24a3840..baed501b640b 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -362,6 +362,10 @@ enum wmi_tlv_cmd_id { WMI_PEER_REORDER_QUEUE_REMOVE_CMDID, WMI_PEER_SET_RX_BLOCKSIZE_CMDID, WMI_PEER_ANTDIV_INFO_REQ_CMDID, + WMI_PEER_RESERVED0_CMDID, + WMI_PEER_TID_MSDUQ_QDEPTH_THRESH_UPDATE_CMDID, + WMI_PEER_TID_CONFIGURATIONS_CMDID, + WMI_PEER_CFR_CAPTURE_CMDID, WMI_BCN_TX_CMDID = WMI_TLV_CMD(WMI_GRP_MGMT), WMI_PDEV_SEND_BCN_CMDID, WMI_BCN_TMPL_CMDID, @@ -981,6 +985,7 @@ enum wmi_tlv_pdev_param { WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE, WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE, WMI_PDEV_PARAM_MESH_MCAST_ENABLE, + WMI_PDEV_PARAM_PER_PEER_CFR_ENABLE = 0xa8, WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD = 0xbc, WMI_PDEV_PARAM_SET_CMD_OBSS_PD_PER_AC = 0xbe, WMI_PDEV_PARAM_ENABLE_SR_PROHIBIT = 0xc6, @@ -1884,6 +1889,8 @@ enum wmi_tlv_tag { WMI_TAG_NDP_EVENT, WMI_TAG_PDEV_PEER_PKTLOG_FILTER_CMD = 0x301, WMI_TAG_PDEV_PEER_PKTLOG_FILTER_INFO, + WMI_TAG_PEER_CFR_CAPTURE_EVENT = 0x317, + WMI_TAG_CFR_CAPTURE_PHASE_PARAM = 0x33b, WMI_TAG_FILS_DISCOVERY_TMPL_CMD = 0x344, WMI_TAG_PDEV_SRG_BSS_COLOR_BITMAP_CMD = 0x37b, WMI_TAG_PDEV_SRG_PARTIAL_BSSID_BITMAP_CMD, @@ -3832,7 +3839,8 @@ struct wmi_scan_prob_req_oui_cmd { #define WMI_TX_PARAMS_DWORD1_BW_MASK GENMASK(14, 8) #define WMI_TX_PARAMS_DWORD1_PREAMBLE_TYPE GENMASK(19, 15) #define WMI_TX_PARAMS_DWORD1_FRAME_TYPE BIT(20) -#define WMI_TX_PARAMS_DWORD1_RSVD GENMASK(31, 21) +#define WMI_TX_PARAMS_DWORD1_CFR_CAPTURE BIT(21) +#define WMI_TX_PARAMS_DWORD1_RSVD GENMASK(31, 22) struct wmi_mgmt_send_params { u32 tlv_header; @@ -4217,6 +4225,87 @@ enum cc_setting_code { */ }; +enum ath11k_wmi_cfr_capture_bw { + WMI_PEER_CFR_CAPTURE_BW_20, + WMI_PEER_CFR_CAPTURE_BW_40, + WMI_PEER_CFR_CAPTURE_BW_80, + WMI_PEER_CFR_CAPTURE_BW_MAX, +}; + +enum ath11k_wmi_cfr_capture_method { + WMI_CFR_CAPTURE_METHOD_NULL_FRAME, + WMI_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE, + WMI_CFR_CAPTURE_METHOD_PROBE_RESP, + WMI_CFR_CAPTURE_METHOD_MAX, +}; + +#define WMI_CFR_FRAME_TX_STATUS GENMASK(1, 0) +#define WMI_CFR_CAPTURE_STATUS_PEER_PS BIT(30) +#define WMI_CFR_PEER_CAPTURE_STATUS BIT(31) + +#define WMI_CFR_CORRELATION_INFO2_BUF_ADDR_HIGH GENMASK(3, 0) +#define WMI_CFR_CORRELATION_INFO2_PPDU_ID GENMASK(31, 16) + +#define WMI_CFR_CFO_MEASUREMENT_VALID BIT(0) +#define WMI_CFR_CFO_MEASUREMENT_RAW_DATA GENMASK(14, 1) + +struct ath11k_wmi_cfr_peer_tx_event_param { + u32 capture_method; + u32 vdev_id; + struct wmi_mac_addr mac_addr; + u32 chan_mhz; + u32 bandwidth; + u32 phy_mode; + u32 band_center_freq1; + u32 band_center_freq2; + u32 sts_count; + u32 correlation_info_1; + u32 correlation_info_2; + u32 status; + u32 timestamp_us; + u32 counter; + u32 chain_rssi[WMI_MAX_CHAINS]; + u32 cfo_measurement; + u32 rx_start_ts; +} __packed; + +struct ath11k_wmi_cfr_peer_tx_event_phase_param { + u32 chain_phase[WMI_MAX_CHAINS]; + u8 agc_gain[WMI_MAX_CHAINS]; +} __packed; + +enum ath11k_wmi_frame_tx_status { + WMI_FRAME_TX_STATUS_OK, + WMI_FRAME_TX_STATUS_XRETRY, + WMI_FRAME_TX_STATUS_DROP, + WMI_FRAME_TX_STATUS_FILTERED, +}; + +struct wmi_peer_cfr_capture_conf_arg { + enum ath11k_wmi_cfr_capture_bw bw; + enum ath11k_wmi_cfr_capture_method method; + u32 request; + u32 periodicity; +}; + +struct wmi_peer_cfr_capture_cmd_fixed_param { + u32 tlv_header; + u32 request; + struct wmi_mac_addr mac_addr; + u32 vdev_id; + u32 periodicity; + /* BW of measurement - of type enum ath11k_wmi_cfr_capture_bw */ + u32 bandwidth; + /* Method used to capture CFR - of type enum ath11k_wmi_cfr_capture_method */ + u32 capture_method; +} __packed; + +#define WMI_PEER_CFR_CAPTURE_ENABLE 1 +#define WMI_PEER_CFR_CAPTURE_DISABLE 0 + +/*periodicity in ms */ +#define WMI_PEER_CFR_PERIODICITY_MAX 600000 + static inline enum cc_setting_code ath11k_wmi_cc_setting_code_to_reg(enum wmi_reg_cc_setting_code status_code) { @@ -6346,7 +6435,7 @@ int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, u32 cmd_id); struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, - struct sk_buff *frame); + struct sk_buff *frame, bool tx_params_valid); int ath11k_wmi_p2p_go_bcn_ie(struct ath11k *ar, u32 vdev_id, const u8 *p2p_ie); int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, @@ -6531,5 +6620,7 @@ bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar); int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar, u32 vdev_id, struct ath11k_reg_tpc_power_info *param); - +int ath11k_wmi_peer_set_cfr_capture_conf(struct ath11k *ar, + u32 vdev_id, const u8 *mac, + struct wmi_peer_cfr_capture_conf_arg *arg); #endif diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 31d5d10beb85..990934ec92fc 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -155,6 +155,7 @@ enum ath12k_hw_rev { ATH12K_HW_QCN9274_HW20, ATH12K_HW_WCN7850_HW20, ATH12K_HW_IPQ5332_HW10, + ATH12K_HW_QCC2072_HW10, }; enum ath12k_firmware_mode { @@ -1081,6 +1082,8 @@ struct ath12k_base { size_t amss_dualmac_len; const u8 *m3_data; size_t m3_len; + const u8 *aux_uc_data; + size_t aux_uc_len; DECLARE_BITMAP(fw_features, ATH12K_FW_FEATURE_COUNT); bool fw_features_valid; diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 9f05eea6695a..ab54c8a84d3e 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1513,7 +1513,7 @@ static int ath12k_dp_setup(struct ath12k_base *ab) HAL_WBM_IDLE_LINK, srng, n_link_desc); if (ret) { ath12k_warn(ab, "failed to setup link desc: %d\n", ret); - return ret; + goto rhash_destroy; } ret = ath12k_dp_cc_init(ab); diff --git a/drivers/net/wireless/ath/ath12k/fw.c b/drivers/net/wireless/ath/ath12k/fw.c index 5ac497f80cad..22074653cbb8 100644 --- a/drivers/net/wireless/ath/ath12k/fw.c +++ b/drivers/net/wireless/ath/ath12k/fw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* - * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -121,6 +121,14 @@ static int ath12k_fw_request_firmware_api_n(struct ath12k_base *ab, ab->fw.m3_data = data; ab->fw.m3_len = ie_len; break; + case ATH12K_FW_IE_AUX_UC_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found aux_uc image ie (%zd B)\n", + ie_len); + + ab->fw.aux_uc_data = data; + ab->fw.aux_uc_len = ie_len; + break; case ATH12K_FW_IE_AMSS_DUALMAC_IMAGE: ath12k_dbg(ab, ATH12K_DBG_BOOT, "found dualmac fw image ie (%zd B)\n", diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h index 7afaefed5086..e146d24dfea4 100644 --- a/drivers/net/wireless/ath/ath12k/fw.h +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* - * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH12K_FW_H @@ -15,6 +15,7 @@ enum ath12k_fw_ie_type { ATH12K_FW_IE_AMSS_IMAGE = 2, ATH12K_FW_IE_M3_IMAGE = 3, ATH12K_FW_IE_AMSS_DUALMAC_IMAGE = 4, + ATH12K_FW_IE_AUX_UC_IMAGE = 5, }; enum ath12k_fw_features { diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index c7a152490fa0..a164563fff28 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -823,3 +823,49 @@ void ath12k_hal_dump_srng_stats(struct ath12k_base *ab) jiffies_to_msecs(jiffies - srng->timestamp)); } } + +void *ath12k_hal_encode_tlv64_hdr(void *tlv, u64 tag, u64 len) +{ + struct hal_tlv_64_hdr *tlv64 = tlv; + + tlv64->tl = le64_encode_bits(tag, HAL_TLV_HDR_TAG) | + le64_encode_bits(len, HAL_TLV_HDR_LEN); + + return tlv64->value; +} +EXPORT_SYMBOL(ath12k_hal_encode_tlv64_hdr); + +void *ath12k_hal_encode_tlv32_hdr(void *tlv, u64 tag, u64 len) +{ + struct hal_tlv_hdr *tlv32 = tlv; + + tlv32->tl = le32_encode_bits(tag, HAL_TLV_HDR_TAG) | + le32_encode_bits(len, HAL_TLV_HDR_LEN); + + return tlv32->value; +} +EXPORT_SYMBOL(ath12k_hal_encode_tlv32_hdr); + +u16 ath12k_hal_decode_tlv64_hdr(void *tlv, void **desc) +{ + struct hal_tlv_64_hdr *tlv64 = tlv; + u16 tag; + + tag = le64_get_bits(tlv64->tl, HAL_SRNG_TLV_HDR_TAG); + *desc = tlv64->value; + + return tag; +} +EXPORT_SYMBOL(ath12k_hal_decode_tlv64_hdr); + +u16 ath12k_hal_decode_tlv32_hdr(void *tlv, void **desc) +{ + struct hal_tlv_hdr *tlv32 = tlv; + u16 tag; + + tag = le32_get_bits(tlv32->tl, HAL_SRNG_TLV_HDR_TAG); + *desc = tlv32->value; + + return tag; +} +EXPORT_SYMBOL(ath12k_hal_decode_tlv32_hdr); diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index f23ba1f9eaac..43e3880f8257 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1121,6 +1121,8 @@ struct ath12k_hw_hal_params { u32 wbm2sw_cc_enable; }; +#define ATH12K_HW_REG_UNDEFINED 0xdeadbeaf + struct ath12k_hw_regs { u32 tcl1_ring_id; u32 tcl1_ring_misc; @@ -1199,6 +1201,8 @@ struct ath12k_hw_regs { u32 reo_status_ring_base; u32 gcc_gcc_pcie_hot_rst; + + u32 qrtr_node_id; }; /* HAL context to be used to access SRNG APIs (currently used by data path @@ -1426,8 +1430,34 @@ struct hal_ops { u32 *sw_cookie, struct ath12k_buffer_addr **pp_buf_addr, u8 *rbm, u32 *msdu_cnt); + void *(*reo_cmd_enc_tlv_hdr)(void *tlv, u64 tag, u64 len); + u16 (*reo_status_dec_tlv_hdr)(void *tlv, void **desc); }; +#define HAL_TLV_HDR_TAG GENMASK(9, 1) +#define HAL_TLV_HDR_LEN GENMASK(25, 10) +#define HAL_TLV_USR_ID GENMASK(31, 26) + +#define HAL_TLV_ALIGN 4 + +struct hal_tlv_hdr { + __le32 tl; + u8 value[]; +} __packed; + +#define HAL_TLV_64_HDR_TAG GENMASK(9, 1) +#define HAL_TLV_64_HDR_LEN GENMASK(21, 10) +#define HAL_TLV_64_USR_ID GENMASK(31, 26) +#define HAL_TLV_64_ALIGN 8 + +struct hal_tlv_64_hdr { + __le64 tl; + u8 value[]; +} __packed; + +#define HAL_SRNG_TLV_HDR_TAG GENMASK(9, 1) +#define HAL_SRNG_TLV_HDR_LEN GENMASK(25, 10) + dma_addr_t ath12k_hal_srng_get_tp_addr(struct ath12k_base *ab, struct hal_srng *srng); dma_addr_t ath12k_hal_srng_get_hp_addr(struct ath12k_base *ab, @@ -1515,4 +1545,8 @@ void ath12k_hal_rx_reo_ent_buf_paddr_get(struct ath12k_hal *hal, void *rx_desc, dma_addr_t *paddr, u32 *sw_cookie, struct ath12k_buffer_addr **pp_buf_addr, u8 *rbm, u32 *msdu_cnt); +void *ath12k_hal_encode_tlv64_hdr(void *tlv, u64 tag, u64 len); +void *ath12k_hal_encode_tlv32_hdr(void *tlv, u64 tag, u64 len); +u16 ath12k_hal_decode_tlv64_hdr(void *tlv, void **desc); +u16 ath12k_hal_decode_tlv32_hdr(void *tlv, void **desc); #endif diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 655753d0413a..a9888e0521a1 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -78,6 +78,7 @@ #define ATH12K_DEFAULT_CAL_FILE "caldata.bin" #define ATH12K_AMSS_FILE "amss.bin" #define ATH12K_M3_FILE "m3.bin" +#define ATH12K_AUX_UC_FILE "aux_ucode.bin" #define ATH12K_REGDB_FILE_NAME "regdb.bin" #define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128 @@ -142,6 +143,7 @@ struct ath12k_hw_params { size_t board_size; size_t cal_offset; enum ath12k_m3_fw_loaders m3_loader; + bool download_aux_ucode:1; } fw; u8 max_radios; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 5cd10752b22e..cdb72439dcf4 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -14531,7 +14531,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) if (is_monitor_disable) /* There's a race between calling ieee80211_register_hw() * and here where the monitor mode is enabled for a little - * while. But that time is so short and in practise it make + * while. But that time is so short and in practice it doesn't make * a difference in real life. */ wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index a42c4289c6b2..375277ca2b89 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -23,7 +23,6 @@ #define ATH12K_PCI_IRQ_CE0_OFFSET 3 #define WINDOW_ENABLE_BIT 0x40000000 -#define WINDOW_REG_ADDRESS 0x310c #define WINDOW_VALUE_MASK GENMASK(24, 19) #define WINDOW_START 0x80000 #define WINDOW_RANGE_MASK GENMASK(18, 0) @@ -35,10 +34,6 @@ */ #define ACCESS_ALWAYS_OFF 0xFE0 -#define PCIE_LOCAL_REG_QRTR_NODE_ID 0x1E03164 -#define DOMAIN_NUMBER_MASK GENMASK(7, 4) -#define BUS_NUMBER_MASK GENMASK(3, 0) - static struct ath12k_pci_driver *ath12k_pci_family_drivers[ATH12K_DEVICE_FAMILY_MAX]; static const struct ath12k_msi_config msi_config_one_msi = { .total_vectors = 1, @@ -125,8 +120,8 @@ static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset) if (window != ab_pci->register_window) { iowrite32(WINDOW_ENABLE_BIT | window, - ab->mem + WINDOW_REG_ADDRESS); - ioread32(ab->mem + WINDOW_REG_ADDRESS); + ab->mem + ab_pci->window_reg_addr); + ioread32(ab->mem + ab_pci->window_reg_addr); ab_pci->register_window = window; } } @@ -145,7 +140,7 @@ static void ath12k_pci_select_static_window(struct ath12k_pci *ab_pci) ab_pci->register_window = window; spin_unlock_bh(&ab_pci->window_lock); - iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS); + iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + ab_pci->window_reg_addr); } static u32 ath12k_pci_get_window_start(struct ath12k_base *ab, @@ -178,8 +173,8 @@ static void ath12k_pci_restore_window(struct ath12k_base *ab) spin_lock_bh(&ab_pci->window_lock); iowrite32(WINDOW_ENABLE_BIT | ab_pci->register_window, - ab->mem + WINDOW_REG_ADDRESS); - ioread32(ab->mem + WINDOW_REG_ADDRESS); + ab->mem + ab_pci->window_reg_addr); + ioread32(ab->mem + ab_pci->window_reg_addr); spin_unlock_bh(&ab_pci->window_lock); } @@ -919,7 +914,7 @@ static void ath12k_pci_update_qrtr_node_id(struct ath12k_base *ab) * writes to the given register, it is available for firmware when the QMI service * is spawned. */ - reg = PCIE_LOCAL_REG_QRTR_NODE_ID & WINDOW_RANGE_MASK; + reg = PCIE_LOCAL_REG_QRTR_NODE_ID(ab) & WINDOW_RANGE_MASK; ath12k_pci_write32(ab, reg, ab_pci->qmi_instance); ath12k_dbg(ab, ATH12K_DBG_PCI, "pci reg 0x%x instance 0x%x read val 0x%x\n", @@ -1541,7 +1536,6 @@ static int ath12k_pci_probe(struct pci_dev *pdev, } ab->dev = &pdev->dev; - pci_set_drvdata(pdev, ab); ab_pci = ath12k_pci_priv(ab); ab_pci->dev_id = pci_dev->device; ab_pci->ab = ab; diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 1cc4f0e050f9..0e0e2020c6ae 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -59,6 +59,11 @@ #define QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB 0x1E20338 #define OTP_BOARD_ID_MASK GENMASK(15, 0) +#define PCIE_LOCAL_REG_QRTR_NODE_ID(ab) \ + ((ab)->hal.regs->qrtr_node_id) +#define DOMAIN_NUMBER_MASK GENMASK(7, 4) +#define BUS_NUMBER_MASK GENMASK(3, 0) + #define PCI_BAR_WINDOW0_BASE 0x1E00000 #define PCI_BAR_WINDOW0_END 0x1E7FFFC #define PCI_SOC_RANGE_MASK 0x3FFF @@ -130,6 +135,8 @@ struct ath12k_pci { u64 dma_mask; const struct ath12k_pci_device_family_ops *device_family_ops; const struct ath12k_pci_reg_base *reg_base; + + u32 window_reg_addr; }; struct ath12k_pci_driver { diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index b7c48b6706df..cfde4147c8fc 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1623,6 +1623,47 @@ static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { }, }; +static const struct qmi_elem_info qmi_wlanfw_aux_uc_info_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01, addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_wlanfw_aux_uc_info_req_msg_v01, size), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info qmi_wlanfw_aux_uc_info_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_wlanfw_aux_uc_info_resp_msg_v01, resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + static const struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, @@ -2609,6 +2650,7 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) case M3_DUMP_REGION_TYPE: case PAGEABLE_MEM_REGION_TYPE: case CALDB_MEM_REGION_TYPE: + case LPASS_SHARED_V01_REGION_TYPE: ret = ath12k_qmi_alloc_chunk(ab, chunk); if (ret) goto err; @@ -3236,6 +3278,131 @@ out: return ret; } +static void ath12k_qmi_aux_uc_free(struct ath12k_base *ab) +{ + struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem; + + if (!aux_uc_mem->vaddr) + return; + + dma_free_coherent(ab->dev, aux_uc_mem->total_size, + aux_uc_mem->vaddr, aux_uc_mem->paddr); + aux_uc_mem->vaddr = NULL; + aux_uc_mem->total_size = 0; + aux_uc_mem->size = 0; +} + +static int ath12k_qmi_aux_uc_load(struct ath12k_base *ab) +{ + struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem; + const struct firmware *fw = NULL; + const void *aux_uc_data; + char path[100]; + size_t aux_uc_len; + int ret; + + if (ab->fw.aux_uc_data && ab->fw.aux_uc_len > 0) { + /* firmware-N.bin had a aux_uc firmware file so use that */ + aux_uc_data = ab->fw.aux_uc_data; + aux_uc_len = ab->fw.aux_uc_len; + } else { + /* + * No aux_uc file in firmware-N.bin so try to request old + * separate aux_ucode.bin. + */ + fw = ath12k_core_firmware_request(ab, ATH12K_AUX_UC_FILE); + if (IS_ERR(fw)) { + ret = PTR_ERR(fw); + ath12k_core_create_firmware_path(ab, ATH12K_AUX_UC_FILE, + path, sizeof(path)); + ath12k_err(ab, "failed to load %s: %d\n", path, ret); + return ret; + } + + aux_uc_data = fw->data; + aux_uc_len = fw->size; + } + + /* In recovery/resume cases, AUX_UC buffer is not freed, try to reuse that */ + if (aux_uc_mem->vaddr) { + if (aux_uc_mem->total_size >= aux_uc_len) + goto copy; + + /* Old buffer is too small, free and reallocate */ + ath12k_qmi_aux_uc_free(ab); + } + + aux_uc_mem->vaddr = dma_alloc_coherent(ab->dev, aux_uc_len, + &aux_uc_mem->paddr, GFP_KERNEL); + if (!aux_uc_mem->vaddr) { + ret = -ENOMEM; + goto out; + } + + aux_uc_mem->total_size = aux_uc_len; + +copy: + memcpy(aux_uc_mem->vaddr, aux_uc_data, aux_uc_len); + aux_uc_mem->size = aux_uc_len; + + ret = 0; + +out: + release_firmware(fw); + + return ret; +} + +static noinline_for_stack +int ath12k_qmi_wlanfw_aux_uc_info_send(struct ath12k_base *ab) +{ + struct m3_mem_region *aux_uc_mem = &ab->qmi.aux_uc_mem; + struct qmi_wlanfw_aux_uc_info_req_msg_v01 req = {}; + struct qmi_wlanfw_aux_uc_info_resp_msg_v01 resp = {}; + struct qmi_txn txn; + int ret = 0; + + ret = ath12k_qmi_aux_uc_load(ab); + if (ret) { + ath12k_err(ab, "failed to load aux_uc firmware: %d", ret); + return ret; + } + + req.addr = aux_uc_mem->paddr; + req.size = aux_uc_mem->size; + + ret = qmi_txn_init(&ab->qmi.handle, &txn, + qmi_wlanfw_aux_uc_info_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, + QMI_WLANFW_AUX_UC_INFO_REQ_V01, + QMI_WLANFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN, + qmi_wlanfw_aux_uc_info_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath12k_warn(ab, "qmi failed to send AUX_UC information request, err = %d\n", + ret); + goto out; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS)); + if (ret < 0) { + ath12k_warn(ab, "qmi failed AUX_UC information request %d\n", ret); + goto out; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath12k_warn(ab, "qmi AUX_UC info request failed, result: %d, err: %d\n", + resp.resp.result, resp.resp.error); + ret = -EINVAL; + goto out; + } +out: + return ret; +} + static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, u32 mode) { @@ -3600,6 +3767,7 @@ static noinline_for_stack int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi) { struct ath12k_base *ab = qmi->ab; + const struct ath12k_hw_params *hw_params = ab->hw_params; int ret; ret = ath12k_qmi_request_target_cap(ab); @@ -3620,7 +3788,7 @@ int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi) return ret; } - if (ab->hw_params->download_calib) { + if (hw_params->download_calib) { ret = ath12k_qmi_load_bdf_qmi(ab, ATH12K_QMI_BDF_TYPE_CALIBRATION); if (ret < 0) ath12k_warn(ab, "qmi failed to load calibrated data :%d\n", ret); @@ -3632,6 +3800,14 @@ int ath12k_qmi_event_load_bdf(struct ath12k_qmi *qmi) return ret; } + if (hw_params->fw.download_aux_ucode) { + ret = ath12k_qmi_wlanfw_aux_uc_info_send(ab); + if (ret < 0) { + ath12k_warn(ab, "qmi failed to send aux_uc info req: %d\n", ret); + return ret; + } + } + return ret; } @@ -3905,6 +4081,7 @@ void ath12k_qmi_deinit_service(struct ath12k_base *ab) qmi_handle_release(&ab->qmi.handle); cancel_work_sync(&ab->qmi.event_work); destroy_workqueue(ab->qmi.event_wq); + ath12k_qmi_aux_uc_free(ab); ath12k_qmi_m3_free(ab); ath12k_qmi_free_target_mem_chunk(ab); ab->qmi.ab = NULL; @@ -3913,5 +4090,6 @@ void ath12k_qmi_deinit_service(struct ath12k_base *ab) void ath12k_qmi_free_resource(struct ath12k_base *ab) { ath12k_qmi_free_target_mem_chunk(ab); + ath12k_qmi_aux_uc_free(ab); ath12k_qmi_m3_free(ab); } diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 7a88268aa1e9..b5a4a01391cb 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -154,6 +154,7 @@ struct ath12k_qmi { u8 num_radios; struct target_info target; struct m3_mem_region m3_mem; + struct m3_mem_region aux_uc_mem; unsigned int service_ins_id; struct dev_mem_info dev_mem[ATH12K_QMI_WLFW_MAX_DEV_MEM_NUM_V01]; }; @@ -178,6 +179,7 @@ enum ath12k_qmi_target_mem { CALDB_MEM_REGION_TYPE = 0x4, MLO_GLOBAL_MEM_REGION_TYPE = 0x8, PAGEABLE_MEM_REGION_TYPE = 0x9, + LPASS_SHARED_V01_REGION_TYPE = 0xb, }; enum qmi_wlanfw_host_build_type { @@ -202,6 +204,7 @@ enum ath12k_qmi_cnss_feature { CNSS_FEATURE_MIN_ENUM_VAL_V01 = INT_MIN, CNSS_QDSS_CFG_MISS_V01 = 3, CNSS_PCIE_PERST_NO_PULL_V01 = 4, + CNSS_AUX_UC_SUPPORT_V01 = 6, CNSS_MAX_FEATURE_V01 = 64, CNSS_FEATURE_MAX_ENUM_VAL_V01 = INT_MAX, }; @@ -540,6 +543,19 @@ struct qmi_wlanfw_m3_info_resp_msg_v01 { struct qmi_response_type_v01 resp; }; +#define QMI_WLANFW_AUX_UC_INFO_REQ_MSG_V01_MAX_MSG_LEN 18 +#define QMI_WLANFW_AUX_UC_INFO_RESP_MSG_V01_MAX_MSG_LEN 7 +#define QMI_WLANFW_AUX_UC_INFO_REQ_V01 0x005A + +struct qmi_wlanfw_aux_uc_info_req_msg_v01 { + u64 addr; + u32 size; +}; + +struct qmi_wlanfw_aux_uc_info_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + #define QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN 11 #define QMI_WLANFW_WLAN_MODE_RESP_MSG_V01_MAX_LEN 7 #define QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN 803 diff --git a/drivers/net/wireless/ath/ath12k/wifi7/Makefile b/drivers/net/wireless/ath/ath12k/wifi7/Makefile index dcfa732bb95b..45b561cdba4b 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/Makefile +++ b/drivers/net/wireless/ath/ath12k/wifi7/Makefile @@ -14,6 +14,7 @@ ath12k_wifi7-y += core.o \ dp_mon.o \ hal.o \ hal_qcn9274.o \ - hal_wcn7850.o + hal_wcn7850.o \ + hal_qcc2072.o ath12k_wifi7-$(CONFIG_ATH12K_AHB) += ahb.o diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c index a1ca55fe51c0..7450938adf65 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c @@ -9,6 +9,7 @@ #include "../peer.h" #include "hal_qcn9274.h" #include "hal_wcn7850.h" +#include "hal_qcc2072.h" static u16 ath12k_wifi7_dp_rx_get_peer_id(struct ath12k_dp *dp, enum ath12k_peer_metadata_version ver, @@ -2110,16 +2111,59 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) return ret; } +int ath12k_dp_rxdma_ring_sel_config_qcc2072(struct ath12k_base *ab) +{ + struct ath12k_dp *dp = ath12k_ab_to_dp(ab); + struct htt_rx_ring_tlv_filter tlv_filter = {}; + u32 ring_id; + int ret = 0; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; + int i; + + ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; + + tlv_filter.rx_filter = HTT_RX_TLV_FLAGS_RXDMA_RING; + tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_BAR; + tlv_filter.pkt_filter_flags3 = HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_MCAST | + HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_UCAST | + HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA; + tlv_filter.offset_valid = true; + tlv_filter.rx_packet_offset = hal_rx_desc_sz; + + tlv_filter.rx_header_offset = offsetof(struct hal_rx_desc_qcc2072, pkt_hdr_tlv); + + tlv_filter.rx_mpdu_start_offset = + ath12k_hal_rx_desc_get_mpdu_start_offset_qcc2072(); + tlv_filter.rx_msdu_end_offset = + ath12k_hal_rx_desc_get_msdu_end_offset_qcc2072(); + + /* + * TODO: Selectively subscribe to required qwords within msdu_end + * and mpdu_start and setup the mask in below msg + * and modify the rx_desc struct + */ + + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { + ring_id = dp->rx_mac_buf_ring[i].ring_id; + ret = ath12k_dp_tx_htt_rx_filter_setup(ab, ring_id, i, + HAL_RXDMA_BUF, + DP_RXDMA_REFILL_RING_SIZE, + &tlv_filter); + } + + return ret; +} + void ath12k_wifi7_dp_rx_process_reo_status(struct ath12k_dp *dp) { struct ath12k_base *ab = dp->ab; struct ath12k_hal *hal = dp->hal; - struct hal_tlv_64_hdr *hdr; struct hal_srng *srng; struct ath12k_dp_rx_reo_cmd *cmd, *tmp; bool found = false; u16 tag; struct hal_reo_status reo_status; + void *hdr, *desc; srng = &hal->srng_list[dp->reo_status_ring.ring_id]; @@ -2130,35 +2174,35 @@ void ath12k_wifi7_dp_rx_process_reo_status(struct ath12k_dp *dp) ath12k_hal_srng_access_begin(ab, srng); while ((hdr = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { - tag = le64_get_bits(hdr->tl, HAL_SRNG_TLV_HDR_TAG); + tag = hal->ops->reo_status_dec_tlv_hdr(hdr, &desc); switch (tag) { case HAL_REO_GET_QUEUE_STATS_STATUS: - ath12k_wifi7_hal_reo_status_queue_stats(ab, hdr, + ath12k_wifi7_hal_reo_status_queue_stats(ab, desc, &reo_status); break; case HAL_REO_FLUSH_QUEUE_STATUS: - ath12k_wifi7_hal_reo_flush_queue_status(ab, hdr, + ath12k_wifi7_hal_reo_flush_queue_status(ab, desc, &reo_status); break; case HAL_REO_FLUSH_CACHE_STATUS: - ath12k_wifi7_hal_reo_flush_cache_status(ab, hdr, + ath12k_wifi7_hal_reo_flush_cache_status(ab, desc, &reo_status); break; case HAL_REO_UNBLOCK_CACHE_STATUS: - ath12k_wifi7_hal_reo_unblk_cache_status(ab, hdr, + ath12k_wifi7_hal_reo_unblk_cache_status(ab, desc, &reo_status); break; case HAL_REO_FLUSH_TIMEOUT_LIST_STATUS: - ath12k_wifi7_hal_reo_flush_timeout_list_status(ab, hdr, + ath12k_wifi7_hal_reo_flush_timeout_list_status(ab, desc, &reo_status); break; case HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS: - ath12k_wifi7_hal_reo_desc_thresh_reached_status(ab, hdr, + ath12k_wifi7_hal_reo_desc_thresh_reached_status(ab, desc, &reo_status); break; case HAL_REO_UPDATE_RX_REO_QUEUE_STATUS: - ath12k_wifi7_hal_reo_update_rx_reo_queue_status(ab, hdr, + ath12k_wifi7_hal_reo_update_rx_reo_queue_status(ab, desc, &reo_status); break; default: diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h index a98836b83f48..8aa79faf567f 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h @@ -22,6 +22,7 @@ int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int mac_id, void ath12k_wifi7_dp_rx_process_reo_status(struct ath12k_dp *dp); int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab); int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab); +int ath12k_dp_rxdma_ring_sel_config_qcc2072(struct ath12k_base *ab); void ath12k_wifi7_dp_setup_pn_check_reo_cmd(struct ath12k_hal_reo_cmd *cmd, struct ath12k_dp_rx_tid *rx_tid, u32 cipher, enum set_key_cmd key_cmd); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal.c b/drivers/net/wireless/ath/ath12k/wifi7/hal.c index 03a007dd6857..bd1753ca0db6 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal.c @@ -12,6 +12,7 @@ #include "../hif.h" #include "hal_qcn9274.h" #include "hal_wcn7850.h" +#include "hal_qcc2072.h" static const struct ath12k_hw_version_map ath12k_wifi7_hw_ver_map[] = { [ATH12K_HW_QCN9274_HW10] = { @@ -42,6 +43,13 @@ static const struct ath12k_hw_version_map ath12k_wifi7_hw_ver_map[] = { .hal_params = &ath12k_hw_hal_params_ipq5332, .hw_regs = &ipq5332_regs, }, + [ATH12K_HW_QCC2072_HW10] = { + .hal_ops = &hal_qcc2072_ops, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcc2072), + .tcl_to_wbm_rbm_map = ath12k_hal_tcl_to_wbm_rbm_map_wcn7850, + .hal_params = &ath12k_hw_hal_params_wcn7850, + .hw_regs = &qcc2072_regs, + }, }; int ath12k_wifi7_hal_init(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal.h b/drivers/net/wireless/ath/ath12k/wifi7/hal.h index 7d65b82c61f2..9337225a5253 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal.h @@ -369,9 +369,6 @@ #define HAL_DEFAULT_BE_BK_VI_REO_TIMEOUT_USEC (100 * 1000) #define HAL_DEFAULT_VO_REO_TIMEOUT_USEC (40 * 1000) -#define HAL_SRNG_TLV_HDR_TAG GENMASK(9, 1) -#define HAL_SRNG_TLV_HDR_LEN GENMASK(25, 10) - #define HAL_SRNG_DESC_LOOP_CNT 0xf0000000 #define HAL_REO_CMD_FLG_NEED_STATUS BIT(0) diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h index 9dad8f7ca9f2..e1ab47b44433 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h @@ -487,27 +487,6 @@ enum hal_tlv_tag { HAL_TLV_BASE = 511 /* 0x1ff */, }; -#define HAL_TLV_HDR_TAG GENMASK(9, 1) -#define HAL_TLV_HDR_LEN GENMASK(25, 10) -#define HAL_TLV_USR_ID GENMASK(31, 26) - -#define HAL_TLV_ALIGN 4 - -struct hal_tlv_hdr { - __le32 tl; - u8 value[]; -} __packed; - -#define HAL_TLV_64_HDR_TAG GENMASK(9, 1) -#define HAL_TLV_64_HDR_LEN GENMASK(21, 10) -#define HAL_TLV_64_USR_ID GENMASK(31, 26) -#define HAL_TLV_64_ALIGN 8 - -struct hal_tlv_64_hdr { - __le64 tl; - u8 value[]; -} __packed; - #define RX_MPDU_DESC_INFO0_MSDU_COUNT GENMASK(7, 0) #define RX_MPDU_DESC_INFO0_FRAG_FLAG BIT(8) #define RX_MPDU_DESC_INFO0_MPDU_RETRY BIT(9) @@ -1070,6 +1049,13 @@ struct hal_reo_get_queue_stats { * Hole_count */ +struct hal_reo_get_queue_stats_qcc2072 { + struct hal_reo_cmd_hdr cmd; + __le32 queue_addr_lo; + __le32 info0; + __le32 rsvd0[6]; +} __packed; + #define HAL_REO_FLUSH_QUEUE_INFO0_DESC_ADDR_HI GENMASK(7, 0) #define HAL_REO_FLUSH_QUEUE_INFO0_BLOCK_DESC_ADDR BIT(8) #define HAL_REO_FLUSH_QUEUE_INFO0_BLOCK_RESRC_IDX GENMASK(10, 9) @@ -2453,6 +2439,11 @@ struct hal_reo_get_queue_stats_status { * entries into this Ring has looped around the ring. */ +struct hal_reo_get_queue_stats_status_qcc2072 { + __le32 tlv32_padding; + struct hal_reo_get_queue_stats_status status; +} __packed; + #define HAL_REO_STATUS_LOOP_CNT GENMASK(31, 28) #define HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED BIT(0) diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c new file mode 100644 index 000000000000..1eefb931a853 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include "hal_qcc2072.h" +#include "hal_wcn7850.h" + +const struct ath12k_hw_regs qcc2072_regs = { + /* SW2TCL(x) R0 ring configuration address */ + .tcl1_ring_id = 0x00000920, + .tcl1_ring_misc = 0x00000928, + .tcl1_ring_tp_addr_lsb = 0x00000934, + .tcl1_ring_tp_addr_msb = 0x00000938, + .tcl1_ring_consumer_int_setup_ix0 = 0x00000948, + .tcl1_ring_consumer_int_setup_ix1 = 0x0000094c, + .tcl1_ring_msi1_base_lsb = 0x00000960, + .tcl1_ring_msi1_base_msb = 0x00000964, + .tcl1_ring_msi1_data = 0x00000968, + .tcl_ring_base_lsb = 0x00000b70, + .tcl1_ring_base_lsb = 0x00000918, + .tcl1_ring_base_msb = 0x0000091c, + .tcl2_ring_base_lsb = 0x00000990, + + /* TCL STATUS ring address */ + .tcl_status_ring_base_lsb = 0x00000d50, + + .wbm_idle_ring_base_lsb = 0x00000d3c, + .wbm_idle_ring_misc_addr = 0x00000d4c, + .wbm_r0_idle_list_cntl_addr = 0x00000240, + .wbm_r0_idle_list_size_addr = 0x00000244, + .wbm_scattered_ring_base_lsb = 0x00000250, + .wbm_scattered_ring_base_msb = 0x00000254, + .wbm_scattered_desc_head_info_ix0 = 0x00000260, + .wbm_scattered_desc_head_info_ix1 = 0x00000264, + .wbm_scattered_desc_tail_info_ix0 = 0x00000270, + .wbm_scattered_desc_tail_info_ix1 = 0x00000274, + .wbm_scattered_desc_ptr_hp_addr = 0x00000027c, + + .wbm_sw_release_ring_base_lsb = 0x0000037c, + .wbm_sw1_release_ring_base_lsb = ATH12K_HW_REG_UNDEFINED, + .wbm0_release_ring_base_lsb = 0x00000e08, + .wbm1_release_ring_base_lsb = 0x00000e80, + + /* PCIe base address */ + .pcie_qserdes_sysclk_en_sel = 0x01e0c0ac, + .pcie_pcs_osc_dtct_config_base = 0x01e0cc58, + + /* PPE release ring address */ + .ppe_rel_ring_base = 0x0000046c, + + /* REO DEST ring address */ + .reo2_ring_base = 0x00000578, + .reo1_misc_ctrl_addr = 0x00000ba0, + .reo1_sw_cookie_cfg0 = 0x0000006c, + .reo1_sw_cookie_cfg1 = 0x00000070, + .reo1_qdesc_lut_base0 = ATH12K_HW_REG_UNDEFINED, + .reo1_qdesc_lut_base1 = ATH12K_HW_REG_UNDEFINED, + + .reo1_ring_base_lsb = 0x00000500, + .reo1_ring_base_msb = 0x00000504, + .reo1_ring_id = 0x00000508, + .reo1_ring_misc = 0x00000510, + .reo1_ring_hp_addr_lsb = 0x00000514, + .reo1_ring_hp_addr_msb = 0x00000518, + .reo1_ring_producer_int_setup = 0x00000524, + .reo1_ring_msi1_base_lsb = 0x00000548, + .reo1_ring_msi1_base_msb = 0x0000054c, + .reo1_ring_msi1_data = 0x00000550, + .reo1_aging_thres_ix0 = 0x00000b2c, + .reo1_aging_thres_ix1 = 0x00000b30, + .reo1_aging_thres_ix2 = 0x00000b34, + .reo1_aging_thres_ix3 = 0x00000b38, + + /* REO Exception ring address */ + .reo2_sw0_ring_base = 0x000008c0, + + /* REO Reinject ring address */ + .sw2reo_ring_base = 0x00000320, + .sw2reo1_ring_base = 0x00000398, + + /* REO cmd ring address */ + .reo_cmd_ring_base = 0x000002a8, + + /* REO status ring address */ + .reo_status_ring_base = 0x00000aa0, + + /* CE base address */ + .umac_ce0_src_reg_base = 0x01b80000, + .umac_ce0_dest_reg_base = 0x01b81000, + .umac_ce1_src_reg_base = 0x01b82000, + .umac_ce1_dest_reg_base = 0x01b83000, + + .gcc_gcc_pcie_hot_rst = 0x1e65304, + + .qrtr_node_id = 0x1e03300, +}; + +static void ath12k_hal_rx_desc_set_msdu_len_qcc2072(struct hal_rx_desc *desc, u16 len) +{ + u32 info = __le32_to_cpu(desc->u.qcc2072.msdu_end.info10); + + info &= ~RX_MSDU_END_INFO10_MSDU_LENGTH; + info |= u32_encode_bits(len, RX_MSDU_END_INFO10_MSDU_LENGTH); + + desc->u.qcc2072.msdu_end.info10 = __cpu_to_le32(info); +} + +static void ath12k_hal_rx_desc_get_dot11_hdr_qcc2072(struct hal_rx_desc *desc, + struct ieee80211_hdr *hdr) +{ + hdr->frame_control = desc->u.qcc2072.mpdu_start.frame_ctrl; + hdr->duration_id = desc->u.qcc2072.mpdu_start.duration; + ether_addr_copy(hdr->addr1, desc->u.qcc2072.mpdu_start.addr1); + ether_addr_copy(hdr->addr2, desc->u.qcc2072.mpdu_start.addr2); + ether_addr_copy(hdr->addr3, desc->u.qcc2072.mpdu_start.addr3); + + if (__le32_to_cpu(desc->u.qcc2072.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR4_VALID) + ether_addr_copy(hdr->addr4, desc->u.qcc2072.mpdu_start.addr4); + + hdr->seq_ctrl = desc->u.qcc2072.mpdu_start.seq_ctrl; +} + +static void ath12k_hal_rx_desc_get_crypto_hdr_qcc2072(struct hal_rx_desc *desc, + u8 *crypto_hdr, + enum hal_encrypt_type enctype) +{ + unsigned int key_id; + + switch (enctype) { + case HAL_ENCRYPT_TYPE_OPEN: + return; + case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: + case HAL_ENCRYPT_TYPE_TKIP_MIC: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[1] = 0; + crypto_hdr[2] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcc2072.mpdu_start.pn[0]); + break; + case HAL_ENCRYPT_TYPE_CCMP_128: + case HAL_ENCRYPT_TYPE_CCMP_256: + case HAL_ENCRYPT_TYPE_GCMP_128: + case HAL_ENCRYPT_TYPE_AES_GCMP_256: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[1] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[2] = 0; + break; + case HAL_ENCRYPT_TYPE_WEP_40: + case HAL_ENCRYPT_TYPE_WEP_104: + case HAL_ENCRYPT_TYPE_WEP_128: + case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: + case HAL_ENCRYPT_TYPE_WAPI: + return; + } + + key_id = u32_get_bits(__le32_to_cpu(desc->u.qcc2072.mpdu_start.info5), + RX_MPDU_START_INFO5_KEY_ID); + crypto_hdr[3] = 0x20 | (key_id << 6); + crypto_hdr[4] = HAL_RX_MPDU_INFO_PN_GET_BYTE3(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[5] = HAL_RX_MPDU_INFO_PN_GET_BYTE4(desc->u.qcc2072.mpdu_start.pn[0]); + crypto_hdr[6] = HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcc2072.mpdu_start.pn[1]); + crypto_hdr[7] = HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcc2072.mpdu_start.pn[1]); +} + +static void ath12k_hal_rx_desc_copy_end_tlv_qcc2072(struct hal_rx_desc *fdesc, + struct hal_rx_desc *ldesc) +{ + memcpy(&fdesc->u.qcc2072.msdu_end, &ldesc->u.qcc2072.msdu_end, + sizeof(struct rx_msdu_end_qcn9274)); +} + +static u8 ath12k_hal_rx_desc_get_msdu_src_link_qcc2072(struct hal_rx_desc *desc) +{ + return 0; +} + +static u8 ath12k_hal_rx_desc_get_l3_pad_bytes_qcc2072(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcc2072.msdu_end.info5, + RX_MSDU_END_INFO5_L3_HDR_PADDING); +} + +static u32 ath12k_hal_rx_desc_get_mpdu_start_tag_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.mpdu_start_tag, + HAL_TLV_HDR_TAG); +} + +static u32 ath12k_hal_rx_desc_get_mpdu_ppdu_id_qcc2072(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcc2072.mpdu_start.phy_ppdu_id); +} + +static u8 *ath12k_hal_rx_desc_get_msdu_payload_qcc2072(struct hal_rx_desc *desc) +{ + return &desc->u.qcc2072.msdu_payload[0]; +} + +static bool ath12k_hal_rx_desc_get_first_msdu_qcc2072(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcc2072.msdu_end.info5, + RX_MSDU_END_INFO5_FIRST_MSDU); +} + +static bool ath12k_hal_rx_desc_get_last_msdu_qcc2072(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcc2072.msdu_end.info5, + RX_MSDU_END_INFO5_LAST_MSDU); +} + +static bool ath12k_hal_rx_desc_encrypt_valid_qcc2072(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.mpdu_start.info4, + RX_MPDU_START_INFO4_ENCRYPT_INFO_VALID); +} + +static u32 ath12k_hal_rx_desc_get_encrypt_type_qcc2072(struct hal_rx_desc *desc) +{ + if (!ath12k_hal_rx_desc_encrypt_valid_qcc2072(desc)) + return HAL_ENCRYPT_TYPE_OPEN; + + return le32_get_bits(desc->u.qcc2072.mpdu_start.info2, + RX_MPDU_START_INFO2_ENC_TYPE); +} + +static u8 ath12k_hal_rx_desc_get_decap_type_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.msdu_end.info11, + RX_MSDU_END_INFO11_DECAP_FORMAT); +} + +static u8 ath12k_hal_rx_desc_get_mesh_ctl_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.msdu_end.info11, + RX_MSDU_END_INFO11_MESH_CTRL_PRESENT); +} + +static bool ath12k_hal_rx_desc_get_mpdu_seq_ctl_vld_qcc2072(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_CTRL_VALID); +} + +static bool ath12k_hal_rx_desc_get_mpdu_fc_valid_qcc2072(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_FCTRL_VALID); +} + +static u16 ath12k_hal_rx_desc_get_mpdu_start_seq_no_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_NUM); +} + +static u16 ath12k_hal_rx_desc_get_msdu_len_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.msdu_end.info10, + RX_MSDU_END_INFO10_MSDU_LENGTH); +} + +static u8 ath12k_hal_rx_desc_get_msdu_sgi_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_SGI); +} + +static u8 ath12k_hal_rx_desc_get_msdu_rate_mcs_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_RATE_MCS); +} + +static u8 ath12k_hal_rx_desc_get_msdu_rx_bw_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_RECV_BW); +} + +static u32 ath12k_hal_rx_desc_get_msdu_freq_qcc2072(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcc2072.msdu_end.phy_meta_data); +} + +static u8 ath12k_hal_rx_desc_get_msdu_pkt_type_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_PKT_TYPE); +} + +static u8 ath12k_hal_rx_desc_get_msdu_nss_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.msdu_end.info12, + RX_MSDU_END_INFO12_MIMO_SS_BITMAP); +} + +static u8 ath12k_hal_rx_desc_get_mpdu_tid_qcc2072(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcc2072.mpdu_start.info2, + RX_MPDU_START_INFO2_TID); +} + +static u16 ath12k_hal_rx_desc_get_mpdu_peer_id_qcc2072(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcc2072.mpdu_start.sw_peer_id); +} + +static bool ath12k_hal_rx_desc_mac_addr2_valid_qcc2072(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcc2072.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR2_VALID; +} + +static u8 *ath12k_hal_rx_desc_mpdu_start_addr2_qcc2072(struct hal_rx_desc *desc) +{ + return desc->u.qcc2072.mpdu_start.addr2; +} + +static bool ath12k_hal_rx_desc_is_da_mcbc_qcc2072(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcc2072.msdu_end.info13) & + RX_MSDU_END_INFO13_MCAST_BCAST; +} + +static bool ath12k_hal_rx_h_msdu_done_qcc2072(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.msdu_end.info14, + RX_MSDU_END_INFO14_MSDU_DONE); +} + +static bool ath12k_hal_rx_h_l4_cksum_fail_qcc2072(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.msdu_end.info13, + RX_MSDU_END_INFO13_TCP_UDP_CKSUM_FAIL); +} + +static bool ath12k_hal_rx_h_ip_cksum_fail_qcc2072(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcc2072.msdu_end.info13, + RX_MSDU_END_INFO13_IP_CKSUM_FAIL); +} + +static bool ath12k_hal_rx_h_is_decrypted_qcc2072(struct hal_rx_desc *desc) +{ + return (le32_get_bits(desc->u.qcc2072.msdu_end.info14, + RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE) == + RX_DESC_DECRYPT_STATUS_CODE_OK); +} + +static u32 ath12k_hal_rx_h_mpdu_err_qcc2072(struct hal_rx_desc *desc) +{ + u32 info = __le32_to_cpu(desc->u.qcc2072.msdu_end.info13); + u32 errmap = 0; + + if (info & RX_MSDU_END_INFO13_FCS_ERR) + errmap |= HAL_RX_MPDU_ERR_FCS; + + if (info & RX_MSDU_END_INFO13_DECRYPT_ERR) + errmap |= HAL_RX_MPDU_ERR_DECRYPT; + + if (info & RX_MSDU_END_INFO13_TKIP_MIC_ERR) + errmap |= HAL_RX_MPDU_ERR_TKIP_MIC; + + if (info & RX_MSDU_END_INFO13_A_MSDU_ERROR) + errmap |= HAL_RX_MPDU_ERR_AMSDU_ERR; + + if (info & RX_MSDU_END_INFO13_OVERFLOW_ERR) + errmap |= HAL_RX_MPDU_ERR_OVERFLOW; + + if (info & RX_MSDU_END_INFO13_MSDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MSDU_LEN; + + if (info & RX_MSDU_END_INFO13_MPDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MPDU_LEN; + + return errmap; +} + +static void ath12k_hal_extract_rx_desc_data_qcc2072(struct hal_rx_desc_data *rx_desc_data, + struct hal_rx_desc *rx_desc, + struct hal_rx_desc *ldesc) +{ + rx_desc_data->is_first_msdu = ath12k_hal_rx_desc_get_first_msdu_qcc2072(ldesc); + rx_desc_data->is_last_msdu = ath12k_hal_rx_desc_get_last_msdu_qcc2072(ldesc); + rx_desc_data->l3_pad_bytes = ath12k_hal_rx_desc_get_l3_pad_bytes_qcc2072(ldesc); + rx_desc_data->enctype = ath12k_hal_rx_desc_get_encrypt_type_qcc2072(rx_desc); + rx_desc_data->decap_type = ath12k_hal_rx_desc_get_decap_type_qcc2072(rx_desc); + rx_desc_data->mesh_ctrl_present = + ath12k_hal_rx_desc_get_mesh_ctl_qcc2072(rx_desc); + rx_desc_data->seq_ctl_valid = + ath12k_hal_rx_desc_get_mpdu_seq_ctl_vld_qcc2072(rx_desc); + rx_desc_data->fc_valid = ath12k_hal_rx_desc_get_mpdu_fc_valid_qcc2072(rx_desc); + rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_qcc2072(rx_desc); + rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_qcc2072(ldesc); + rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_qcc2072(rx_desc); + rx_desc_data->rate_mcs = ath12k_hal_rx_desc_get_msdu_rate_mcs_qcc2072(rx_desc); + rx_desc_data->bw = ath12k_hal_rx_desc_get_msdu_rx_bw_qcc2072(rx_desc); + rx_desc_data->phy_meta_data = ath12k_hal_rx_desc_get_msdu_freq_qcc2072(rx_desc); + rx_desc_data->pkt_type = ath12k_hal_rx_desc_get_msdu_pkt_type_qcc2072(rx_desc); + rx_desc_data->nss = hweight8(ath12k_hal_rx_desc_get_msdu_nss_qcc2072(rx_desc)); + rx_desc_data->tid = ath12k_hal_rx_desc_get_mpdu_tid_qcc2072(rx_desc); + rx_desc_data->peer_id = ath12k_hal_rx_desc_get_mpdu_peer_id_qcc2072(rx_desc); + rx_desc_data->addr2_present = ath12k_hal_rx_desc_mac_addr2_valid_qcc2072(rx_desc); + rx_desc_data->addr2 = ath12k_hal_rx_desc_mpdu_start_addr2_qcc2072(rx_desc); + rx_desc_data->is_mcbc = ath12k_hal_rx_desc_is_da_mcbc_qcc2072(rx_desc); + rx_desc_data->msdu_done = ath12k_hal_rx_h_msdu_done_qcc2072(ldesc); + rx_desc_data->l4_csum_fail = ath12k_hal_rx_h_l4_cksum_fail_qcc2072(rx_desc); + rx_desc_data->ip_csum_fail = ath12k_hal_rx_h_ip_cksum_fail_qcc2072(rx_desc); + rx_desc_data->is_decrypted = ath12k_hal_rx_h_is_decrypted_qcc2072(rx_desc); + rx_desc_data->err_bitmap = ath12k_hal_rx_h_mpdu_err_qcc2072(rx_desc); +} + +static int ath12k_hal_srng_create_config_qcc2072(struct ath12k_hal *hal) +{ + struct hal_srng_config *s; + int ret; + + ret = ath12k_hal_srng_create_config_wcn7850(hal); + if (ret) + return ret; + + s = &hal->srng_config[HAL_REO_CMD]; + s->entry_size = (sizeof(struct hal_tlv_hdr) + + sizeof(struct hal_reo_get_queue_stats_qcc2072)) >> 2; + + s = &hal->srng_config[HAL_REO_STATUS]; + s->entry_size = (sizeof(struct hal_tlv_hdr) + + sizeof(struct hal_reo_get_queue_stats_status_qcc2072)) >> 2; + + return 0; +} + +static u16 ath12k_hal_reo_status_dec_tlv_hdr_qcc2072(void *tlv, void **desc) +{ + struct hal_reo_get_queue_stats_status_qcc2072 *status_tlv; + u16 tag; + + tag = ath12k_hal_decode_tlv32_hdr(tlv, (void **)&status_tlv); + /* + * actual desc of REO status entry starts after tlv32_padding, + * see hal_reo_get_queue_stats_status_qcc2072 + */ + *desc = &status_tlv->status; + + return tag; +} + +const struct hal_ops hal_qcc2072_ops = { + .create_srng_config = ath12k_hal_srng_create_config_qcc2072, + .rx_desc_set_msdu_len = ath12k_hal_rx_desc_set_msdu_len_qcc2072, + .rx_desc_get_dot11_hdr = ath12k_hal_rx_desc_get_dot11_hdr_qcc2072, + .rx_desc_get_crypto_header = ath12k_hal_rx_desc_get_crypto_hdr_qcc2072, + .rx_desc_copy_end_tlv = ath12k_hal_rx_desc_copy_end_tlv_qcc2072, + .rx_desc_get_msdu_src_link_id = ath12k_hal_rx_desc_get_msdu_src_link_qcc2072, + .extract_rx_desc_data = ath12k_hal_extract_rx_desc_data_qcc2072, + .rx_desc_get_l3_pad_bytes = ath12k_hal_rx_desc_get_l3_pad_bytes_qcc2072, + .rx_desc_get_mpdu_start_tag = ath12k_hal_rx_desc_get_mpdu_start_tag_qcc2072, + .rx_desc_get_mpdu_ppdu_id = ath12k_hal_rx_desc_get_mpdu_ppdu_id_qcc2072, + .rx_desc_get_msdu_payload = ath12k_hal_rx_desc_get_msdu_payload_qcc2072, + .ce_dst_setup = ath12k_wifi7_hal_ce_dst_setup, + .srng_src_hw_init = ath12k_wifi7_hal_srng_src_hw_init, + .srng_dst_hw_init = ath12k_wifi7_hal_srng_dst_hw_init, + .set_umac_srng_ptr_addr = ath12k_wifi7_hal_set_umac_srng_ptr_addr, + .srng_update_shadow_config = ath12k_wifi7_hal_srng_update_shadow_config, + .srng_get_ring_id = ath12k_wifi7_hal_srng_get_ring_id, + .ce_get_desc_size = ath12k_wifi7_hal_ce_get_desc_size, + .ce_src_set_desc = ath12k_wifi7_hal_ce_src_set_desc, + .ce_dst_set_desc = ath12k_wifi7_hal_ce_dst_set_desc, + .ce_dst_status_get_length = ath12k_wifi7_hal_ce_dst_status_get_length, + .set_link_desc_addr = ath12k_wifi7_hal_set_link_desc_addr, + .tx_set_dscp_tid_map = ath12k_wifi7_hal_tx_set_dscp_tid_map, + .tx_configure_bank_register = + ath12k_wifi7_hal_tx_configure_bank_register, + .reoq_lut_addr_read_enable = ath12k_wifi7_hal_reoq_lut_addr_read_enable, + .reoq_lut_set_max_peerid = ath12k_wifi7_hal_reoq_lut_set_max_peerid, + .write_reoq_lut_addr = ath12k_wifi7_hal_write_reoq_lut_addr, + .write_ml_reoq_lut_addr = ath12k_wifi7_hal_write_ml_reoq_lut_addr, + .setup_link_idle_list = ath12k_wifi7_hal_setup_link_idle_list, + .reo_init_cmd_ring = ath12k_wifi7_hal_reo_init_cmd_ring_tlv32, + .reo_hw_setup = ath12k_wifi7_hal_reo_hw_setup, + .rx_buf_addr_info_set = ath12k_wifi7_hal_rx_buf_addr_info_set, + .rx_buf_addr_info_get = ath12k_wifi7_hal_rx_buf_addr_info_get, + .cc_config = ath12k_wifi7_hal_cc_config, + .get_idle_link_rbm = ath12k_wifi7_hal_get_idle_link_rbm, + .rx_msdu_list_get = ath12k_wifi7_hal_rx_msdu_list_get, + .rx_reo_ent_buf_paddr_get = ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get, + .reo_cmd_enc_tlv_hdr = ath12k_hal_encode_tlv32_hdr, + .reo_status_dec_tlv_hdr = ath12k_hal_reo_status_dec_tlv_hdr_qcc2072, +}; + +u32 ath12k_hal_rx_desc_get_mpdu_start_offset_qcc2072(void) +{ + return offsetof(struct hal_rx_desc_qcc2072, mpdu_start_tag); +} + +u32 ath12k_hal_rx_desc_get_msdu_end_offset_qcc2072(void) +{ + return offsetof(struct hal_rx_desc_qcc2072, msdu_end_tag); +} diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.h new file mode 100644 index 000000000000..6de943df7786 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include "../hal.h" +#include "hal.h" + +extern const struct ath12k_hw_regs qcc2072_regs; +extern const struct hal_ops hal_qcc2072_ops; + +u32 ath12k_hal_rx_desc_get_mpdu_start_offset_qcc2072(void); +u32 ath12k_hal_rx_desc_get_msdu_end_offset_qcc2072(void); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c index c129e937132b..41c918eb1767 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c @@ -297,6 +297,8 @@ const struct ath12k_hw_regs qcn9274_v1_regs = { .umac_ce1_dest_reg_base = 0x01b83000, .gcc_gcc_pcie_hot_rst = 0x1e38338, + + .qrtr_node_id = 0x1e03164, }; const struct ath12k_hw_regs qcn9274_v2_regs = { @@ -390,6 +392,8 @@ const struct ath12k_hw_regs qcn9274_v2_regs = { .umac_ce1_dest_reg_base = 0x01b83000, .gcc_gcc_pcie_hot_rst = 0x1e38338, + + .qrtr_node_id = 0x1e03164, }; const struct ath12k_hw_regs ipq5332_regs = { @@ -1020,7 +1024,7 @@ const struct hal_ops hal_qcn9274_ops = { .write_reoq_lut_addr = ath12k_wifi7_hal_write_reoq_lut_addr, .write_ml_reoq_lut_addr = ath12k_wifi7_hal_write_ml_reoq_lut_addr, .setup_link_idle_list = ath12k_wifi7_hal_setup_link_idle_list, - .reo_init_cmd_ring = ath12k_wifi7_hal_reo_init_cmd_ring, + .reo_init_cmd_ring = ath12k_wifi7_hal_reo_init_cmd_ring_tlv64, .reo_hw_setup = ath12k_wifi7_hal_reo_hw_setup, .reo_shared_qaddr_cache_clear = ath12k_wifi7_hal_reo_shared_qaddr_cache_clear, .rx_buf_addr_info_set = ath12k_wifi7_hal_rx_buf_addr_info_set, @@ -1029,4 +1033,6 @@ const struct hal_ops hal_qcn9274_ops = { .get_idle_link_rbm = ath12k_wifi7_hal_get_idle_link_rbm, .rx_msdu_list_get = ath12k_wifi7_hal_rx_msdu_list_get, .rx_reo_ent_buf_paddr_get = ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get, + .reo_cmd_enc_tlv_hdr = ath12k_hal_encode_tlv64_hdr, + .reo_status_dec_tlv_hdr = ath12k_hal_decode_tlv64_hdr, }; diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c index 903fb52a03bf..49c693289709 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c @@ -23,15 +23,13 @@ void ath12k_wifi7_hal_reo_set_desc_hdr(struct hal_desc_header *hdr, hdr->info0 |= le32_encode_bits(magic, HAL_DESC_HDR_INFO0_DBG_RESERVED); } -static int ath12k_wifi7_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv, +static int ath12k_wifi7_hal_reo_cmd_queue_stats(struct ath12k_hal *hal, void *tlv, struct ath12k_hal_reo_cmd *cmd) { struct hal_reo_get_queue_stats *desc; - tlv->tl = le64_encode_bits(HAL_REO_GET_QUEUE_STATS, HAL_TLV_HDR_TAG) | - le64_encode_bits(sizeof(*desc), HAL_TLV_HDR_LEN); - - desc = (struct hal_reo_get_queue_stats *)tlv->value; + desc = hal->ops->reo_cmd_enc_tlv_hdr(tlv, HAL_REO_GET_QUEUE_STATS, + sizeof(*desc)); memset_startat(desc, 0, queue_addr_lo); desc->cmd.info0 &= ~cpu_to_le32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED); @@ -47,8 +45,7 @@ static int ath12k_wifi7_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv, return le32_get_bits(desc->cmd.info0, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); } -static int ath12k_wifi7_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, - struct hal_tlv_64_hdr *tlv, +static int ath12k_wifi7_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, void *tlv, struct ath12k_hal_reo_cmd *cmd) { struct hal_reo_flush_cache *desc; @@ -61,10 +58,8 @@ static int ath12k_wifi7_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, hal->current_blk_index = avail_slot; } - tlv->tl = le64_encode_bits(HAL_REO_FLUSH_CACHE, HAL_TLV_HDR_TAG) | - le64_encode_bits(sizeof(*desc), HAL_TLV_HDR_LEN); - - desc = (struct hal_reo_flush_cache *)tlv->value; + desc = hal->ops->reo_cmd_enc_tlv_hdr(tlv, HAL_REO_FLUSH_CACHE, + sizeof(*desc)); memset_startat(desc, 0, cache_addr_lo); desc->cmd.info0 &= ~cpu_to_le32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED); @@ -98,15 +93,13 @@ static int ath12k_wifi7_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, } static int -ath12k_wifi7_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv, +ath12k_wifi7_hal_reo_cmd_update_rx_queue(struct ath12k_hal *hal, void *tlv, struct ath12k_hal_reo_cmd *cmd) { struct hal_reo_update_rx_queue *desc; - tlv->tl = le64_encode_bits(HAL_REO_UPDATE_RX_REO_QUEUE, HAL_TLV_HDR_TAG) | - le64_encode_bits(sizeof(*desc), HAL_TLV_HDR_LEN); - - desc = (struct hal_reo_update_rx_queue *)tlv->value; + desc = hal->ops->reo_cmd_enc_tlv_hdr(tlv, HAL_REO_UPDATE_RX_REO_QUEUE, + sizeof(*desc)); memset_startat(desc, 0, queue_addr_lo); desc->cmd.info0 &= ~cpu_to_le32(HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED); @@ -227,7 +220,8 @@ int ath12k_wifi7_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng, enum hal_reo_cmd_type type, struct ath12k_hal_reo_cmd *cmd) { - struct hal_tlv_64_hdr *reo_desc; + struct ath12k_hal *hal = &ab->hal; + void *reo_desc; int ret; spin_lock_bh(&srng->lock); @@ -241,14 +235,13 @@ int ath12k_wifi7_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng, switch (type) { case HAL_REO_CMD_GET_QUEUE_STATS: - ret = ath12k_wifi7_hal_reo_cmd_queue_stats(reo_desc, cmd); + ret = ath12k_wifi7_hal_reo_cmd_queue_stats(hal, reo_desc, cmd); break; case HAL_REO_CMD_FLUSH_CACHE: - ret = ath12k_wifi7_hal_reo_cmd_flush_cache(&ab->hal, reo_desc, - cmd); + ret = ath12k_wifi7_hal_reo_cmd_flush_cache(hal, reo_desc, cmd); break; case HAL_REO_CMD_UPDATE_RX_QUEUE: - ret = ath12k_wifi7_hal_reo_cmd_update_rx_queue(reo_desc, cmd); + ret = ath12k_wifi7_hal_reo_cmd_update_rx_queue(hal, reo_desc, cmd); break; case HAL_REO_CMD_FLUSH_QUEUE: case HAL_REO_CMD_UNBLOCK_CACHE: @@ -550,12 +543,9 @@ ath12k_wifi7_hal_rx_msdu_link_desc_set(struct ath12k_base *ab, } void ath12k_wifi7_hal_reo_status_queue_stats(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_get_queue_stats_status *desc, struct hal_reo_status *status) { - struct hal_reo_get_queue_stats_status *desc = - (struct hal_reo_get_queue_stats_status *)tlv->value; - status->uniform_hdr.cmd_num = le32_get_bits(desc->hdr.info0, HAL_REO_STATUS_HDR_INFO0_STATUS_NUM); @@ -614,12 +604,9 @@ void ath12k_wifi7_hal_reo_status_queue_stats(struct ath12k_base *ab, } void ath12k_wifi7_hal_reo_flush_queue_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_flush_queue_status *desc, struct hal_reo_status *status) { - struct hal_reo_flush_queue_status *desc = - (struct hal_reo_flush_queue_status *)tlv->value; - status->uniform_hdr.cmd_num = le32_get_bits(desc->hdr.info0, HAL_REO_STATUS_HDR_INFO0_STATUS_NUM); @@ -633,12 +620,10 @@ void ath12k_wifi7_hal_reo_flush_queue_status(struct ath12k_base *ab, void ath12k_wifi7_hal_reo_flush_cache_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_flush_cache_status *desc, struct hal_reo_status *status) { struct ath12k_hal *hal = &ab->hal; - struct hal_reo_flush_cache_status *desc = - (struct hal_reo_flush_cache_status *)tlv->value; status->uniform_hdr.cmd_num = le32_get_bits(desc->hdr.info0, @@ -675,12 +660,10 @@ ath12k_wifi7_hal_reo_flush_cache_status(struct ath12k_base *ab, } void ath12k_wifi7_hal_reo_unblk_cache_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_unblock_cache_status *desc, struct hal_reo_status *status) { struct ath12k_hal *hal = &ab->hal; - struct hal_reo_unblock_cache_status *desc = - (struct hal_reo_unblock_cache_status *)tlv->value; status->uniform_hdr.cmd_num = le32_get_bits(desc->hdr.info0, @@ -704,12 +687,9 @@ void ath12k_wifi7_hal_reo_unblk_cache_status(struct ath12k_base *ab, void ath12k_wifi7_hal_reo_flush_timeout_list_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_flush_timeout_list_status *desc, struct hal_reo_status *status) { - struct hal_reo_flush_timeout_list_status *desc = - (struct hal_reo_flush_timeout_list_status *)tlv->value; - status->uniform_hdr.cmd_num = le32_get_bits(desc->hdr.info0, HAL_REO_STATUS_HDR_INFO0_STATUS_NUM); @@ -734,12 +714,9 @@ ath12k_wifi7_hal_reo_flush_timeout_list_status(struct ath12k_base *ab, void ath12k_wifi7_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_desc_thresh_reached_status *desc, struct hal_reo_status *status) { - struct hal_reo_desc_thresh_reached_status *desc = - (struct hal_reo_desc_thresh_reached_status *)tlv->value; - status->uniform_hdr.cmd_num = le32_get_bits(desc->hdr.info0, HAL_REO_STATUS_HDR_INFO0_STATUS_NUM); @@ -769,12 +746,9 @@ ath12k_wifi7_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab, } void ath12k_wifi7_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_status_hdr *desc, struct hal_reo_status *status) { - struct hal_reo_status_hdr *desc = - (struct hal_reo_status_hdr *)tlv->value; - status->uniform_hdr.cmd_num = le32_get_bits(desc->info0, HAL_REO_STATUS_HDR_INFO0_STATUS_NUM); @@ -891,8 +865,8 @@ void ath12k_wifi7_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3); } -void ath12k_wifi7_hal_reo_init_cmd_ring(struct ath12k_base *ab, - struct hal_srng *srng) +void ath12k_wifi7_hal_reo_init_cmd_ring_tlv64(struct ath12k_base *ab, + struct hal_srng *srng) { struct hal_srng_params params; struct hal_tlv_64_hdr *tlv; @@ -916,6 +890,31 @@ void ath12k_wifi7_hal_reo_init_cmd_ring(struct ath12k_base *ab, } } +void ath12k_wifi7_hal_reo_init_cmd_ring_tlv32(struct ath12k_base *ab, + struct hal_srng *srng) +{ + struct hal_reo_get_queue_stats *desc; + struct hal_srng_params params; + struct hal_tlv_hdr *tlv; + int i, cmd_num = 1; + int entry_size; + u8 *entry; + + memset(¶ms, 0, sizeof(params)); + + entry_size = ath12k_hal_srng_get_entrysize(ab, HAL_REO_CMD); + ath12k_hal_srng_get_params(ab, srng, ¶ms); + entry = (u8 *)params.ring_base_vaddr; + + for (i = 0; i < params.num_entries; i++) { + tlv = (struct hal_tlv_hdr *)entry; + desc = (struct hal_reo_get_queue_stats *)tlv->value; + desc->cmd.info0 = le32_encode_bits(cmd_num++, + HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); + entry += entry_size; + } +} + void ath12k_wifi7_hal_reo_hw_setup(struct ath12k_base *ab, u32 ring_hash_map) { struct ath12k_hal *hal = &ab->hal; diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.h index 8a0f4a781d8a..ac2a8ac03288 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_rx.h @@ -813,25 +813,27 @@ enum hal_mon_reception_type { (HAL_RU(ru_per80, num_80mhz, ru_idx_per80mhz)) void ath12k_wifi7_hal_reo_status_queue_stats(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_get_queue_stats_status *desc, struct hal_reo_status *status); void ath12k_wifi7_hal_reo_flush_queue_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_flush_queue_status *desc, struct hal_reo_status *status); void ath12k_wifi7_hal_reo_flush_cache_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_flush_cache_status *desc, struct hal_reo_status *status); void ath12k_wifi7_hal_reo_unblk_cache_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_unblock_cache_status *desc, struct hal_reo_status *status); -void ath12k_wifi7_hal_reo_flush_timeout_list_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, - struct hal_reo_status *status); -void ath12k_wifi7_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, - struct hal_reo_status *status); +void +ath12k_wifi7_hal_reo_flush_timeout_list_status(struct ath12k_base *ab, + struct hal_reo_flush_timeout_list_status *desc, + struct hal_reo_status *status); +void +ath12k_wifi7_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab, + struct hal_reo_desc_thresh_reached_status *desc, + struct hal_reo_status *status); void ath12k_wifi7_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab, - struct hal_tlv_64_hdr *tlv, + struct hal_reo_status_hdr *desc, struct hal_reo_status *status); void ath12k_wifi7_hal_rx_msdu_link_info_get(struct hal_rx_msdu_link *link, u32 *num_msdus, u32 *msdu_cookies, @@ -860,8 +862,10 @@ void ath12k_wifi7_hal_rx_msdu_list_get(struct ath12k *ar, void *link_desc, void *msdu_list_opaque, u16 *num_msdus); -void ath12k_wifi7_hal_reo_init_cmd_ring(struct ath12k_base *ab, - struct hal_srng *srng); +void ath12k_wifi7_hal_reo_init_cmd_ring_tlv64(struct ath12k_base *ab, + struct hal_srng *srng); +void ath12k_wifi7_hal_reo_init_cmd_ring_tlv32(struct ath12k_base *ab, + struct hal_srng *srng); void ath12k_wifi7_hal_reo_shared_qaddr_cache_clear(struct ath12k_base *ab); void ath12k_wifi7_hal_reo_hw_setup(struct ath12k_base *ab, u32 ring_hash_map); void ath12k_wifi7_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_rx_desc.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_rx_desc.h index cc5e1d336376..0d19a9cbb68c 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_rx_desc.h @@ -1481,10 +1481,27 @@ struct hal_rx_desc_wcn7850 { u8 msdu_payload[]; }; +struct rx_pkt_hdr_tlv_qcc2072 { + __le32 tag; + __le64 phy_ppdu_id; + u8 rx_pkt_hdr[HAL_RX_BE_PKT_HDR_TLV_LEN]; +}; + +struct hal_rx_desc_qcc2072 { + __le32 msdu_end_tag; + struct rx_msdu_end_qcn9274 msdu_end; + u8 rx_padding0[RX_BE_PADDING0_BYTES]; + __le32 mpdu_start_tag; + struct rx_mpdu_start_qcn9274 mpdu_start; + struct rx_pkt_hdr_tlv_qcc2072 pkt_hdr_tlv; + u8 msdu_payload[]; +}; + struct hal_rx_desc { union { struct hal_rx_desc_qcn9274_compact qcn9274_compact; struct hal_rx_desc_wcn7850 wcn7850; + struct hal_rx_desc_qcc2072 qcc2072; } u; } __packed; diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c index 7108cc41536d..e64e512cac7d 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c @@ -256,6 +256,8 @@ const struct ath12k_hw_regs wcn7850_regs = { .umac_ce1_dest_reg_base = 0x01b83000, .gcc_gcc_pcie_hot_rst = 0x1e40304, + + .qrtr_node_id = 0x1e03164, }; static inline @@ -614,7 +616,7 @@ void ath12k_hal_extract_rx_desc_data_wcn7850(struct hal_rx_desc_data *rx_desc_da rx_desc_data->err_bitmap = ath12k_hal_rx_h_mpdu_err_wcn7850(rx_desc); } -static int ath12k_hal_srng_create_config_wcn7850(struct ath12k_hal *hal) +int ath12k_hal_srng_create_config_wcn7850(struct ath12k_hal *hal) { struct hal_srng_config *s; @@ -793,7 +795,7 @@ const struct hal_ops hal_wcn7850_ops = { .write_reoq_lut_addr = ath12k_wifi7_hal_write_reoq_lut_addr, .write_ml_reoq_lut_addr = ath12k_wifi7_hal_write_ml_reoq_lut_addr, .setup_link_idle_list = ath12k_wifi7_hal_setup_link_idle_list, - .reo_init_cmd_ring = ath12k_wifi7_hal_reo_init_cmd_ring, + .reo_init_cmd_ring = ath12k_wifi7_hal_reo_init_cmd_ring_tlv64, .reo_shared_qaddr_cache_clear = ath12k_wifi7_hal_reo_shared_qaddr_cache_clear, .reo_hw_setup = ath12k_wifi7_hal_reo_hw_setup, .rx_buf_addr_info_set = ath12k_wifi7_hal_rx_buf_addr_info_set, @@ -802,4 +804,6 @@ const struct hal_ops hal_wcn7850_ops = { .get_idle_link_rbm = ath12k_wifi7_hal_get_idle_link_rbm, .rx_msdu_list_get = ath12k_wifi7_hal_rx_msdu_list_get, .rx_reo_ent_buf_paddr_get = ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get, + .reo_cmd_enc_tlv_hdr = ath12k_hal_encode_tlv64_hdr, + .reo_status_dec_tlv_hdr = ath12k_hal_decode_tlv64_hdr, }; diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.h index 46047fd6a312..a56ca9fd3de4 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.h @@ -36,4 +36,5 @@ void ath12k_hal_rx_desc_get_dot11_hdr_wcn7850(struct hal_rx_desc *desc, void ath12k_hal_extract_rx_desc_data_wcn7850(struct hal_rx_desc_data *rx_desc_data, struct hal_rx_desc *rx_desc, struct hal_rx_desc *ldesc); +int ath12k_hal_srng_create_config_wcn7850(struct ath12k_hal *hal); #endif diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c index 8ac06b2fc18f..df045ddf42da 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c @@ -170,6 +170,16 @@ static const struct ath12k_hw_ops wcn7850_ops = { .is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850, }; +static const struct ath12k_hw_ops qcc2072_ops = { + .get_hw_mac_from_pdev_id = ath12k_wifi7_hw_qcn9274_mac_from_pdev_id, + .mac_id_to_pdev_id = ath12k_wifi7_hw_mac_id_to_pdev_id_wcn7850, + .mac_id_to_srng_id = ath12k_wifi7_hw_mac_id_to_srng_id_wcn7850, + .rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_qcc2072, + .get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850, + .dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850, + .is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850, +}; + #define ATH12K_TX_RING_MASK_0 0x1 #define ATH12K_TX_RING_MASK_1 0x2 #define ATH12K_TX_RING_MASK_2 0x4 @@ -339,6 +349,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, + .download_aux_ucode = false, }, .max_radios = 1, .single_pdev_only = false, @@ -421,6 +432,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 256 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, + .download_aux_ucode = false, }, .max_radios = 1, @@ -505,6 +517,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, .m3_loader = ath12k_m3_fw_loader_driver, + .download_aux_ucode = false, }, .max_radios = 2, .single_pdev_only = false, @@ -586,6 +599,7 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, .m3_loader = ath12k_m3_fw_loader_remoteproc, + .download_aux_ucode = false, }, .max_radios = 1, .single_pdev_only = false, @@ -652,6 +666,93 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = { .dp_primary_link_only = true, }, + { + .name = "qcc2072 hw1.0", + .hw_rev = ATH12K_HW_QCC2072_HW10, + + .fw = { + .dir = "QCC2072/hw1.0", + .board_size = 256 * 1024, + .cal_offset = 256 * 1024, + .m3_loader = ath12k_m3_fw_loader_driver, + .download_aux_ucode = true, + }, + + .max_radios = 1, + .single_pdev_only = true, + .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_WCN7850, + .internal_sleep_clock = true, + + .hw_ops = &qcc2072_ops, + .ring_mask = &ath12k_wifi7_hw_ring_mask_wcn7850, + + .host_ce_config = ath12k_wifi7_host_ce_config_wcn7850, + .ce_count = 9, + .target_ce_config = ath12k_wifi7_target_ce_config_wlan_wcn7850, + .target_ce_count = 9, + .svc_to_ce_map = + ath12k_wifi7_target_service_to_ce_map_wlan_wcn7850, + .svc_to_ce_map_len = 14, + + .rxdma1_enable = false, + .num_rxdma_per_pdev = 2, + .num_rxdma_dst_ring = 1, + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), + .supports_monitor = true, + + .idle_ps = true, + .download_calib = false, + .supports_suspend = true, + .tcl_ring_retry = false, + .reoq_lut_support = false, + .supports_shadow_regs = true, + + .num_tcl_banks = 7, + .max_tx_ring = 3, + + .mhi_config = &ath12k_wifi7_mhi_config_wcn7850, + + .wmi_init = ath12k_wifi7_wmi_init_wcn7850, + + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) | + BIT(CNSS_PCIE_PERST_NO_PULL_V01) | + BIT(CNSS_AUX_UC_SUPPORT_V01), + + .rfkill_pin = 0, + .rfkill_cfg = 0, + .rfkill_on_level = 0, + + .rddm_size = 0x780000, + + .def_num_link = 2, + .max_mlo_peer = 32, + + .otp_board_id_register = 0, + + .supports_sta_ps = true, + + .acpi_guid = &wcn7850_uuid, + .supports_dynamic_smps_6ghz = false, + + .iova_mask = 0, + + .supports_aspm = true, + + .ce_ie_addr = NULL, + .ce_remap = NULL, + .bdf_addr_offset = 0, + + .current_cc_support = true, + + .dp_primary_link_only = false, + }, }; /* Note: called under rcu_read_lock() */ diff --git a/drivers/net/wireless/ath/ath12k/wifi7/pci.c b/drivers/net/wireless/ath/ath12k/wifi7/pci.c index dedc88858bb0..6c96b52dec13 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/pci.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/pci.c @@ -19,6 +19,7 @@ #define QCN9274_DEVICE_ID 0x1109 #define WCN7850_DEVICE_ID 0x1107 +#define QCC2072_DEVICE_ID 0x1112 #define ATH12K_PCI_W7_SOC_HW_VERSION_1 1 #define ATH12K_PCI_W7_SOC_HW_VERSION_2 2 @@ -27,9 +28,13 @@ #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 4) +#define WINDOW_REG_ADDRESS 0x310c +#define WINDOW_REG_ADDRESS_QCC2072 0x3278 + static const struct pci_device_id ath12k_wifi7_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) }, + { PCI_VDEVICE(QCOM, QCC2072_DEVICE_ID) }, {} }; @@ -104,6 +109,11 @@ static int ath12k_wifi7_pci_probe(struct pci_dev *pdev, ab_pci->msi_config = &ath12k_wifi7_msi_config[0]; ab->static_window_map = true; ab_pci->pci_ops = &ath12k_wifi7_pci_ops_qcn9274; + /* + * init window reg addr before reading hardware version + * as it will be used there + */ + ab_pci->window_reg_addr = WINDOW_REG_ADDRESS; ath12k_wifi7_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); ab->target_mem_mode = ath12k_core_get_memory_mode(ab); @@ -126,6 +136,11 @@ static int ath12k_wifi7_pci_probe(struct pci_dev *pdev, ab_pci->msi_config = &ath12k_wifi7_msi_config[0]; ab->static_window_map = false; ab_pci->pci_ops = &ath12k_wifi7_pci_ops_wcn7850; + /* + * init window reg addr before reading hardware version + * as it will be used there + */ + ab_pci->window_reg_addr = WINDOW_REG_ADDRESS; ath12k_wifi7_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; @@ -140,7 +155,16 @@ static int ath12k_wifi7_pci_probe(struct pci_dev *pdev, return -EOPNOTSUPP; } break; - + case QCC2072_DEVICE_ID: + ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD; + ab_pci->msi_config = &ath12k_wifi7_msi_config[0]; + ab->static_window_map = false; + ab_pci->pci_ops = &ath12k_wifi7_pci_ops_wcn7850; + ab_pci->window_reg_addr = WINDOW_REG_ADDRESS_QCC2072; + ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; + /* there is only one version till now */ + ab->hw_rev = ATH12K_HW_QCC2072_HW10; + break; default: dev_err(&pdev->dev, "Unknown Wi-Fi 7 PCI device found: 0x%x\n", pci_dev->device); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/wmi.c b/drivers/net/wireless/ath/ath12k/wifi7/wmi.c index c575b44a33f3..ed538d20d324 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/wmi.c @@ -102,4 +102,9 @@ void ath12k_wifi7_wmi_init_wcn7850(struct ath12k_base *ab, config->num_multicast_filter_entries = 0x20; config->num_wow_filters = 0x16; config->num_keep_alive_pattern = 0; + + if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) + config->peer_metadata_ver = ATH12K_PEER_METADATA_V1A; + else + config->peer_metadata_ver = ab->wmi_ab.dp_peer_meta_data_ver; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 17ffc4822741..cce3d699112d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -399,6 +399,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, struct ath12k_band_cap *cap_band; struct ath12k_pdev_cap *pdev_cap = &pdev->cap; struct ath12k_fw_pdev *fw_pdev; + u32 supported_bands; u32 phy_map; u32 hw_idx, phy_idx = 0; int i; @@ -422,14 +423,19 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, return -EINVAL; mac_caps = wmi_mac_phy_caps + phy_idx; + supported_bands = le32_to_cpu(mac_caps->supported_bands); + + if (!(supported_bands & WMI_HOST_WLAN_2GHZ_CAP) && + !(supported_bands & WMI_HOST_WLAN_5GHZ_CAP)) + return -EINVAL; pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); pdev->hw_link_id = ath12k_wmi_mac_phy_get_hw_link_id(mac_caps); - pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); + pdev_cap->supported_bands |= supported_bands; pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density); fw_pdev = &ab->fw_pdev[ab->fw_pdev_count]; - fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands); + fw_pdev->supported_bands = supported_bands; fw_pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id); ab->fw_pdev_count++; @@ -438,10 +444,12 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, * band to band for a single radio, need to see how this should be * handled. */ - if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2GHZ_CAP) { + if (supported_bands & WMI_HOST_WLAN_2GHZ_CAP) { pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_2g); pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_2g); - } else if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5GHZ_CAP) { + } + + if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) { pdev_cap->vht_cap = le32_to_cpu(mac_caps->vht_cap_info_5g); pdev_cap->vht_mcs = le32_to_cpu(mac_caps->vht_supp_mcs_5g); pdev_cap->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g); @@ -451,8 +459,6 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, WMI_NSS_RATIO_EN_DIS_GET(mac_caps->nss_ratio); pdev_cap->nss_ratio_info = WMI_NSS_RATIO_INFO_GET(mac_caps->nss_ratio); - } else { - return -EINVAL; } /* tx/rx chainmask reported from fw depends on the actual hw chains used, @@ -468,7 +474,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, pdev_cap->rx_chain_mask_shift = find_first_bit((unsigned long *)&pdev_cap->rx_chain_mask, 32); - if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2GHZ_CAP) { + if (supported_bands & WMI_HOST_WLAN_2GHZ_CAP) { cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; cap_band->phy_id = le32_to_cpu(mac_caps->phy_id); cap_band->max_bw_supported = le32_to_cpu(mac_caps->max_bw_supported_2g); @@ -488,7 +494,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, le32_to_cpu(mac_caps->he_ppet2g.ppet16_ppet8_ru3_ru0[i]); } - if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5GHZ_CAP) { + if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) { cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; cap_band->phy_id = le32_to_cpu(mac_caps->phy_id); cap_band->max_bw_supported = @@ -2800,7 +2806,8 @@ int ath12k_wmi_send_scan_chan_list_cmd(struct ath12k *ar, max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) / sizeof(*chan_info); - num_send_chans = min(arg->nallchans, max_chan_limit); + num_send_chans = min3(arg->nallchans, max_chan_limit, + ATH12K_WMI_MAX_NUM_CHAN_PER_CMD); arg->nallchans -= num_send_chans; len += sizeof(*chan_info) * num_send_chans; @@ -4449,7 +4456,7 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc, pref = soc->wmi_ab.preferred_hw_mode; - if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) { + if (ath12k_hw_mode_pri_map[mode] <= ath12k_hw_mode_pri_map[pref]) { svc_rdy_ext->pref_hw_mode_caps = *hw_mode_caps; soc->wmi_ab.preferred_hw_mode = mode; } @@ -4918,19 +4925,10 @@ ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab, const struct ath12k_wmi_caps_ext_params *caps, struct ath12k_pdev *pdev) { - struct ath12k_band_cap *cap_band; - u32 bands, support_320mhz; + u32 bands; int i; if (ab->hw_params->single_pdev_only) { - if (caps->hw_mode_id == WMI_HOST_HW_MODE_SINGLE) { - support_320mhz = le32_to_cpu(caps->eht_cap_phy_info_5ghz[0]) & - IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; - cap_band = &pdev->cap.band[NL80211_BAND_6GHZ]; - cap_band->eht_cap_phy_info[0] |= support_320mhz; - return 0; - } - for (i = 0; i < ab->fw_pdev_count; i++) { struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i]; @@ -4983,14 +4981,22 @@ static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag, void *data) { const struct ath12k_wmi_caps_ext_params *caps = ptr; + struct ath12k_band_cap *cap_band; + u32 support_320mhz; int i = 0, ret; if (tag != WMI_TAG_MAC_PHY_CAPABILITIES_EXT) return -EPROTO; if (ab->hw_params->single_pdev_only) { - if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id) && - caps->hw_mode_id != WMI_HOST_HW_MODE_SINGLE) + if (caps->hw_mode_id == WMI_HOST_HW_MODE_SINGLE) { + support_320mhz = le32_to_cpu(caps->eht_cap_phy_info_5ghz[0]) & + IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + cap_band = &ab->pdevs[0].cap.band[NL80211_BAND_6GHZ]; + cap_band->eht_cap_phy_info[0] |= support_320mhz; + } + + if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id)) return 0; } else { for (i = 0; i < ab->num_radios; i++) { @@ -5471,6 +5477,10 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, ret); return ret; } + + ab->wmi_ab.dp_peer_meta_data_ver = + u32_get_bits(parse->arg.target_cap_flags, + WMI_TARGET_CAP_FLAGS_RX_PEER_METADATA_VERSION); break; case WMI_TAG_ARRAY_STRUCT: diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 65f0d7ed4178..fdc203fdba0a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2783,6 +2783,8 @@ enum wmi_channel_width { #define WMI_EHT_MCS_NSS_10_11 GENMASK(11, 8) #define WMI_EHT_MCS_NSS_12_13 GENMASK(15, 12) +#define WMI_TARGET_CAP_FLAGS_RX_PEER_METADATA_VERSION GENMASK(1, 0) + struct wmi_service_ready_ext2_event { __le32 reg_db_version; __le32 hw_min_max_tx_power_2ghz; @@ -5230,6 +5232,8 @@ struct ath12k_wmi_base { struct ath12k_svc_ext_info svc_ext_info; u32 sbs_lower_band_end_freq; struct ath12k_hw_mode_info hw_mode_info; + + u8 dp_peer_meta_data_ver; }; struct wmi_pdev_set_bios_interface_cmd { @@ -6322,6 +6326,9 @@ struct ath12k_wmi_rssi_dbm_conv_info_arg { s8 min_nf_dbm; }; +/* each WMI cmd can hold 58 channel entries at most */ +#define ATH12K_WMI_MAX_NUM_CHAN_PER_CMD 58 + int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb, u32 cmd_id); struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len); diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index f56ec44a1636..bb08e1740582 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -135,6 +135,9 @@ static int ath12k_wow_cleanup(struct ath12k *ar) lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif != &arvif->ahvif->deflink) + continue; + ret = ath12k_wow_vif_cleanup(arvif); if (ret) { ath12k_warn(ar->ab, "failed to clean wow wakeups on vdev %i: %d\n", @@ -479,8 +482,12 @@ static int ath12k_wow_set_wakeups(struct ath12k *ar, lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif != &arvif->ahvif->deflink) + continue; + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) continue; + ret = ath12k_wow_vif_set_wakeups(arvif, wowlan); if (ret) { ath12k_warn(ar->ab, "failed to set wow wakeups on vdev %i: %d\n", @@ -538,6 +545,9 @@ static int ath12k_wow_nlo_cleanup(struct ath12k *ar) lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif != &arvif->ahvif->deflink) + continue; + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) continue; @@ -745,6 +755,9 @@ static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) list_for_each_entry(arvif, &ar->arvifs, list) { ahvif = arvif->ahvif; + if (arvif != &ahvif->deflink) + continue; + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA) continue; @@ -776,6 +789,9 @@ static int ath12k_gtk_rekey_offload(struct ath12k *ar, bool enable) lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif != &arvif->ahvif->deflink) + continue; + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA || !arvif->is_up || !arvif->rekey_data.enable_offload) diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index 0a3f916a1ef3..fd323ae84c95 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -80,11 +80,9 @@ struct ath5k_dbg_info { * @ATH5K_DEBUG_CALIBRATE: periodic calibration * @ATH5K_DEBUG_TXPOWER: transmit power setting * @ATH5K_DEBUG_LED: led management - * @ATH5K_DEBUG_DUMP_RX: print received skb content - * @ATH5K_DEBUG_DUMP_TX: print transmit skb content * @ATH5K_DEBUG_DUMPBANDS: dump bands * @ATH5K_DEBUG_DMA: debug dma start/stop - * @ATH5K_DEBUG_TRACE: trace function calls + * @ATH5K_DEBUG_ANI: debug Adaptive Noise Immunity * @ATH5K_DEBUG_DESC: descriptor setup * @ATH5K_DEBUG_ANY: show at any debug level * diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 0c47be06c153..47d570a5ca6a 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -47,7 +47,7 @@ config ATH9K_PCI config ATH9K_AHB bool "Atheros ath9k AHB bus support" - depends on ATH9K + depends on ATH9K && OF default n help This option enables the AHB bus support in ath9k. diff --git a/drivers/net/wireless/ath/ath9k/common-debug.h b/drivers/net/wireless/ath/ath9k/common-debug.h index 2938b5b96b07..97948af97682 100644 --- a/drivers/net/wireless/ath/ath9k/common-debug.h +++ b/drivers/net/wireless/ath/ath9k/common-debug.h @@ -19,14 +19,14 @@ /** * struct ath_rx_stats - RX Statistics * @rx_pkts_all: No. of total frames received, including ones that - may have had errors. + * may have had errors. * @rx_bytes_all: No. of total bytes received, including ones that - may have had errors. + * may have had errors. * @crc_err: No. of frames with incorrect CRC value * @decrypt_crc_err: No. of frames whose CRC check failed after - decryption process completed + * decryption process completed * @phy_err: No. of frames whose reception failed because the PHY - encountered an error + * encountered an error * @mic_err: No. of frames with incorrect TKIP MIC verification failure * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections * @post_delim_crc_err: Post-Frame delimiter CRC error detections diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index cb3e75969875..804e2a0a0c20 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -142,11 +142,12 @@ struct ath_interrupt_stats { /** * struct ath_tx_stats - Statistics about TX * @tx_pkts_all: No. of total frames transmitted, including ones that - may have had errors. + * may have had errors. * @tx_bytes_all: No. of total bytes transmitted, including ones that - may have had errors. + * may have had errors. * @queued: Total MPDUs (non-aggr) queued * @completed: Total MPDUs (non-aggr) completed + * @xretries: Total MPDUs with xretries * @a_aggr: Total no. of aggregates queued * @a_queued_hw: Total AMPDUs queued to hardware * @a_completed: Total AMPDUs completed @@ -154,14 +155,14 @@ struct ath_interrupt_stats { * @a_xretries: No. of AMPDUs dropped due to xretries * @txerr_filtered: No. of frames with TXERR_FILT flag set. * @fifo_underrun: FIFO underrun occurrences - Valid only for: - - non-aggregate condition. - - first packet of aggregate. + * Valid only for: + * - non-aggregate condition. + * - first packet of aggregate. * @xtxop: No. of frames filtered because of TXOP limit * @timer_exp: Transmit timer expiry * @desc_cfg_err: Descriptor configuration errors - * @data_urn: TX data underrun errors - * @delim_urn: TX delimiter underrun errors + * @data_underrun: TX data underrun errors + * @delim_underrun: TX delimiter underrun errors * @puttxbuf: Number of times hardware was given txbuf to write. * @txstart: Number of times hardware was told to start tx. * @txprocdesc: Number of times tx descriptor was processed diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9bd1286d2857..31e107c81e2d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -58,7 +58,7 @@ union wil_tx_desc; */ #define WIL_MAX_VIFS 4 -/** +/* * extract bits [@b0:@b1] (inclusive) from the value @x * it should be @b0 <= @b1, or result is incorrect */ @@ -433,7 +433,7 @@ extern struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE]; * @cid: CID value * @tid: TID value * - * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + * Returns: @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID */ static inline u8 mk_cidxtid(u8 cid, u8 tid) { @@ -444,8 +444,7 @@ static inline u8 mk_cidxtid(u8 cid, u8 tid) * parse_cidxtid - parse @cidxtid field * @cid: store CID value here * @tid: store TID value here - * - * @cidxtid field encoded as bits 0..3 - CID; 4..7 - TID + * @cidxtid: field encoded as bits 0..3 - CID; 4..7 - TID */ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid) { @@ -500,7 +499,7 @@ enum { /* for wil_ctx.mapped_as */ wil_mapped_as_page = 2, }; -/** +/* * struct wil_ctx - software context for ring descriptor */ struct wil_ctx { @@ -514,7 +513,7 @@ struct wil_desc_ring_rx_swtail { /* relevant for enhanced DMA only */ dma_addr_t pa; }; -/** +/* * A general ring structure, used for RX and TX. * In legacy DMA it represents the vring, * In enahnced DMA it represents the descriptor ring (vrings are handled by FW) @@ -531,7 +530,7 @@ struct wil_ring { bool is_rx; }; -/** +/* * Additional data for Rx ring. * Used for enhanced DMA RX chaining. */ @@ -543,7 +542,7 @@ struct wil_ring_rx_data { u16 buff_size; }; -/** +/* * Status ring structure, used for enhanced DMA completions for RX and TX. */ struct wil_status_ring { @@ -586,8 +585,8 @@ struct wil_net_stats { u32 ft_roams; /* relevant in STA mode */ }; -/** - * struct tx_rx_ops - different TX/RX ops for legacy and enhanced +/* + * struct wil_txrx_ops - different TX/RX ops for legacy and enhanced * DMA flow */ struct wil_txrx_ops { @@ -627,7 +626,7 @@ struct wil_txrx_ops { irqreturn_t (*irq_rx)(int irq, void *cookie); }; -/** +/* * Additional data for Tx ring */ struct wil_ring_tx_data { @@ -658,7 +657,7 @@ enum { /* for wil6210_priv.status */ struct pci_dev; /** - * struct tid_ampdu_rx - TID aggregation information (Rx). + * struct wil_tid_ampdu_rx - TID aggregation information (Rx). * * @reorder_buf: buffer to reorder incoming aggregated MPDUs * @last_rx: jiffies of last rx activity @@ -728,7 +727,7 @@ enum wil_rekey_state { WIL_REKEY_WAIT_M4_SENT = 2, }; -/** +/* * struct wil_sta_info - data for peer * * Peer identified by its CID (connection ID) @@ -741,7 +740,7 @@ struct wil_sta_info { u8 mid; enum wil_sta_status status; struct wil_net_stats stats; - /** + /* * 20 latency bins. 1st bin counts packets with latency * of 0..tx_latency_res, last bin counts packets with latency * of 19*tx_latency_res and above. @@ -882,7 +881,7 @@ struct wil6210_vif { struct work_struct enable_tx_key_worker; }; -/** +/* * RX buffer allocated for enhanced DMA RX descriptors */ struct wil_rx_buff { @@ -891,7 +890,7 @@ struct wil_rx_buff { int id; }; -/** +/* * During Rx completion processing, the driver extracts a buffer ID which * is used as an index to the rx_buff_mgmt.buff_arr array and then the SKB * is given to the network stack and the buffer is moved from the 'active' @@ -1147,7 +1146,7 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val) wil_w(wil, reg, wil_r(wil, reg) & ~val); } -/** +/* * wil_cid_valid - check cid is valid */ static inline bool wil_cid_valid(struct wil6210_priv *wil, int cid) diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 104748fcdc33..54991f31c52c 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -3224,7 +3224,9 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr, D_INFO("Invoking measurement of type %d on " "channel %d (for '%s')\n", type, params.channel, buf); + mutex_lock(&il->mutex); il3945_get_measurement(il, ¶ms, type); + mutex_unlock(&il->mutex); return count; } diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 3588dec75ebd..57fa866efd9f 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4606,7 +4606,9 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr, if (ret) IL_INFO("%s is not in decimal form.\n", buf); else { + mutex_lock(&il->mutex); ret = il_set_tx_power(il, val, false); + mutex_unlock(&il->mutex); if (ret) IL_ERR("failed setting tx power (0x%08x).\n", ret); else diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index d25445bd1e5c..77db8c75e6e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -19,12 +19,6 @@ #define IWL_BZ_SMEM_OFFSET 0x400000 #define IWL_BZ_SMEM_LEN 0xD0000 -#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" -#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" -#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" -#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" -#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" - static const struct iwl_family_base_params iwl_bz_base = { .num_of_queues = 512, .max_tfd_queue_size = 65536, @@ -100,9 +94,3 @@ const struct iwl_mac_cfg iwl_gl_mac_cfg = { .xtal_latency = 12000, .low_latency_xtal = true, }; - -IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c index fd82050e33a3..ad2536f53084 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c @@ -5,6 +5,12 @@ */ #include "iwl-config.h" +#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" +#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" +#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" +#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" +#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" + /* NVM versions */ #define IWL_FM_NVM_VERSION 0x0a1d @@ -50,3 +56,9 @@ const char iwl_be201_name[] = "Intel(R) Wi-Fi 7 BE201 320MHz"; const char iwl_be200_name[] = "Intel(R) Wi-Fi 7 BE200 320MHz"; const char iwl_be202_name[] = "Intel(R) Wi-Fi 7 BE202 160MHz"; const char iwl_be401_name[] = "Intel(R) Wi-Fi 7 BE401 320MHz"; + +IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c index 408b9850bd10..2c29054ce7b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c @@ -13,5 +13,4 @@ const char iwl_killer_bn1850i_name[] = const char iwl_bn201_name[] = "Intel(R) Wi-Fi 8 BN201"; const char iwl_bn203_name[] = "Intel(R) Wi-Fi 8 BN203"; -const char iwl_be221_name[] = "Intel(R) Wi-Fi 7 BE221"; const char iwl_be223_name[] = "Intel(R) Wi-Fi 7 BE223"; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 52edc19d8cdd..de9aef0d924c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -28,6 +28,8 @@ static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = { [DSM_FUNC_ENERGY_DETECTION_THRESHOLD] = sizeof(u32), [DSM_FUNC_RFI_CONFIG] = sizeof(u32), [DSM_FUNC_ENABLE_11BE] = sizeof(u32), + [DSM_FUNC_ENABLE_UNII_9] = sizeof(u32), + [DSM_FUNC_ENABLE_11BN] = sizeof(u32), }; static int iwl_acpi_get_handle(struct device *dev, acpi_string method, @@ -156,61 +158,104 @@ out: } /* - * This function receives a DSM function number, calculates its expected size - * according to Intel BIOS spec, and fills in the value in a 32-bit field. + * This function loads all the DSM functions, it checks the size and populates + * the cache with the values in a 32-bit field. * In case the expected size is smaller than 32-bit, padding will be added. */ -int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, - enum iwl_dsm_funcs func, u32 *value) +static int iwl_acpi_load_dsm_values(struct iwl_fw_runtime *fwrt) { - size_t expected_size; - u64 tmp; + u64 query_func_val; int ret; BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS); - if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size) || !func)) - return -EINVAL; + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, + DSM_FUNC_QUERY, + &iwl_guid, &query_func_val, + acpi_dsm_size[DSM_FUNC_QUERY]); - expected_size = acpi_dsm_size[func]; + if (ret) { + IWL_DEBUG_RADIO(fwrt, "ACPI QUERY FUNC not valid: %d\n", ret); + return ret; + } - /* Currently all ACPI DSMs are either 8-bit or 32-bit */ - if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) - return -EOPNOTSUPP; + fwrt->dsm_revision = ACPI_DSM_REV; + fwrt->dsm_source = BIOS_SOURCE_ACPI; - if (!fwrt->acpi_dsm_funcs_valid) { - ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, - DSM_FUNC_QUERY, - &iwl_guid, &tmp, - acpi_dsm_size[DSM_FUNC_QUERY]); - if (ret) { - /* always indicate BIT(0) to avoid re-reading */ - fwrt->acpi_dsm_funcs_valid = BIT(0); - return ret; + IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", + (u32)query_func_val); + + /* DSM_FUNC_QUERY is 0, start from 1 */ + for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) { + size_t expected_size = acpi_dsm_size[func]; + u64 tmp; + + if (!(query_func_val & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, + "ACPI DSM %d not indicated as valid\n", + func); + continue; } - IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", - (u32)tmp); - /* always indicate BIT(0) to avoid re-reading */ - fwrt->acpi_dsm_funcs_valid = tmp | BIT(0); + /* This is an invalid function (5 for example) */ + if (!expected_size) + continue; + + /* Currently all ACPI DSMs are either 8-bit or 32-bit */ + if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) + continue; + + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, + &iwl_guid, &tmp, expected_size); + if (ret) + continue; + + if ((expected_size == sizeof(u8) && tmp != (u8)tmp) || + (expected_size == sizeof(u32) && tmp != (u32)tmp)) + IWL_DEBUG_RADIO(fwrt, + "DSM value overflows the expected size, truncating\n"); + fwrt->dsm_values[func] = (u32)tmp; + fwrt->dsm_funcs_valid |= BIT(func); + } + + return 0; +} + +/* + * This function receives a DSM function number, calculates its expected size + * according to Intel BIOS spec, and fills in the value in a 32-bit field. + * In case the expected size is smaller than 32-bit, padding will be added. + */ +int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs func, u32 *value) +{ + if (!fwrt->dsm_funcs_valid) { + int ret = iwl_acpi_load_dsm_values(fwrt); + + /* + * Always set the valid bit for DSM_FUNC_QUERY so that even if + * DSM_FUNC_QUERY returns 0 (no DSM function is valid), we will + * still consider the cache as valid. + */ + fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY); + + if (ret) + return ret; } - if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) { + BUILD_BUG_ON(ARRAY_SIZE(fwrt->dsm_values) != DSM_FUNC_NUM_FUNCS); + BUILD_BUG_ON(BITS_PER_TYPE(fwrt->dsm_funcs_valid) < DSM_FUNC_NUM_FUNCS); + + if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values) || !func)) + return -EINVAL; + + if (!(fwrt->dsm_funcs_valid & BIT(func))) { IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n", func); return -ENODATA; } - ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, - &iwl_guid, &tmp, expected_size); - if (ret) - return ret; - - if ((expected_size == sizeof(u8) && tmp != (u8)tmp) || - (expected_size == sizeof(u32) && tmp != (u32)tmp)) - IWL_DEBUG_RADIO(fwrt, - "DSM value overflows the expected size, truncating\n"); - *value = (u32)tmp; + *value = fwrt->dsm_values[func]; return 0; } 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 f76cea6e9ec8..c7a833f8041a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -66,6 +66,18 @@ enum iwl_mac_conf_subcmd_ids { */ TWT_OPERATION_CMD = 0x10, /** + * @NAN_CFG_CMD: &struct iwl_nan_config_cmd + */ + NAN_CFG_CMD = 0x12, + /** + * @NAN_DW_END_NOTIF: &struct iwl_nan_dw_end_notif + */ + NAN_DW_END_NOTIF = 0xf4, + /** + * @NAN_JOINED_CLUSTER_NOTIF: &struct iwl_nan_cluster_notif + */ + NAN_JOINED_CLUSTER_NOTIF = 0xf5, + /** * @MISSED_BEACONS_NOTIF: &struct iwl_missed_beacons_notif */ MISSED_BEACONS_NOTIF = 0xF6, @@ -492,22 +504,36 @@ enum iwl_link_modify_bandwidth { }; /** + * enum iwl_npca_flags - NPCA flags + * @IWL_NPCA_FLAG_MAC_HDR_BASED: MAC header based NPCA operation + * permitted in the BSS (MOPLEN) + */ +enum iwl_npca_flags { + IWL_NPCA_FLAG_MAC_HDR_BASED = BIT(0), +}; /* NPCA_FLAG_E */ + +/** * struct iwl_npca_params - NPCA parameters (non-primary channel access) * + * @dis_subch_bmap: disabled subchannel bitmap for NPCA * @switch_delay: after switch, delay TX according to destination AP * @switch_back_delay: switch back to control channel before OBSS frame end + * @initial_qsrc: Indicates the value that is used to initialize the + * EDCAF QSRC[AC] variables * @min_dur_threshold: minimum PPDU time to switch to the non-primary - * NPCA channel - * @flags: NPCA flags - bit 0: puncturing allowed, bit 1: new TX allowed + * NPCA channel (usec) + * @flags: NPCA flags, see &enum iwl_npca_flags * @reserved: reserved for alignment purposes */ struct iwl_npca_params { + __le16 dis_subch_bmap; u8 switch_delay; u8 switch_back_delay; - __le16 min_dur_threshold; - __le16 flags; - __le16 reserved; -} __packed; /* NPCA_PARAM_API_S_VER_1 */ + u8 initial_qsrc; + u8 min_dur_threshold; + u8 flags; + u8 reserved; +} __packed; /* NPCA_PARAM_API_S_VER_2 */ /** * struct iwl_link_config_cmd - command structure to configure the LINK context @@ -618,7 +644,8 @@ struct iwl_link_config_cmd { struct iwl_npca_params npca_params; /* since _VER_7 */ struct iwl_ac_qos prio_edca_params; /* since _VER_7 */ __le32 reserved3[4]; -} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5, _VER_6, _VER_7 */ +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, + * _VER_5, _VER_6, _VER_7, _VER_8 */ /* Currently FW supports link ids in the range 0-3 and can have * at most two active links for each vif. @@ -990,4 +1017,122 @@ struct iwl_twt_operation_cmd { u8 ul_tid_bitmap; } __packed; /* TWT_OPERATION_API_S_VER_1 */ +enum iwl_nan_band { + IWL_NAN_BAND_5GHZ = 0, + IWL_NAN_BAND_2GHZ = 1, + IWL_NUM_NAN_BANDS, +}; + +/** + * struct iwl_nan_band_config - NAN band configuration + * + * @rssi_close: RSSI threshold for close proximity in dBm + * @rssi_middle: RSSI threshold for middle proximity in dBm + * @dw_interval: Discovery Window (DW) interval for synchronization beacons and + * SDFs. Valid values of DW interval are: 1, 2, 3, 4 and 5 corresponding to + * 1, 2, 4, 8, and 16 DWs. + * @reserved: reserved + */ +struct iwl_nan_band_config { + u8 rssi_close; + u8 rssi_middle; + u8 dw_interval; + u8 reserved; +}; /* NAN_BAND_SPECIFIC_CONFIG_API_S_VER_1 */ + +/** + * enum iwl_nan_flags - flags for NAN configuration + * + * @IWL_NAN_FLAG_DW_END_NOTIF_ENABLED: indicates that the host wants to receive + * notifications when a DW ends. + */ +enum iwl_nan_flags { + IWL_NAN_FLAG_DW_END_NOTIF_ENABLED = BIT(0), +}; + +/** + * struct iwl_nan_config_cmd - NAN configuration command + * + * @action: action to perform, see &enum iwl_ctxt_action + * @nmi_addr: NAN Management Interface (NMI) address + * @reserved_for_nmi_addr: reserved + * @discovery_beacon_interval: discovery beacon interval in TUs + * @cluster_id: lower last two bytes of the cluster ID, in case the local + * device starts a cluster + * @sta_id: station ID of the NAN station + * @hb_channel: channel for 5 GHz if the device supports operation on 5 GHz. + * Valid values are 44 and 149, which correspond to the 5 GHz channel, and + * 0 which means that NAN operation on the 5 GHz band is disabled. + * @master_pref: master preference + * @dwell_time: dwell time on the discovery channel during scan (milliseconds). + * If set to 0, the dwell time is determined by the firmware. + * @scan_period: scan period in seconds. If set to 0, the scan period is + * determined by the firmware. + * @flags: flags for NAN configuration, see &enum iwl_nan_flags + * @band_config: band configuration for NAN, one for each band + * @nan_attr_len: length of the NAN attributes to be added to the beacon (bytes) + * @nan_vendor_elems_len: length of the NAN vendor elements to be added to the + * beacon (bytes) + * @beacon_data: variable length data that contains the NAN attributes + * (&nan_attr_len) followed by the NAN vendor elements + * (&nan_vendor_elems_len). + */ +struct iwl_nan_config_cmd { + __le32 action; + u8 nmi_addr[6]; + __le16 reserved_for_nmi_addr; + __le32 discovery_beacon_interval; + + u8 cluster_id[2]; + u8 sta_id; + u8 hb_channel; + + u8 master_pref; + u8 dwell_time; + u8 scan_period; + u8 flags; + + struct iwl_nan_band_config band_config[IWL_NUM_NAN_BANDS]; + + __le32 nan_attr_len; + __le32 nan_vendor_elems_len; + u8 beacon_data[]; +} __packed; /* NAN_CONFIG_CMD_API_S_VER_1 */ + +/** + * enum iwl_nan_cluster_notif_flags - flags for the cluster notification + * + * @IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER: indicates that the device has + * started a new cluster. If not set, the device has joined an existing + * cluster. + */ +enum iwl_nan_cluster_notif_flags { + IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER = BIT(0), +}; /* NAN_JOINED_CLUSTER_FLAG_E_VER_1 */ + +/** + * struct iwl_nan_cluster_notif - event sent when the device starts or joins a + * NAN cluster. + * + * @cluster_id: the last two bytes of the cluster ID + * @flags: combination of &enum iwl_nan_cluster_notif_flags + * @reserved: reserved + */ +struct iwl_nan_cluster_notif { + u8 cluster_id[2]; + u8 flags; + u8 reserved; +}; /* NAN_JOINED_CLUSTER_NTF_API_S_VER_1 */ + +/** + * struct iwl_nan_dw_end_notif - sent to notify the host the end of a DW. + * + * @band: band on which the DW ended. See &enum iwl_nan_band. + * @reserved: reserved + */ +struct iwl_nan_dw_end_notif { + u8 band; + u8 reserved[3]; +} __packed; /* NAN_DW_END_NTF_API_S_VER_1 */ + #endif /* __iwl_fw_api_mac_cfg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 4644fc1aa1ec..bd6bf931866f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -503,18 +503,26 @@ enum bios_source { }; /** - * struct bios_value_u32 - BIOS configuration. + * struct iwl_bios_config_hdr - BIOS configuration header * @table_source: see &enum bios_source * @table_revision: table revision. * @reserved: reserved - * @value: value in bios. */ -struct bios_value_u32 { +struct iwl_bios_config_hdr { u8 table_source; u8 table_revision; u8 reserved[2]; +} __packed; /* BIOS_CONFIG_HDR_API_S_VER_1 */ + +/** + * struct bios_value_u32 - BIOS configuration. + * @hdr: bios config header + * @value: value in bios. + */ +struct bios_value_u32 { + struct iwl_bios_config_hdr hdr; __le32 value; -} __packed; /* BIOS_TABLE_SOURCE_U32_S_VER_1 */ +} __packed; /* BIOS_CONFIG_DATA_U32_API_S_VER_1 */ /** * struct iwl_tas_config_cmd - configures the TAS. @@ -650,6 +658,10 @@ struct iwl_lari_config_change_cmd_v8 { * bit0: enable 11be in China(CB/CN). * bit1: enable 11be in South Korea. * bit 2 - 31: reserved. + * @oem_11bn_allow_bitmap: Bitmap of 11bn allowed MCCs. The firmware expects to + * get the data from the BIOS. + * @oem_unii9_enable: UNII-9 enablement as read from the BIOS + * @bios_hdr: bios config header */ struct iwl_lari_config_change_cmd { __le32 config_bitmap; @@ -661,8 +673,16 @@ struct iwl_lari_config_change_cmd { __le32 edt_bitmap; __le32 oem_320mhz_allow_bitmap; __le32 oem_11be_allow_bitmap; + /* since version 13 */ + __le32 oem_11bn_allow_bitmap; + /* since version 13 */ + __le32 oem_unii9_enable; + /* since version 13 */ + struct iwl_bios_config_hdr bios_hdr; } __packed; -/* LARI_CHANGE_CONF_CMD_S_VER_12 */ +/* LARI_CHANGE_CONF_CMD_S_VER_12 + * LARI_CHANGE_CONF_CMD_S_VER_13 + */ /* Activate UNII-1 (5.2GHz) for World Wide */ #define ACTIVATE_5G2_IN_WW_MASK BIT(4) @@ -682,11 +702,11 @@ struct iwl_pnvm_init_complete_ntfy { /** * struct iwl_mcc_allowed_ap_type_cmd - struct for MCC_ALLOWED_AP_TYPE_CMD - * @offset_map: mapping a mcc to UHB AP type support (UATS) allowed + * @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS) * @reserved: reserved */ struct iwl_mcc_allowed_ap_type_cmd { - u8 offset_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; + u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; __le16 reserved; } __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 535864e22626..0cd8a12e0f7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -766,7 +766,7 @@ enum iwl_6ghz_ap_type { * AP_TX_POWER_CONSTRAINTS_CMD * Used for VLP/LPI/AFC Access Point power constraints for 6GHz channels * @link_id: linkId - * @ap_type: see &enum iwl_ap_type + * @ap_type: see &enum iwl_6ghz_ap_type * @eirp_pwr: 8-bit 2s complement signed integer in the range * -64 dBm to 63 dBm with a 0.5 dB step * default &DEFAULT_TPE_TX_POWER (no maximum limit) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 9c464e7aba10..ae6be3ed32f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -73,6 +73,7 @@ enum iwl_tlc_mng_cfg_chains { * @IWL_TLC_MNG_MODE_VHT: enable VHT * @IWL_TLC_MNG_MODE_HE: enable HE * @IWL_TLC_MNG_MODE_EHT: enable EHT + * @IWL_TLC_MNG_MODE_UHR: enable UHR */ enum iwl_tlc_mng_cfg_mode { IWL_TLC_MNG_MODE_CCK = 0, @@ -82,6 +83,7 @@ enum iwl_tlc_mng_cfg_mode { IWL_TLC_MNG_MODE_VHT, IWL_TLC_MNG_MODE_HE, IWL_TLC_MNG_MODE_EHT, + IWL_TLC_MNG_MODE_UHR, }; /** @@ -205,7 +207,7 @@ struct iwl_tlc_config_cmd_v4 { } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */ /** - * struct iwl_tlc_config_cmd - TLC configuration + * struct iwl_tlc_config_cmd_v5 - TLC configuration * @sta_id: station id * @reserved1: reserved * @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw @@ -221,7 +223,7 @@ struct iwl_tlc_config_cmd_v4 { * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI), * set zero for no limit. */ -struct iwl_tlc_config_cmd { +struct iwl_tlc_config_cmd_v5 { u8 sta_id; u8 reserved1[3]; u8 max_ch_width; @@ -236,6 +238,38 @@ struct iwl_tlc_config_cmd { } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_5 */ /** + * struct iwl_tlc_config_cmd - TLC configuration + * @sta_mask: station mask (in NAN we can have multiple logical stations of + * the same peer (with the same TLC configuration)). + * @phy_id: the phy id to used for this TLC configuration + * @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw + * @mode: &enum iwl_tlc_mng_cfg_mode + * @chains: bitmask of &enum iwl_tlc_mng_cfg_chains + * @sgi_ch_width_supp: bitmap of SGI support per channel width + * use BIT(&enum iwl_tlc_mng_cfg_cw) + * @flags: bitmask of &enum iwl_tlc_mng_cfg_flags + * @non_ht_rates: bitmap of supported legacy rates + * @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per <nss, channel-width> + * pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz). + * @max_mpdu_len: max MPDU length, in bytes + * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI), + * set zero for no limit. + */ +struct iwl_tlc_config_cmd { + __le32 sta_mask; + __le32 phy_id; + u8 max_ch_width; + u8 mode; + u8 chains; + u8 sgi_ch_width_supp; + __le16 flags; + __le16 non_ht_rates; + __le32 ht_rates[IWL_TLC_NSS_MAX][IWL_TLC_MCS_PER_BW_NUM_V4]; + __le16 max_mpdu_len; + __le16 max_tx_op; +} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_6 */ + +/** * enum iwl_tlc_update_flags - updated fields * @IWL_TLC_NOTIF_FLAG_RATE: last initial rate update * @IWL_TLC_NOTIF_FLAG_AMSDU: umsdu parameters update @@ -706,10 +740,11 @@ enum { #define RATE_MCS_HE_SU_4_LTF 3 #define RATE_MCS_HE_SU_4_LTF_08_GI 4 -/* Bit 24-23: HE type. (0) SU, (1) SU_EXT, (2) MU, (3) trigger based */ +/* Bit 24-23: HE type. (0) SU, (1) HE SU_EXT/UHR ELR, (2) MU, (3) trigger based */ #define RATE_MCS_HE_TYPE_POS 23 #define RATE_MCS_HE_TYPE_SU (0 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_EXT_SU (1 << RATE_MCS_HE_TYPE_POS) +#define RATE_MCS_HE_TYPE_UHR_ELR (1 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_MU (2 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_TRIG (3 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_MSK (3 << RATE_MCS_HE_TYPE_POS) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 3ed7e0807b90..ac6c1ef2cbcd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -1062,13 +1062,37 @@ struct iwl_vht_sigs { #define OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM 0x000007ff #define OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM_VALID 0x80000000 __le32 a0; - __le32 a1, a2; +#define OFDM_RX_FRAME_VHT_BANDWIDTH 0x00000003 +#define OFDM_RX_FRAME_VHT_STBC 0x00000008 +#define OFDM_RX_FRAME_VHT_GRP_ID 0x000003f0 +#define OFDM_RX_FRAME_VHT_STS_USER0 0x00001c00 +#define OFDM_RX_FRAME_VHT_MU_STS_USER1 0x0000e000 +#define OFDM_RX_FRAME_VHT_MU_STS_USER2 0x00070000 +#define OFDM_RX_FRAME_VHT_MU_STS_USER3 0x00380000 +#define OFDM_RX_FRAME_VHT_PARTIAL_AID_OR_MU_STS 0x003fe000 +#define OFDM_RX_FRAME_VHT_MU_MIMO_USER_POSITION 0x03000000 +#define OFDM_RX_FRAME_VHT_NO_STREAMS 0x04000000 +#define OFDM_RX_FRAME_VHT_STS 0x38000000 + __le32 a1; +#define OFDM_RX_FRAME_VHT_SHORT_GI 0x00000001 +#define OFDM_RX_FRAME_VHT_SHORT_GI_AMBIG 0x00000002 +#define OFDM_RX_FRAME_VHT_CODING 0x00000004 +#define OFDM_RX_FRAME_VHT_CODING_EXTRA_SYM 0x00000008 +#define OFDM_RX_FRAME_VHT_MCS_OR_MU_CODING 0x000000f0 +#define OFDM_RX_FRAME_VHT_BF_OR_MU_RESERVED 0x00000100 +#define OFDM_RX_FRAME_VHT_CRC 0x0003fc00 +#define OFDM_RX_FRAME_VHT_CRC_OK_BIT 0x00040000 +#define OFDM_RX_FRAME_VHT_CUR_USER_CODING 0x00080000 +#define OFDM_RX_FRAME_VHT_CUR_USER_STS 0x00700000 + __le32 a2; }; struct iwl_he_sigs { #define OFDM_RX_FRAME_HE_BEAM_CHANGE 0x00000001 #define OFDM_RX_FRAME_HE_UL_FLAG 0x00000002 +/* SU/ER-SU: MCS, MU: SIG-B MCS */ #define OFDM_RX_FRAME_HE_MCS 0x0000003c +/* SU/ER-SU: DCM, MU: SIG-B DCM */ #define OFDM_RX_FRAME_HE_DCM 0x00000040 #define OFDM_RX_FRAME_HE_BSS_COLOR 0x00001f80 #define OFDM_RX_FRAME_HE_SPATIAL_REUSE 0x0001e000 @@ -1247,19 +1271,82 @@ struct iwl_eht_tb_sigs { }; struct iwl_uhr_sigs { - __le32 usig_a1, usig_a1_uhr, usig_a2_uhr, b1, b2; + /* same as EHT above */ + __le32 usig_a1; +#define OFDM_RX_FRAME_UHR_BSS_COLOR2 0x0000003f + __le32 usig_a1_uhr; +#define OFDM_RX_FRAME_UHR_PPDU_TYPE 0x00000003 +#define OFDM_RX_FRAME_UHR_COBF_CSR_DISABLE 0x00000004 +#define OFDM_RX_FRAME_UHR_PUNC_CHANNEL 0x000000f8 +#define OFDM_RX_FRAME_UHR_USIG2_VALIDATE_B8 0x00000100 +#define OFDM_RX_FRAME_UHR_SIG_MCS 0x00000600 +#define OFDM_RX_FRAME_UHR_SIG_SYM_NUM 0x0000f800 +#define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_1 0x000f0000 +#define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_2 0x00f00000 +#define OFDM_RX_FRAME_UHR_TRIG_USIG2_DISREGARD 0x1f000000 + __le32 usig_a2_uhr; +#define OFDM_RX_FRAME_UHR_SPATIAL_REUSE 0x0000000f +#define OFDM_RX_FRAME_UHR_GI_LTF_TYPE 0x00000030 +#define OFDM_RX_FRAME_UHR_NUM_OF_LTF_SYM 0x000001c0 +#define OFDM_RX_FRAME_UHR_CODING_EXTRA_SYM 0x00000200 +#define OFDM_RX_FRAME_UHR_PE_A_FACTOR 0x00000c00 +#define OFDM_RX_FRAME_UHR_PE_DISAMBIGUITY 0x00001000 +#define OFDM_RX_FRAME_UHR_IM_DISABLE 0x00002000 +#define OFDM_RX_FRAME_UHR_USIG_OVF_DISREGARD 0x0000c000 +#define OFDM_RX_FRAME_UHR_NUM_OF_USERS 0x00070000 +#define OFDM_RX_FRAME_UHR_NSTS 0x00f00000 +#define OFDM_RX_FRAME_UHR_BF 0x01000000 +#define OFDM_RX_FRAME_UHR_USIG_OVF_NDP_DISREGARD 0x06000000 +#define OFDM_RX_FRAME_UHR_COMM_CC1_CRC_OK 0x08000000 +#define OFDM_RX_FRAME_UHR_COMM_CC2_CRC_OK 0x10000000 +#define OFDM_RX_FRAME_UHR_NON_VALID_RU_ALLOC 0x20000000 + __le32 b1; +#define OFDM_RX_FRAME_UHR_MCS 0x000001f0 +#define OFDM_RX_FRAME_UHR_CODING 0x00000200 +#define OFDM_RX_FRAME_UHR_SPATIAL_CONFIG 0x00003c00 +#define OFDM_RX_FRAME_UHR_STA_RU 0x003fc000 +#define OFDM_RX_FRAME_UHR_STA_RU_PS160 0x00400000 +#define OFDM_RX_FRAME_UHR_UEQM 0x00800000 +#define OFDM_RX_FRAME_UHR_2XLDPC 0x01000000 +#define OFDM_RX_FRAME_UHR_UEQM_PATTERN 0x06000000 +#define OFDM_RX_FRAME_UHR_IS_MU_MIMO_USER_FIELD 0x08000000 +#define OFDM_RX_FRAME_UHR_USER_FIELD_CRC_OK 0x40000000 + __le32 b2; +#define OFDM_RX_UHR_NUM_OF_DATA_SYM 0x000007ff +#define OFDM_RX_UHR_PE_DURATION 0x00003800 __le32 sig2; + /* same as EHT above: OFDM_RX_FRAME_EHT_RU_ALLOC_* */ __le32 cmn[6]; +#define OFDM_RX_FRAME_UHR_USER_FIELD_ID 0x000007ff __le32 user_id; }; struct iwl_uhr_tb_sigs { - __le32 usig_a1, usig_a2_uhr, tb_rx0, tb_rx1; + /* same as UHR above */ + __le32 usig_a1, usig_a2_uhr; + /* same as HE above */ + __le32 tb_rx0, tb_rx1; }; struct iwl_uhr_elr_sigs { + /* same as UHR above */ __le32 usig_a1, usig_a2_uhr; - __le32 uhr_sig_elr1, uhr_sig_elr2; +#define OFDM_RX_VECTOR_UHR_ELR_VER_ID 0x00000007 +#define OFDM_RX_VECTOR_UHR_ELR_UPLINK_FLAG 0x00000008 +#define OFDM_RX_VECTOR_UHR_ELR_MCS 0x00000010 +#define OFDM_RX_VECTOR_UHR_ELR_CODING 0x00000020 +#define OFDM_RX_VECTOR_UHR_ELR_LENGTH_IN_SYM 0x00007fc0 +#define OFDM_RX_VECTOR_UHR_ELR_CODING_EXTRA_SYM 0x00008000 +#define OFDM_RX_VECTOR_UHR_ELR_SIG1_CRC_OK 0x00010000 +#define OFDM_RX_VECTOR_UHR_ELR_STA_ID 0x0ffe0000 +#define OFDM_RX_VECTOR_UHR_ELR_DISREGARD 0x70000000 + __le32 uhr_sig_elr1; +#define OFDM_RX_VECTOR_UHR_ELR_MARK_BSS_COLOR 0x0000003f +#define OFDM_RX_VECTOR_UHR_ELR_SIG_ID_INDX 0x00000e00 +#define OFDM_RX_VECTOR_UHR_ELR_STA_RU 0x000ff000 +#define OFDM_RX_VECTOR_UHR_ELR_STA_RU_PS160 0x00100000 +#define OFDM_RX_VECTOR_UHR_ELR_SIG2_CRC_OK 0x00200000 + __le32 uhr_sig_elr2; }; union iwl_sigs { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index b9e0b69c6680..378788de1d74 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -447,6 +447,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * during assert handling even if the dump isn't split * @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware has capability of * handling raw DSM table data. + * @IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT: Supports NAN synchronization * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -550,6 +551,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0), IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 1), + IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 2), NUM_IWL_UCODE_TLV_CAPA /* * This construction make both sparse (which cannot increment the previous diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index d2ad169ae880..958e71a3c958 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -376,8 +376,10 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, num_sub_bands = IWL_NUM_SUB_BANDS_V2; gain = cmd->v7.gain[0]; *cmd_size = sizeof(cmd->v7); - cmd->v7.ppag_config_info.table_source = fwrt->ppag_bios_source; - cmd->v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev; + cmd->v7.ppag_config_info.hdr.table_source = + fwrt->ppag_bios_source; + cmd->v7.ppag_config_info.hdr.table_revision = + fwrt->ppag_bios_rev; cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags); } else { IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); @@ -488,206 +490,6 @@ bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc) } IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list); -__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) -{ - int ret; - u32 val; - __le32 config_bitmap = 0; - - switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) { - case IWL_CFG_RF_TYPE_HR1: - case IWL_CFG_RF_TYPE_HR2: - case IWL_CFG_RF_TYPE_JF1: - case IWL_CFG_RF_TYPE_JF2: - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, - &val); - - if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); - break; - default: - break; - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); - if (!ret) { - if (val == DSM_VALUE_SRD_PASSIVE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); - else if (val == DSM_VALUE_SRD_DISABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); - } - - if (fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) { - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, - &val); - /* - * China 2022 enable if the BIOS object does not exist or - * if it is enabled in BIOS. - */ - if (ret < 0 || val & DSM_MASK_CHINA_22_REG) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK); - } - - return config_bitmap; -} -IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap); - -static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver) -{ - size_t cmd_size; - - switch (cmd_ver) { - case 12: - cmd_size = sizeof(struct iwl_lari_config_change_cmd); - break; - case 8: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8); - break; - case 6: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6); - break; - default: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); - break; - } - return cmd_size; -} - -int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, - struct iwl_lari_config_change_cmd *cmd, - size_t *cmd_size) -{ - int ret; - u32 value; - bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE); - u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, - WIDE_ID(REGULATORY_AND_NVM_GROUP, - LARI_CONFIG_CHANGE), 1); - - if (WARN_ONCE(cmd_ver > 12, - "Don't add newer versions to this function\n")) - return -EINVAL; - - memset(cmd, 0, sizeof(*cmd)); - *cmd_size = iwl_get_lari_config_cmd_size(cmd_ver); - - cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt); - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= DSM_11AX_ALLOW_BITMAP; - cmd->oem_11ax_allow_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= DSM_UNII4_ALLOW_BITMAP; - - /* Since version 12, bits 4 and 5 are supported - * regardless of this capability, By pass this masking - * if firmware has capability of accepting raw DSM table. - */ - if (!has_raw_dsm_capa && cmd_ver < 12 && - !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA)) - value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK | - DSM_VALUE_UNII4_CANADA_EN_MSK); - - cmd->oem_unii4_allow_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; - - if (!has_raw_dsm_capa && cmd_ver < 8) - value &= ~ACTIVATE_5G2_IN_WW_MASK; - - /* Since version 12, bits 5 and 6 are supported - * regardless of this capability, By pass this masking - * if firmware has capability of accepting raw DSM table. - */ - if (!has_raw_dsm_capa && cmd_ver < 12 && - !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA)) - value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V8; - - cmd->chan_state_active_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value); - if (!ret) - cmd->oem_uhb_allow_bitmap = cpu_to_le32(value); - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP; - cmd->force_disable_channels_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, - &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= DSM_EDT_ALLOWED_BITMAP; - cmd->edt_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_wbem(fwrt, &value); - if (!ret) - cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value); - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value); - if (!ret) - cmd->oem_11be_allow_bitmap = cpu_to_le32(value); - - if (cmd->config_bitmap || - cmd->oem_uhb_allow_bitmap || - cmd->oem_11ax_allow_bitmap || - cmd->oem_unii4_allow_bitmap || - cmd->chan_state_active_bitmap || - cmd->force_disable_channels_bitmap || - cmd->edt_bitmap || - cmd->oem_320mhz_allow_bitmap || - cmd->oem_11be_allow_bitmap) { - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", - le32_to_cpu(cmd->config_bitmap), - le32_to_cpu(cmd->oem_11ax_allow_bitmap)); - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n", - le32_to_cpu(cmd->oem_unii4_allow_bitmap), - le32_to_cpu(cmd->chan_state_active_bitmap), - cmd_ver); - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n", - le32_to_cpu(cmd->oem_uhb_allow_bitmap), - le32_to_cpu(cmd->force_disable_channels_bitmap)); - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n", - le32_to_cpu(cmd->edt_bitmap), - le32_to_cpu(cmd->oem_320mhz_allow_bitmap)); - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n", - le32_to_cpu(cmd->oem_11be_allow_bitmap)); - } else { - return 1; - } - - return 0; -} -IWL_EXPORT_SYMBOL(iwl_fill_lari_config); - int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 735482e7adf5..1489031687b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -125,7 +125,9 @@ enum iwl_dsm_funcs { DSM_FUNC_ENERGY_DETECTION_THRESHOLD = 10, DSM_FUNC_RFI_CONFIG = 11, DSM_FUNC_ENABLE_11BE = 12, - DSM_FUNC_NUM_FUNCS = 13, + DSM_FUNC_ENABLE_11BN = 13, + DSM_FUNC_ENABLE_UNII_9 = 14, + DSM_FUNC_NUM_FUNCS, }; enum iwl_dsm_values_srd { @@ -218,11 +220,6 @@ int iwl_bios_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); int iwl_bios_get_eckv(struct iwl_fw_runtime *fwrt, u32 *ext_clk); int iwl_bios_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value); -__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); -int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, - struct iwl_lari_config_change_cmd *cmd, - size_t *cmd_size); - int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 57570ff15622..ff186fb2e0da 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -116,10 +116,14 @@ struct iwl_txf_iter_data { * @phy_filters: specific phy filters as read from WPFC BIOS table * @ppag_bios_rev: PPAG BIOS revision * @ppag_bios_source: see &enum bios_source - * @acpi_dsm_funcs_valid: bitmap indicating which DSM values are valid, + * @dsm_funcs_valid: bitmap indicating which DSM values are valid, * zero (default initialization) means it hasn't been read yet, * and BIT(0) is set when it has since function 0 also has this - * bitmap and is always supported + * bitmap and is always supported. + * If the bit is set for a specific function, then the corresponding + * entry in &dsm_values is valid. + * @dsm_values: cache of the DSM values. The validity of each entry is + * determined by &dsm_funcs_valid. * @geo_enabled: WGDS table is present * @geo_num_profiles: number of geo profiles * @geo_rev: geo profiles table revision @@ -137,6 +141,8 @@ struct iwl_txf_iter_data { * @timestamp.seq: timestamp marking sequence * @timestamp.delay: timestamp marking worker delay * @tpc_enabled: TPC enabled + * @dsm_source: one of &enum bios_source. UEFI, ACPI or NONE + * @dsm_revision: the revision of the DSM table */ struct iwl_fw_runtime { struct iwl_trans *trans; @@ -211,9 +217,12 @@ struct iwl_fw_runtime { bool uats_valid; u8 uefi_tables_lock_status; struct iwl_phy_specific_cfg phy_filters; + enum bios_source dsm_source; + u8 dsm_revision; -#ifdef CONFIG_ACPI - u32 acpi_dsm_funcs_valid; +#if defined(CONFIG_ACPI) || defined(CONFIG_EFI) + u32 dsm_funcs_valid; + u32 dsm_values[DSM_FUNC_NUM_FUNCS]; #endif }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/smem.c b/drivers/net/wireless/intel/iwlwifi/fw/smem.c index 90fd69b4860c..344ddde85b18 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/smem.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/smem.c @@ -6,6 +6,7 @@ */ #include "iwl-drv.h" #include "runtime.h" +#include "dbg.h" #include "fw/api/commands.h" static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, @@ -17,7 +18,9 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, u8 api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP, SHARED_MEM_CFG_CMD, 0); - if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem))) + /* Note: notification has 3 entries, but we only expect 2 */ + if (IWL_FW_CHECK(fwrt, lmac_num > ARRAY_SIZE(fwrt->smem_cfg.lmac), + "FW advertises %d LMACs\n", lmac_num)) return; fwrt->smem_cfg.num_lmacs = lmac_num; @@ -26,7 +29,8 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, fwrt->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo2_size); if (api_ver >= 4 && - !WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg))) { + !IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg), + "bad shared mem notification size\n")) { fwrt->smem_cfg.rxfifo2_control_size = le32_to_cpu(mem_cfg->rxfifo2_control_size); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 4ae4d215e633..a7ba86e06c09 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -402,8 +402,9 @@ static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data, if (uats_data->revision != 1) return -EINVAL; - memcpy(fwrt->uats_table.offset_map, uats_data->offset_map, - sizeof(fwrt->uats_table.offset_map)); + memcpy(fwrt->uats_table.mcc_to_ap_type_map, + uats_data->mcc_to_ap_type_map, + sizeof(fwrt->uats_table.mcc_to_ap_type_map)); fwrt->uats_valid = true; @@ -721,17 +722,12 @@ out: return ret; } -int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, - u32 *value) +static int iwl_uefi_load_dsm_values(struct iwl_fw_runtime *fwrt) { struct uefi_cnv_var_general_cfg *data; int ret = -EINVAL; - BUILD_BUG_ON(ARRAY_SIZE(data->functions) < DSM_FUNC_NUM_FUNCS); - - /* Not supported function index */ - if (func >= DSM_FUNC_NUM_FUNCS || func == 5) - return -EOPNOTSUPP; + BUILD_BUG_ON(ARRAY_SIZE(data->functions) < ARRAY_SIZE(fwrt->dsm_values)); data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME, "DSM", sizeof(*data), NULL); @@ -743,24 +739,66 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, data->revision); goto out; } + fwrt->dsm_revision = data->revision; + fwrt->dsm_source = BIOS_SOURCE_UEFI; - if (!(data->functions[DSM_FUNC_QUERY] & BIT(func))) { - IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", - func, data->functions[DSM_FUNC_QUERY]); - goto out; - } + fwrt->dsm_funcs_valid = data->functions[DSM_FUNC_QUERY]; - *value = data->functions[func]; + /* + * Make sure we don't load the DSM values twice. Set this only after we + * validated the DSM table so that if the table in UEFI is not valid, + * we will fallback to ACPI. + */ + fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY); - IWL_DEBUG_RADIO(fwrt, - "UEFI: DSM func=%d: value=%d\n", func, *value); + for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) { + if (!(fwrt->dsm_funcs_valid & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", + func, fwrt->dsm_funcs_valid); + continue; + } + fwrt->dsm_values[func] = data->functions[func]; + + IWL_DEBUG_RADIO(fwrt, + "UEFI: DSM func=%d: value=%d\n", func, + fwrt->dsm_values[func]); + } ret = 0; + out: kfree(data); return ret; } +int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value) +{ + /* Not supported function index */ + if (func >= DSM_FUNC_NUM_FUNCS || func == 5) + return -EOPNOTSUPP; + + if (!fwrt->dsm_funcs_valid) { + int ret = iwl_uefi_load_dsm_values(fwrt); + + if (ret) + return ret; + } + + if (!(fwrt->dsm_funcs_valid & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", + func, fwrt->dsm_funcs_valid); + return -EINVAL; + } + + *value = fwrt->dsm_values[func]; + + IWL_DEBUG_RADIO(fwrt, + "UEFI: DSM func=%d: value=%d\n", func, *value); + + return 0; +} + int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt) { struct uefi_cnv_var_puncturing_data *data; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 5a4c557e47c7..349ac1505ad7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -60,7 +60,7 @@ struct uefi_cnv_wlan_sgom_data { struct uefi_cnv_wlan_uats_data { u8 revision; - u8 offset_map[IWL_UATS_MAP_SIZE - 1]; + u8 mcc_to_ap_type_map[IWL_UATS_MAP_SIZE - 1]; } __packed; struct uefi_cnv_common_step_data { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 076810ee5d34..45cf2bc68e41 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -687,7 +687,6 @@ extern const char iwl_killer_bn1850w2_name[]; extern const char iwl_killer_bn1850i_name[]; extern const char iwl_bn201_name[]; extern const char iwl_bn203_name[]; -extern const char iwl_be221_name[]; extern const char iwl_be223_name[]; extern const char iwl_ax221_name[]; #if IS_ENABLED(CONFIG_IWLDVM) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/Makefile b/drivers/net/wireless/intel/iwlwifi/mld/Makefile index c966e573f430..5740c0510b61 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mld/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += tests/ iwlmld-y += mld.o notif.o mac80211.o fw.o power.o iface.o link.o rx.o mcc.o session-protect.o phy.o iwlmld-y += scan.o sta.o tx.o coex.o tlc.o agg.o key.o regulatory.o ap.o thermal.o roc.o stats.o -iwlmld-y += low_latency.o mlo.o ptp.o time_sync.o ftm-initiator.o +iwlmld-y += low_latency.o mlo.o ptp.o time_sync.o ftm-initiator.o nan.o iwlmld-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o iwlmld-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmld-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index dd85be94433c..6595542e95cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -996,8 +996,6 @@ static void iwl_mld_mlo_rekey(struct iwl_mld *mld, struct iwl_mld_wowlan_status *wowlan_status, struct ieee80211_vif *vif) { - struct iwl_mld_old_mlo_keys *old_keys __free(kfree) = NULL; - IWL_DEBUG_WOWLAN(mld, "Num of MLO Keys: %d\n", wowlan_status->num_mlo_keys); if (!wowlan_status->num_mlo_keys) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c index b9c9cd3f44e4..5c2a2033b3fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c @@ -244,7 +244,7 @@ static size_t iwl_mld_dump_tas_resp(struct iwl_dhc_tas_status_resp *resp, } pos += scnprintf(buf + pos, count - pos, "TAS Report\n"); - switch (resp->tas_config_info.table_source) { + switch (resp->tas_config_info.hdr.table_source) { case BIOS_SOURCE_NONE: pos += scnprintf(buf + pos, count - pos, "BIOS SOURCE NONE "); @@ -260,13 +260,13 @@ static size_t iwl_mld_dump_tas_resp(struct iwl_dhc_tas_status_resp *resp, default: pos += scnprintf(buf + pos, count - pos, "BIOS SOURCE UNKNOWN (%d) ", - resp->tas_config_info.table_source); + resp->tas_config_info.hdr.table_source); break; } pos += scnprintf(buf + pos, count - pos, "revision is: %d data is: 0x%08x\n", - resp->tas_config_info.table_revision, + resp->tas_config_info.hdr.table_revision, resp->tas_config_info.value); pos += scnprintf(buf + pos, count - pos, "Current MCC: 0x%x\n", le16_to_cpu(resp->curr_mcc)); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index a5ececfc13e4..3ca3e169738e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -339,6 +339,10 @@ int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif, lockdep_assert_wiphy(mld->wiphy); + /* NAN interface type is not known to FW */ + if (vif->type == NL80211_IFTYPE_NAN) + return 0; + if (action == FW_CTXT_ACTION_REMOVE) return iwl_mld_rm_mac_from_fw(mld, vif); @@ -387,21 +391,16 @@ static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy, IWL_MLD_ALLOC_FN(vif, vif) /* Constructor function for struct iwl_mld_vif */ -static int +static void iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - int ret; lockdep_assert_wiphy(mld->wiphy); mld_vif->mld = mld; mld_vif->roc_activity = ROC_NUM_ACTIVITIES; - ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif); - if (ret) - return ret; - if (!mld->fw_status.in_hw_restart) { wiphy_work_init(&mld_vif->emlsr.unblock_tpt_wk, iwl_mld_emlsr_unblock_tpt_wk); @@ -415,8 +414,6 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) iwl_mld_mlo_scan_start_wk); } iwl_mld_init_internal_sta(&mld_vif->aux_sta); - - return 0; } int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) @@ -426,7 +423,13 @@ int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) lockdep_assert_wiphy(mld->wiphy); - ret = iwl_mld_init_vif(mld, vif); + iwl_mld_init_vif(mld, vif); + + /* NAN interface type is not known to FW */ + if (vif->type == NL80211_IFTYPE_NAN) + return 0; + + ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h index a3573d20f214..62fca166afd1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h @@ -32,6 +32,7 @@ enum iwl_mld_cca_40mhz_wa_status { * 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_MLD_EMLSR_BLOCKED_TPT: throughput is too low to make EMLSR worthwhile + * @IWL_MLD_EMLSR_BLOCKED_NAN: NAN is preventing EMLSR. */ enum iwl_mld_emlsr_blocked { IWL_MLD_EMLSR_BLOCKED_PREVENTION = 0x1, @@ -40,6 +41,7 @@ enum iwl_mld_emlsr_blocked { IWL_MLD_EMLSR_BLOCKED_NON_BSS = 0x8, IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS = 0x10, IWL_MLD_EMLSR_BLOCKED_TPT = 0x20, + IWL_MLD_EMLSR_BLOCKED_NAN = 0x40, }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 55b484c16280..df8221277d51 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -50,7 +50,7 @@ { \ .max = 1, \ .types = BIT(NL80211_IFTYPE_P2P_DEVICE), \ - } + }, static const struct ieee80211_iface_limit iwl_mld_limits[] = { IWL_MLD_LIMITS(0) @@ -60,6 +60,22 @@ static const struct ieee80211_iface_limit iwl_mld_limits_ap[] = { IWL_MLD_LIMITS(BIT(NL80211_IFTYPE_AP)) }; +static const struct ieee80211_iface_limit iwl_mld_limits_nan[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_NAN), + }, + /* Removed when two channels are permitted */ + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + static const struct ieee80211_iface_combination iwl_mld_iface_combinations[] = { { @@ -74,6 +90,19 @@ iwl_mld_iface_combinations[] = { .limits = iwl_mld_limits_ap, .n_limits = ARRAY_SIZE(iwl_mld_limits_ap), }, + /* NAN combinations follow, these exclude P2P */ + { + .num_different_channels = 2, + .max_interfaces = 3, + .limits = iwl_mld_limits_nan, + .n_limits = ARRAY_SIZE(iwl_mld_limits_nan) - 1, + }, + { + .num_different_channels = 1, + .max_interfaces = 4, + .limits = iwl_mld_limits_nan, + .n_limits = ARRAY_SIZE(iwl_mld_limits_nan), + } }; static const u8 ext_capa_base[IWL_MLD_STA_EXT_CAPA_SIZE] = { @@ -305,8 +334,38 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) wiphy->hw_timestamp_max_peers = 1; - wiphy->iface_combinations = iwl_mld_iface_combinations; - wiphy->n_iface_combinations = ARRAY_SIZE(iwl_mld_iface_combinations); + if (iwl_mld_nan_supported(mld)) { + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_NAN); + hw->wiphy->iface_combinations = iwl_mld_iface_combinations; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(iwl_mld_iface_combinations); + + hw->wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ); + if (mld->nvm_data->bands[NL80211_BAND_5GHZ].n_channels) + hw->wiphy->nan_supported_bands |= + BIT(NL80211_BAND_5GHZ); + + hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC | + WIPHY_NAN_FLAGS_USERSPACE_DE; + + hw->wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK | + NAN_OP_MODE_80P80MHZ | + NAN_OP_MODE_160MHZ; + + /* Support 2 antenna's for Tx and Rx */ + hw->wiphy->nan_capa.n_antennas = 0x22; + + /* Maximal channel switch time is 4 msec */ + hw->wiphy->nan_capa.max_channel_switch_time = 4; + hw->wiphy->nan_capa.dev_capabilities = + NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED | + NAN_DEV_CAPA_NDPE_SUPPORTED; + } else { + wiphy->iface_combinations = iwl_mld_iface_combinations; + /* Do not include NAN combinations */ + wiphy->n_iface_combinations = + ARRAY_SIZE(iwl_mld_iface_combinations) - 2; + } wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_CONCURRENT); @@ -318,6 +377,8 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT); if (fw_has_capa(ucode_capa, IWL_UCODE_TLV_CAPA_PROTECTED_TWT)) @@ -616,10 +677,11 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw, * Add the default link, but not if this is an MLD vif as that implies * the HW is restarting and it will be configured by change_vif_links. */ - if (!ieee80211_vif_is_mld(vif)) + if (vif->type != NL80211_IFTYPE_NAN && !ieee80211_vif_is_mld(vif)) { ret = iwl_mld_add_link(mld, &vif->bss_conf); - if (ret) - goto err; + if (ret) + goto err; + } if (vif->type == NL80211_IFTYPE_STATION) { vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC; @@ -647,6 +709,9 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_P2P_DEVICE) mld->p2p_device_vif = vif; + if (vif->type == NL80211_IFTYPE_NAN) + mld->nan_device_vif = vif; + return 0; err: @@ -674,7 +739,10 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_P2P_DEVICE) mld->p2p_device_vif = NULL; - iwl_mld_remove_link(mld, &vif->bss_conf); + if (vif->type == NL80211_IFTYPE_NAN) + mld->nan_device_vif = NULL; + else + iwl_mld_remove_link(mld, &vif->bss_conf); #ifdef CONFIG_IWLWIFI_DEBUGFS debugfs_remove(iwl_mld_vif_from_mac80211(vif)->dbgfs_slink); @@ -984,7 +1052,9 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, { struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); - unsigned int n_active = iwl_mld_count_active_links(mld, vif); + struct iwl_mld_link *temp_mld_link; + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + u16 final_active_links = 0; int ret; lockdep_assert_wiphy(mld->wiphy); @@ -992,10 +1062,7 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, if (WARN_ON(!mld_link)) return -EINVAL; - /* if the assigned one was not counted yet, count it now */ if (!rcu_access_pointer(mld_link->chan_ctx)) { - n_active++; - /* Track addition of non-BSS link */ if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { ret = iwl_mld_emlsr_check_non_bss_block(mld, 1); @@ -1016,17 +1083,25 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, rcu_assign_pointer(mld_link->chan_ctx, ctx); - if (n_active > 1) { - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + /* We cannot rely on vif->active_links at this stage as it contains + * both the removed links and the newly added links. + * Therefore, we create our own bitmap of the final active links, + * which does not include the removed links. + */ + for_each_mld_vif_valid_link(mld_vif, temp_mld_link) { + if (rcu_access_pointer(temp_mld_link->chan_ctx)) + final_active_links |= BIT(link_id); + } + if (hweight16(final_active_links) > 1) { /* Indicate to mac80211 that EML is enabled */ vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE; mld_vif->emlsr.last_entry_ts = jiffies; - if (vif->active_links & BIT(mld_vif->emlsr.selected_links)) + if (final_active_links == mld_vif->emlsr.selected_links) mld_vif->emlsr.primary = mld_vif->emlsr.selected_primary; else - mld_vif->emlsr.primary = __ffs(vif->active_links); + mld_vif->emlsr.primary = __ffs(final_active_links); iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP, NULL); @@ -1506,6 +1581,9 @@ iwl_mld_mac80211_conf_tx(struct ieee80211_hw *hw, lockdep_assert_wiphy(mld->wiphy); + if (vif->type == NL80211_IFTYPE_NAN) + return 0; + link = iwl_mld_link_dereference_check(mld_vif, link_id); if (!link) return -EINVAL; @@ -1706,6 +1784,9 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld, /* Ensure any block due to a non-BSS link is synced */ iwl_mld_emlsr_check_non_bss_block(mld, 0); + /* Ensure NAN block is synced */ + iwl_mld_emlsr_check_nan_block(mld, vif); + /* Block EMLSR until a certain throughput it reached */ if (!mld->fw_status.in_hw_restart && IWL_MLD_ENTER_EMLSR_TPT_THRESH > 0) @@ -2699,4 +2780,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = { .set_hw_timestamp = iwl_mld_set_hw_timestamp, .start_pmsr = iwl_mld_start_pmsr, .can_neg_ttlm = iwl_mld_can_neg_ttlm, + .start_nan = iwl_mld_start_nan, + .stop_nan = iwl_mld_stop_nan, + .nan_change_conf = iwl_mld_nan_change_config, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index 8a4c96385640..495e9d8f3af6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -234,6 +234,9 @@ static const struct iwl_hcmd_names iwl_mld_mac_conf_names[] = { HCMD_NAME(AUX_STA_CMD), HCMD_NAME(STA_REMOVE_CMD), HCMD_NAME(ROC_CMD), + HCMD_NAME(NAN_CFG_CMD), + HCMD_NAME(NAN_DW_END_NOTIF), + HCMD_NAME(NAN_JOINED_CLUSTER_NOTIF), HCMD_NAME(MISSED_BEACONS_NOTIF), HCMD_NAME(EMLSR_TRANS_FAIL_NOTIF), HCMD_NAME(ROC_NOTIF), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index 22efe8e10f53..66c7a7d31409 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -35,6 +35,7 @@ #include "ptp.h" #include "time_sync.h" #include "ftm-initiator.h" +#include "nan.h" /** * DOC: Introduction @@ -199,6 +200,7 @@ * @ptp_data: data of the PTP clock * @time_sync: time sync data. * @ftm_initiator: FTM initiator data + * @nan_device_vif: points to the NAN device vif if exists */ struct iwl_mld { /* Add here fields that need clean up on restart */ @@ -228,6 +230,7 @@ struct iwl_mld { #endif /* CONFIG_PM_SLEEP */ struct ieee80211_vif *p2p_device_vif; bool bt_is_active; + struct ieee80211_vif *nan_device_vif; ); struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX]; /* And here fields that survive a fw restart */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index c6b151f26921..f842f5183223 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -12,7 +12,8 @@ HOW(ROC) \ HOW(NON_BSS) \ HOW(TMP_NON_BSS) \ - HOW(TPT) + HOW(TPT) \ + HOW(NAN) static const char * iwl_mld_get_emlsr_blocked_string(enum iwl_mld_emlsr_blocked blocked) @@ -451,29 +452,49 @@ static void iwl_mld_count_non_bss_links(void *_data, u8 *mac, struct iwl_mld_update_emlsr_block_data { bool block; + enum iwl_mld_emlsr_blocked reason; int result; }; static void -iwl_mld_vif_iter_update_emlsr_non_bss_block(void *_data, u8 *mac, - struct ieee80211_vif *vif) +iwl_mld_vif_iter_update_emlsr_block(void *_data, u8 *mac, + struct ieee80211_vif *vif) { struct iwl_mld_update_emlsr_block_data *data = _data; struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); int ret; + if (!iwl_mld_vif_has_emlsr_cap(vif)) + return; + if (data->block) { ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif, - IWL_MLD_EMLSR_BLOCKED_NON_BSS, + data->reason, iwl_mld_get_primary_link(vif)); if (ret) data->result = ret; } else { iwl_mld_unblock_emlsr(mld_vif->mld, vif, - IWL_MLD_EMLSR_BLOCKED_NON_BSS); + data->reason); } } +int iwl_mld_update_emlsr_block(struct iwl_mld *mld, bool block, + enum iwl_mld_emlsr_blocked reason) +{ + struct iwl_mld_update_emlsr_block_data block_data = { + .block = block, + .reason = reason, + }; + + ieee80211_iterate_active_interfaces_mtx(mld->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mld_vif_iter_update_emlsr_block, + &block_data); + + return block_data.result; +} + int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld, int pending_link_changes) { @@ -481,7 +502,6 @@ int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld, * block EMLSR on the bss vif. Upon deactivation, check if this link * was the last non-station link active, and if so unblock the bss vif */ - struct iwl_mld_update_emlsr_block_data block_data = {}; int count = pending_link_changes; /* No need to count if we are activating a non-BSS link */ @@ -495,14 +515,8 @@ int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld, * We could skip updating it if the block change did not change (and * pending_link_changes is non-zero). */ - block_data.block = !!count; - - ieee80211_iterate_active_interfaces_mtx(mld->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mld_vif_iter_update_emlsr_non_bss_block, - &block_data); - - return block_data.result; + return iwl_mld_update_emlsr_block(mld, !!count, + IWL_MLD_EMLSR_BLOCKED_NON_BSS); } #define EMLSR_SEC_LINK_MIN_PERC 10 @@ -844,9 +858,9 @@ iwl_mld_emlsr_pair_state(struct ieee80211_vif *vif, if (c_low->chan->center_freq > c_high->chan->center_freq) swap(c_low, c_high); - c_low_upper_edge = c_low->chan->center_freq + + c_low_upper_edge = c_low->center_freq1 + cfg80211_chandef_get_width(c_low) / 2; - c_high_lower_edge = c_high->chan->center_freq - + c_high_lower_edge = c_high->center_freq1 - cfg80211_chandef_get_width(c_high) / 2; if (a->chandef->chan->band == NL80211_BAND_5GHZ && @@ -1197,3 +1211,16 @@ void iwl_mld_stop_ignoring_tpt_updates(struct iwl_mld *mld) iwl_mld_ignore_tpt_iter, &start); } + +int iwl_mld_emlsr_check_nan_block(struct iwl_mld *mld, struct ieee80211_vif *vif) +{ + if (mld->nan_device_vif && + ieee80211_vif_nan_started(mld->nan_device_vif)) + return iwl_mld_block_emlsr_sync(mld, vif, + IWL_MLD_EMLSR_BLOCKED_NAN, + iwl_mld_get_primary_link(vif)); + + iwl_mld_unblock_emlsr(mld, vif, IWL_MLD_EMLSR_BLOCKED_NAN); + + return 0; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.h b/drivers/net/wireless/intel/iwlwifi/mld/mlo.h index d936589fe39d..ccc3a7afa095 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.h @@ -150,6 +150,11 @@ void iwl_mld_emlsr_check_chan_load(struct ieee80211_hw *hw, */ void iwl_mld_retry_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif); +int iwl_mld_emlsr_check_nan_block(struct iwl_mld *mld, struct ieee80211_vif *vif); + +int iwl_mld_update_emlsr_block(struct iwl_mld *mld, bool block, + enum iwl_mld_emlsr_blocked reason); + struct iwl_mld_link_sel_data { u8 link_id; const struct cfg80211_chan_def *chandef; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c new file mode 100644 index 000000000000..2dbd3d58b0c6 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include "mld.h" +#include "iface.h" +#include "mlo.h" +#include "fw/api/mac-cfg.h" + +#define IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU 512 +#define IWL_NAN_RSSI_CLOSE 55 +#define IWL_NAN_RSSI_MIDDLE 70 + +bool iwl_mld_nan_supported(struct iwl_mld *mld) +{ + return fw_has_capa(&mld->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT); +} + +static int iwl_mld_nan_send_config_cmd(struct iwl_mld *mld, + struct iwl_nan_config_cmd *cmd, + u8 *beacon_data, size_t beacon_data_len) +{ + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD), + }; + + hcmd.len[0] = sizeof(*cmd); + hcmd.data[0] = cmd; + + if (beacon_data_len) { + hcmd.len[1] = beacon_data_len; + hcmd.data[1] = beacon_data; + hcmd.dataflags[1] = IWL_HCMD_DFL_DUP; + } + + return iwl_mld_send_cmd(mld, &hcmd); +} + +static int iwl_mld_nan_config(struct iwl_mld *mld, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf, + enum iwl_ctxt_action action) +{ + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_nan_config_cmd cmd = { + .action = cpu_to_le32(action), + }; + u8 *data __free(kfree) = NULL; + + lockdep_assert_wiphy(mld->wiphy); + + ether_addr_copy(cmd.nmi_addr, vif->addr); + cmd.master_pref = conf->master_pref; + + if (conf->cluster_id) + memcpy(cmd.cluster_id, conf->cluster_id + 4, + sizeof(cmd.cluster_id)); + + cmd.scan_period = conf->scan_period < 255 ? conf->scan_period : 255; + cmd.dwell_time = + conf->scan_dwell_time < 255 ? conf->scan_dwell_time : 255; + + if (conf->discovery_beacon_interval) + cmd.discovery_beacon_interval = + cpu_to_le32(conf->discovery_beacon_interval); + else + cmd.discovery_beacon_interval = + cpu_to_le32(IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU); + + if (conf->enable_dw_notification) + cmd.flags = IWL_NAN_FLAG_DW_END_NOTIF_ENABLED; + + /* 2 GHz band must be supported */ + cmd.band_config[IWL_NAN_BAND_2GHZ].rssi_close = + abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close); + cmd.band_config[IWL_NAN_BAND_2GHZ].rssi_middle = + abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle); + cmd.band_config[IWL_NAN_BAND_2GHZ].dw_interval = + conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval; + + /* 5 GHz band operation is optional. Configure its operation if + * supported. Note that conf->bands might be zero, so we need to check + * the channel pointer, not the band mask. + */ + if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) { + cmd.hb_channel = + conf->band_cfgs[NL80211_BAND_5GHZ].chan->hw_value; + + cmd.band_config[IWL_NAN_BAND_5GHZ].rssi_close = + abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close); + cmd.band_config[IWL_NAN_BAND_5GHZ].rssi_middle = + abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle); + cmd.band_config[IWL_NAN_BAND_5GHZ].dw_interval = + conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval; + } + + if (conf->extra_nan_attrs_len || conf->vendor_elems_len) { + data = kmalloc(conf->extra_nan_attrs_len + + conf->vendor_elems_len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + cmd.nan_attr_len = cpu_to_le32(conf->extra_nan_attrs_len); + cmd.nan_vendor_elems_len = cpu_to_le32(conf->vendor_elems_len); + + if (conf->extra_nan_attrs_len) + memcpy(data, conf->extra_nan_attrs, + conf->extra_nan_attrs_len); + + if (conf->vendor_elems_len) + memcpy(data + conf->extra_nan_attrs_len, + conf->vendor_elems, + conf->vendor_elems_len); + } + + cmd.sta_id = mld_vif->aux_sta.sta_id; + return iwl_mld_nan_send_config_cmd(mld, &cmd, data, + conf->extra_nan_attrs_len + + conf->vendor_elems_len); +} + +int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta; + int ret; + + IWL_DEBUG_MAC80211(mld, "NAN: start: bands=0x%x\n", conf->bands); + + ret = iwl_mld_update_emlsr_block(mld, true, IWL_MLD_EMLSR_BLOCKED_NAN); + if (ret) + return ret; + + ret = iwl_mld_add_aux_sta(mld, aux_sta); + if (ret) + goto unblock_emlsr; + + ret = iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_ADD); + if (ret) { + IWL_ERR(mld, "Failed to start NAN. ret=%d\n", ret); + goto remove_aux; + } + return 0; + +remove_aux: + iwl_mld_remove_aux_sta(mld, vif); +unblock_emlsr: + iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN); + + return ret; +} + +int iwl_mld_nan_change_config(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf, + u32 changes) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + + IWL_DEBUG_MAC80211(mld, "NAN: change: changes=0x%x, bands=0x%x\n", + changes, conf->bands); + + /* Note that we do not use 'changes' as the FW always expects the + * complete configuration, and mac80211 always provides the complete + * configuration. + */ + return iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_MODIFY); +} + +int iwl_mld_stop_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_nan_config_cmd cmd = { + .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), + }; + int ret; + + lockdep_assert_wiphy(mld->wiphy); + + ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD), + &cmd); + if (ret) + IWL_ERR(mld, "NAN: Failed to stop NAN. ret=%d\n", ret); + + /* assume that higher layer guarantees that no additional frames are + * added before calling this callback + */ + iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id); + iwl_mld_remove_aux_sta(mld, vif); + + /* cancel based on object type being NAN, as the NAN objects do + * not have a unique identifier associated with them + */ + iwl_mld_cancel_notifications_of_object(mld, + IWL_MLD_OBJECT_TYPE_NAN, + 0); + + iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN); + + return 0; +} + +void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt) +{ + struct iwl_nan_cluster_notif *notif = (void *)pkt->data; + struct wireless_dev *wdev = mld->nan_device_vif ? + ieee80211_vif_to_wdev(mld->nan_device_vif) : NULL; + bool new_cluster = !!(notif->flags & + IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER); + u8 cluster_id[ETH_ALEN] = { + 0x50, 0x6f, 0x9a, 0x01, + notif->cluster_id[0], notif->cluster_id[1] + }; + + IWL_DEBUG_INFO(mld, + "NAN: cluster event: cluster_id=%pM, flags=0x%x\n", + cluster_id, notif->flags); + + if (IWL_FW_CHECK(mld, !wdev, "NAN: cluster event without wdev\n")) + return; + + if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif), + "NAN: cluster event without NAN started\n")) + return; + + cfg80211_nan_cluster_joined(wdev, cluster_id, new_cluster, GFP_KERNEL); +} + +bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt, + u32 obj_id) +{ + return true; +} + +bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt, + u32 obj_id) +{ + return true; +} + +void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt) +{ + struct iwl_nan_dw_end_notif *notif = (void *)pkt->data; + struct iwl_mld_vif *mld_vif = mld->nan_device_vif ? + iwl_mld_vif_from_mac80211(mld->nan_device_vif) : + NULL; + struct wireless_dev *wdev; + struct ieee80211_channel *chan; + + IWL_INFO(mld, "NAN: DW end: band=%u\n", notif->band); + + if (IWL_FW_CHECK(mld, !mld_vif, "NAN: DW end without mld_vif\n")) + return; + + if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif), + "NAN: DW end without NAN started\n")) + return; + + if (WARN_ON(mld_vif->aux_sta.sta_id == IWL_INVALID_STA)) + return; + + IWL_DEBUG_INFO(mld, "NAN: flush queues for aux sta=%u\n", + mld_vif->aux_sta.sta_id); + + iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id); + + /* TODO: currently the notification specified the band on which the DW + * ended. Need to change that to the actual channel on which the next DW + * will be started. + */ + switch (notif->band) { + case IWL_NAN_BAND_2GHZ: + chan = ieee80211_get_channel(mld->wiphy, 2437); + break; + case IWL_NAN_BAND_5GHZ: + /* TODO: use the actual channel */ + chan = ieee80211_get_channel(mld->wiphy, 5745); + break; + default: + IWL_FW_CHECK(mld, false, + "NAN: Invalid band %u in DW end notif\n", + notif->band); + return; + } + + wdev = ieee80211_vif_to_wdev(mld->nan_device_vif); + cfg80211_next_nan_dw_notif(wdev, chan, GFP_KERNEL); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.h b/drivers/net/wireless/intel/iwlwifi/mld/nan.h new file mode 100644 index 000000000000..c9c83d1012f0 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include <net/cfg80211.h> +#include <linux/etherdevice.h> + +bool iwl_mld_nan_supported(struct iwl_mld *mld); +int iwl_mld_start_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf); +int iwl_mld_nan_change_config(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf, + u32 changes); +int iwl_mld_stop_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt); +void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt); +bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt, + u32 obj_id); +bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt, + u32 obj_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 4cf3920b005f..35356b244c0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -111,6 +111,9 @@ static bool iwl_mld_cancel_##name##_notif(struct iwl_mld *mld, \ #define RX_HANDLER_OF_FTM_REQ(_grp, _cmd, _name) \ RX_HANDLER_OF_OBJ(_grp, _cmd, _name, FTM_REQ) +#define RX_HANDLER_OF_NAN(_grp, _cmd, _name) \ + RX_HANDLER_OF_OBJ(_grp, _cmd, _name, NAN) + static void iwl_mld_handle_mfuart_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt) { @@ -344,6 +347,8 @@ CMD_VERSIONS(time_sync_confirm_notif, CMD_VER_ENTRY(1, iwl_time_msmt_cfm_notify)) CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy)) CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif)) +CMD_VERSIONS(nan_cluster_notif, CMD_VER_ENTRY(1, iwl_nan_cluster_notif)) +CMD_VERSIONS(nan_dw_end_notif, CMD_VER_ENTRY(1, iwl_nan_dw_end_notif)) DEFINE_SIMPLE_CANCELLATION(session_prot, iwl_session_prot_notif, mac_link_id) DEFINE_SIMPLE_CANCELLATION(tlc, iwl_tlc_update_notif, sta_id) @@ -459,6 +464,10 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = { beacon_filter_notif) RX_HANDLER_OF_FTM_REQ(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF, ftm_resp_notif) + RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_JOINED_CLUSTER_NOTIF, + nan_cluster_notif) + RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_DW_END_NOTIF, + nan_dw_end_notif) }; EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_rx_handlers); @@ -531,6 +540,8 @@ static void iwl_mld_rx_notif(struct iwl_mld *mld, struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_packet *pkt) { + union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; + for (int i = 0; i < ARRAY_SIZE(iwl_mld_rx_handlers); i++) { const struct iwl_rx_handler *rx_h = &iwl_mld_rx_handlers[i]; struct iwl_async_handler_entry *entry; @@ -571,6 +582,8 @@ static void iwl_mld_rx_notif(struct iwl_mld *mld, } iwl_notification_wait_notify(&mld->notif_wait, pkt); + iwl_dbg_tlv_time_point(&mld->fwrt, + IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF, &tp_data); } void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.h b/drivers/net/wireless/intel/iwlwifi/mld/notif.h index adcdd9dec192..373c1a90d98e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.h @@ -25,6 +25,7 @@ enum iwl_mld_object_type { IWL_MLD_OBJECT_TYPE_ROC, IWL_MLD_OBJECT_TYPE_SCAN, IWL_MLD_OBJECT_TYPE_FTM_REQ, + IWL_MLD_OBJECT_TYPE_NAN, }; void iwl_mld_cancel_notifications_of_object(struct iwl_mld *mld, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/power.c b/drivers/net/wireless/intel/iwlwifi/mld/power.c index f664b277adf7..c3318e84f4a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/power.c @@ -328,6 +328,33 @@ iwl_mld_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd, link->tpe.max_reg_client[0].power[i]); } +static int +iwl_mld_set_ap_power_type(struct iwl_txpower_constraints_cmd *cmd, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link) +{ + if (vif->type == NL80211_IFTYPE_AP) { + cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); + return 0; + } + + switch (link->power_type) { + case IEEE80211_REG_LPI_AP: + cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_LPI); + break; + case IEEE80211_REG_SP_AP: + cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_SP); + break; + case IEEE80211_REG_VLP_AP: + cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); + break; + default: + return -EINVAL; + } + + return 0; +} + void iwl_mld_send_ap_tx_power_constraint_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, @@ -349,15 +376,13 @@ iwl_mld_send_ap_tx_power_constraint_cmd(struct iwl_mld *mld, memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr)); memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr)); - if (vif->type == NL80211_IFTYPE_AP) { - cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); - } else if (link->power_type == IEEE80211_REG_UNSET_AP) { + if (iwl_mld_set_ap_power_type(&cmd, vif, link)) return; - } else { - cmd.ap_type = cpu_to_le16(link->power_type - 1); + + if (vif->type != NL80211_IFTYPE_AP) iwl_mld_tpe_sta_cmd_data(&cmd, link); - } + IWL_DEBUG_POWER(mld, "AP power type: %d\n", le16_to_cpu(cmd.ap_type)); ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(PHY_OPS_GROUP, AP_TX_POWER_CONSTRAINTS_CMD), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index 40571125b3ab..6ab5a3410353 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c @@ -165,8 +165,8 @@ static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld) { struct iwl_fw_runtime *fwrt = &mld->fwrt; union iwl_ppag_table_cmd cmd = { - .v7.ppag_config_info.table_source = fwrt->ppag_bios_source, - .v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev, + .v7.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source, + .v7.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev, .v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags), }; int ret; @@ -206,11 +206,27 @@ int iwl_mld_init_ppag(struct iwl_mld *mld) return iwl_mld_ppag_send_cmd(mld); } +static __le32 iwl_mld_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) +{ + int ret; + u32 val; + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); + if (!ret) { + if (val == DSM_VALUE_SRD_PASSIVE) + return cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); + else if (val == DSM_VALUE_SRD_DISABLE) + return cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + } + + return 0; +} + void iwl_mld_configure_lari(struct iwl_mld *mld) { struct iwl_fw_runtime *fwrt = &mld->fwrt; struct iwl_lari_config_change_cmd cmd = { - .config_bitmap = iwl_get_lari_config_bitmap(fwrt), + .config_bitmap = iwl_mld_get_lari_config_bitmap(fwrt), }; bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE); @@ -265,6 +281,14 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) if (!ret) cmd.oem_11be_allow_bitmap = cpu_to_le32(value); + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BN, &value); + if (!ret) + cmd.oem_11bn_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII_9, &value); + if (!ret) + cmd.oem_unii9_enable = cpu_to_le32(value); + if (!cmd.config_bitmap && !cmd.oem_uhb_allow_bitmap && !cmd.oem_11ax_allow_bitmap && @@ -273,9 +297,14 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) !cmd.force_disable_channels_bitmap && !cmd.edt_bitmap && !cmd.oem_320mhz_allow_bitmap && - !cmd.oem_11be_allow_bitmap) + !cmd.oem_11be_allow_bitmap && + !cmd.oem_11bn_allow_bitmap && + !cmd.oem_unii9_enable) return; + cmd.bios_hdr.table_source = fwrt->dsm_source; + cmd.bios_hdr.table_revision = fwrt->dsm_revision; + IWL_DEBUG_RADIO(mld, "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", le32_to_cpu(cmd.config_bitmap), @@ -295,9 +324,28 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) IWL_DEBUG_RADIO(mld, "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n", le32_to_cpu(cmd.oem_11be_allow_bitmap)); - - ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(REGULATORY_AND_NVM_GROUP, - LARI_CONFIG_CHANGE), &cmd); + IWL_DEBUG_RADIO(mld, + "sending LARI_CONFIG_CHANGE, oem_11bn_allow_bitmap=0x%x\n", + le32_to_cpu(cmd.oem_11bn_allow_bitmap)); + IWL_DEBUG_RADIO(mld, + "sending LARI_CONFIG_CHANGE, oem_unii9_enable=0x%x\n", + le32_to_cpu(cmd.oem_unii9_enable)); + + if (iwl_fw_lookup_cmd_ver(mld->fw, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), 12) == 12) { + int cmd_size = offsetof(typeof(cmd), oem_11bn_allow_bitmap); + + ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), + &cmd, cmd_size); + } else { + ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), + &cmd); + } if (ret) IWL_DEBUG_RADIO(mld, "Failed to send LARI_CONFIG_CHANGE (%d)\n", @@ -373,8 +421,8 @@ void iwl_mld_init_tas(struct iwl_mld *mld) for (u8 i = 0; i < data.block_list_size; i++) cmd.block_list_array[i] = cpu_to_le16(data.block_list_array[i]); - cmd.tas_config_info.table_source = data.table_source; - cmd.tas_config_info.table_revision = data.table_revision; + cmd.tas_config_info.hdr.table_source = data.table_source; + cmd.tas_config_info.hdr.table_revision = data.table_revision; cmd.tas_config_info.value = cpu_to_le32(data.tas_selection); ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 6a76e3fcb581..214dcfde2fb4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -208,6 +208,134 @@ static void iwl_mld_fill_signal(struct iwl_mld *mld, int link_id, } static void +iwl_mld_decode_vht_phy_data(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_vht *vht, + struct ieee80211_rx_status *rx_status) +{ + bool stbc; + + vht->known = cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH | + IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID | + IEEE80211_RADIOTAP_VHT_KNOWN_STBC | + IEEE80211_RADIOTAP_VHT_KNOWN_GI | + IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS | + IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM | + IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED); + + switch (le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_BANDWIDTH)) { + case 0: + vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_20; + break; + case 1: + vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_40; + break; + case 2: + vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_80; + break; + case 3: + vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_160; + break; + } + + vht->group_id = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_GRP_ID); + + stbc = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_STBC); + if (stbc) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; + + if (le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_SHORT_GI)) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; + + if (le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_SHORT_GI_AMBIG)) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9; + + if (le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_CODING_EXTRA_SYM)) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM; + + if (vht->group_id != 0 && vht->group_id != 63) { + /* MU frame */ + int user = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_MU_MIMO_USER_POSITION); + int nsts; + + /* Always beamformed */ + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED; + + /* No MCS information in the a1/a2 data for MU frames */ + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_STS_USER0); + vht->mcs_nss[0] = (stbc ? nsts / 2 : nsts) | 0xf0; + + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_MU_STS_USER1); + vht->mcs_nss[1] = (stbc ? nsts / 2 : nsts) | 0xf0; + + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_MU_STS_USER2); + vht->mcs_nss[2] = (stbc ? nsts / 2 : nsts) | 0xf0; + + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_MU_STS_USER3); + vht->mcs_nss[3] = (stbc ? nsts / 2 : nsts) | 0xf0; + + /* Report current user MCS from rate_n_flags via rx_status */ + vht->mcs_nss[user] &= 0x0f; + vht->mcs_nss[user] |= rx_status->rate_idx << 4; + + /* Report LDPC for current user */ + if (rx_status->enc_flags & RX_ENC_FLAG_LDPC) + vht->coding = 0x1 << user; + } else { + int nsts; + + /* SU frame */ + vht->known |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID); + + if (le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_BF_OR_MU_RESERVED)) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED; + + vht->partial_aid = + cpu_to_le16(le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_PARTIAL_AID_OR_MU_STS)); + + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_STS) + 1; + vht->mcs_nss[0] = + (stbc ? nsts / 2 : nsts) | + le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_MCS_OR_MU_CODING) << 4; + vht->mcs_nss[1] = 0; + vht->mcs_nss[2] = 0; + vht->mcs_nss[3] = 0; + + if (rx_status->enc_flags & RX_ENC_FLAG_LDPC) + vht->coding = 0x1; + } +} + +static void iwl_mld_rx_vht(struct sk_buff *skb, + struct iwl_mld_rx_phy_data *phy_data) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_radiotap_vht *vht; + + if (likely(!phy_data->ntfy)) + return; + + vht = skb_put_zero(skb, sizeof(*vht)); + rx_status->flag |= RX_FLAG_RADIOTAP_VHT; + + iwl_mld_decode_vht_phy_data(phy_data, vht, rx_status); +} + +static void iwl_mld_he_set_ru_alloc(struct ieee80211_rx_status *rx_status, struct ieee80211_radiotap_he *he, u8 ru_with_p80) @@ -268,11 +396,11 @@ iwl_mld_decode_he_mu(struct iwl_mld_rx_phy_data *phy_data, { u32 rate_n_flags = phy_data->rate_n_flags; - he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, - OFDM_RX_FRAME_HE_SIGB_DCM, + he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_DCM, IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); - he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, - OFDM_RX_FRAME_HE_SIGB_MCS, + he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_MCS, IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, OFDM_RX_FRAME_HE_PRMBL_PUNC_TYPE, @@ -280,7 +408,7 @@ iwl_mld_decode_he_mu(struct iwl_mld_rx_phy_data *phy_data, he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, OFDM_RX_FRAME_HE_MU_NUM_OF_SIGB_SYM_OR_USER_NUM, IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); - he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, + he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, OFDM_RX_FRAME_HE_MU_SIGB_COMP, IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); @@ -1377,6 +1505,10 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, iwl_mld_set_rx_rate(mld, phy_data, rx_status); + /* must be before HE data (radiotap field order) */ + if (format == RATE_MCS_MOD_TYPE_VHT) + iwl_mld_rx_vht(skb, phy_data); + /* must be before L-SIG data (radiotap field order) */ if (format == RATE_MCS_MOD_TYPE_HE) iwl_mld_rx_he(skb, phy_data); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c index fd1022ddc912..16f48087a888 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c @@ -1063,14 +1063,15 @@ static int iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld, struct iwl_mld_scan_params *params, struct ieee80211_vif *vif, - struct iwl_scan_req_params_v17 *scan_p, - enum iwl_mld_scan_status scan_status) + struct iwl_scan_req_params_v17 *scan_p) { struct iwl_scan_channel_params_v7 *chan_p = &scan_p->channel_params; struct iwl_scan_probe_params_v4 *probe_p = &scan_p->probe_params; - chan_p->flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif, - scan_status); + /* Explicitly clear the flags since most of them are not + * relevant for 6 GHz scan. + */ + chan_p->flags = 0; chan_p->count = iwl_mld_scan_cfg_channels_6g(mld, params, params->n_channels, probe_p, chan_p, @@ -1106,8 +1107,7 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld, if (params->scan_6ghz) return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params, - vif, scan_p, - scan_status); + vif, scan_p); /* relevant only for 2.4 GHz/5 GHz scan */ cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index 61ecc33116cf..6056a306f7cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -1163,7 +1163,8 @@ void iwl_mld_remove_aux_sta(struct iwl_mld *mld, struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); if (WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE && - vif->type != NL80211_IFTYPE_STATION)) + vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_NAN)) return; iwl_mld_remove_internal_sta(mld, &mld_vif->aux_sta, false, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c index 0e172281b0c8..62a54c37a98c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c @@ -8,6 +8,7 @@ #include "tlc.h" #include "hcmd.h" #include "sta.h" +#include "phy.h" #include "fw/api/rs.h" #include "fw/api/context.h" @@ -447,11 +448,48 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, } } -static void iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd, - struct iwl_tlc_config_cmd_v4 *cmd_v4) +static int iwl_mld_convert_tlc_cmd_to_v5(struct iwl_tlc_config_cmd *cmd, + struct iwl_tlc_config_cmd_v5 *cmd_v5) { + if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1)) + return -EINVAL; + + /* Convert sta_mask to sta_id */ + cmd_v5->sta_id = __ffs(le32_to_cpu(cmd->sta_mask)); + + /* Copy all the rest */ + cmd_v5->max_ch_width = cmd->max_ch_width; + cmd_v5->mode = cmd->mode; + cmd_v5->chains = cmd->chains; + cmd_v5->sgi_ch_width_supp = cmd->sgi_ch_width_supp; + cmd_v5->flags = cmd->flags; + cmd_v5->non_ht_rates = cmd->non_ht_rates; + + BUILD_BUG_ON(sizeof(cmd_v5->ht_rates) != sizeof(cmd->ht_rates)); + memcpy(cmd_v5->ht_rates, cmd->ht_rates, sizeof(cmd->ht_rates)); + + cmd_v5->max_mpdu_len = cmd->max_mpdu_len; + cmd_v5->max_tx_op = cmd->max_tx_op; + + return 0; +} + +static int iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd, + struct iwl_tlc_config_cmd_v4 *cmd_v4) +{ + if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1)) + return -EINVAL; + + /* Convert sta_mask to sta_id */ + cmd_v4->sta_id = __ffs(le32_to_cpu(cmd->sta_mask)); + /* Copy everything until ht_rates */ - memcpy(cmd_v4, cmd, offsetof(struct iwl_tlc_config_cmd, ht_rates)); + cmd_v4->max_ch_width = cmd->max_ch_width; + cmd_v4->mode = cmd->mode; + cmd_v4->chains = cmd->chains; + cmd_v4->sgi_ch_width_supp = cmd->sgi_ch_width_supp; + cmd_v4->flags = cmd->flags; + cmd_v4->non_ht_rates = cmd->non_ht_rates; /* Convert ht_rates from __le32 to __le16 */ BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates) != ARRAY_SIZE(cmd->ht_rates)); @@ -465,14 +503,17 @@ static void iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd, /* Copy the rest */ cmd_v4->max_mpdu_len = cmd->max_mpdu_len; cmd_v4->max_tx_op = cmd->max_tx_op; + + return 0; } static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, - enum nl80211_band band) + struct ieee80211_bss_conf *link) { struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); + enum nl80211_band band = link->chanreq.oper.chan->band; struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band]; const struct ieee80211_sta_he_cap *own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); @@ -492,25 +533,44 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD); u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0); - struct iwl_tlc_config_cmd_v4 cmd_v4; + struct ieee80211_chanctx_conf *chan_ctx; + struct iwl_tlc_config_cmd_v5 cmd_v5 = {}; + struct iwl_tlc_config_cmd_v4 cmd_v4 = {}; void *cmd_ptr; u8 cmd_size; + u32 phy_id; int ret; if (fw_sta_id < 0) return; - cmd.sta_id = fw_sta_id; + cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id)); + + chan_ctx = rcu_dereference_wiphy(mld->wiphy, link->chanctx_conf); + if (WARN_ON(!chan_ctx)) + return; + + phy_id = iwl_mld_phy_from_mac80211(chan_ctx)->fw_id; + cmd.phy_id = cpu_to_le32(phy_id); iwl_mld_fill_supp_rates(mld, vif, link_sta, sband, own_he_cap, own_eht_cap, &cmd); - if (cmd_ver == 5) { + if (cmd_ver == 6) { cmd_ptr = &cmd; cmd_size = sizeof(cmd); + } else if (cmd_ver == 5) { + /* TODO: remove support once FW moves to version 6 */ + ret = iwl_mld_convert_tlc_cmd_to_v5(&cmd, &cmd_v5); + if (ret) + return; + cmd_ptr = &cmd_v5; + cmd_size = sizeof(cmd_v5); } else if (cmd_ver == 4) { - iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4); + ret = iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4); + if (ret) + return; cmd_ptr = &cmd_v4; cmd_size = sizeof(cmd_v4); } else { @@ -520,8 +580,9 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, } IWL_DEBUG_RATE(mld, - "TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n", - cmd.sta_id, cmd.max_ch_width, cmd.mode); + "TLC CONFIG CMD, sta_mask=0x%x, max_ch_width=%d, mode=%d, phy_id=%d\n", + le32_to_cpu(cmd.sta_mask), cmd.max_ch_width, cmd.mode, + le32_to_cpu(cmd.phy_id)); /* Send async since this can be called within a RCU-read section */ ret = iwl_mld_send_cmd_with_flags_pdu(mld, cmd_id, CMD_ASYNC, cmd_ptr, @@ -561,7 +622,6 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld, struct ieee80211_link_sta *link_sta) { struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); - enum nl80211_band band; if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan)) return; @@ -575,8 +635,7 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld, ieee80211_sta_recalc_aggregates(link_sta->sta); } - band = link_conf->chanreq.oper.chan->band; - iwl_mld_send_tlc_cmd(mld, vif, link_sta, band); + iwl_mld_send_tlc_cmd(mld, vif, link_sta, link_conf); } void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c index 3b4b575aadaa..546d09a38dab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c @@ -345,6 +345,11 @@ u8 iwl_mld_get_lowest_rate(struct iwl_mld *mld, iwl_mld_get_basic_rates_and_band(mld, vif, info, &basic_rates, &band); + if (band >= NUM_NL80211_BANDS) { + WARN_ON(vif->type != NL80211_IFTYPE_NAN); + return IWL_FIRST_OFDM_RATE; + } + sband = mld->hw->wiphy->bands[band]; for_each_set_bit(i, &basic_rates, BITS_PER_LONG) { u16 hw = sband->bitrates[i].hw_value; @@ -667,6 +672,12 @@ iwl_mld_get_tx_queue_id(struct iwl_mld *mld, struct ieee80211_txq *txq, WARN_ON(!ieee80211_is_mgmt(fc)); return mld_vif->aux_sta.queue_id; + case NL80211_IFTYPE_NAN: + mld_vif = iwl_mld_vif_from_mac80211(info->control.vif); + + WARN_ON(!ieee80211_is_mgmt(fc)); + + return mld_vif->aux_sta.queue_id; default: WARN_ONCE(1, "Unsupported vif type\n"); break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 07f1a84c274e..2375fc76039f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -726,8 +726,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_time_quota_data *quota; u32 status; - if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm) || - ieee80211_vif_is_mld(vif))) + if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm))) return -EINVAL; /* add back the PHY */ @@ -1248,7 +1247,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, struct ieee80211_vif *vif = NULL; struct iwl_mvm_vif *mvmvif = NULL; struct ieee80211_sta *ap_sta = NULL; - struct iwl_mvm_vif_link_info *mvm_link; struct iwl_d3_manager_config d3_cfg_cmd = { /* * Program the minimum sleep time to 10 seconds, as many @@ -1280,13 +1278,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); - mvm_link = mvmvif->link[iwl_mvm_get_primary_link(vif)]; - if (WARN_ON_ONCE(!mvm_link)) { - ret = -EINVAL; - goto out_noreset; - } - - if (mvm_link->ap_sta_id == IWL_INVALID_STA) { + if (mvmvif->deflink.ap_sta_id == IWL_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) { ret = 1; @@ -1304,10 +1296,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, .offloading_tid = 0, }; - wowlan_config_cmd.sta_id = mvm_link->ap_sta_id; + wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id; ap_sta = rcu_dereference_protected( - mvm->fw_id_to_mac_id[mvm_link->ap_sta_id], + mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id], lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(ap_sta)) { ret = -EINVAL; @@ -1324,7 +1316,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out_noreset; ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, - vif, mvmvif, mvm_link, ap_sta); + vif, mvmvif, &mvmvif->deflink, + ap_sta); if (ret) goto out; @@ -1819,10 +1812,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, struct iwl_mvm_d3_gtk_iter_data *data = _data; struct iwl_wowlan_status_data *status = data->status; s8 keyidx; - int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - - if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id) - return; switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: @@ -1876,7 +1865,6 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, { int i, j; struct ieee80211_key_conf *key; - int link_id = vif->active_links ? __ffs(vif->active_links) : -1; for (i = 0; i < ARRAY_SIZE(status->gtk); i++) { if (!status->gtk[i].len) @@ -1888,8 +1876,7 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, status->gtk[i].key, - sizeof(status->gtk[i].key), - link_id); + sizeof(status->gtk[i].key), -1); if (IS_ERR(key)) { /* FW may send also the old keys */ if (PTR_ERR(key) == -EALREADY) @@ -1918,14 +1905,13 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_key_conf *key_config; struct ieee80211_key_seq seq; - int link_id = vif->active_links ? __ffs(vif->active_links) : -1; s8 keyidx = key_data->id; if (!key_data->len) return true; key_config = ieee80211_gtk_rekey_add(vif, keyidx, key_data->key, - sizeof(key_data->key), link_id); + sizeof(key_data->key), -1); if (IS_ERR(key_config)) { /* FW may send also the old keys */ return PTR_ERR(key_config) == -EALREADY; @@ -1935,13 +1921,9 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, ieee80211_set_key_rx_seq(key_config, 0, &seq); if (keyidx == 4 || keyidx == 5) { - struct iwl_mvm_vif_link_info *mvm_link; - - link_id = link_id < 0 ? 0 : link_id; - mvm_link = mvmvif->link[link_id]; - if (mvm_link->igtk) - mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID; - mvm_link->igtk = key_config; + if (mvmvif->deflink.igtk) + mvmvif->deflink.igtk->hw_key_idx = STA_KEY_IDX_INVALID; + mvmvif->deflink.igtk = key_config; } if (vif->type == NL80211_IFTYPE_STATION && (keyidx == 6 || keyidx == 7)) @@ -2396,23 +2378,19 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, bool keep = false; struct iwl_mvm_sta *mvm_ap_sta; 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; - if (!status) goto out_unlock; IWL_DEBUG_WOWLAN(mvm, "wakeup reason 0x%x\n", status->wakeup_reasons); - mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, mvm_link->ap_sta_id); + mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, + mvmvif->deflink.ap_sta_id); if (!mvm_ap_sta) goto out_unlock; @@ -2756,9 +2734,6 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm, u8 sta_id = mvm->net_detect ? IWL_INVALID_STA : mvmvif->deflink.ap_sta_id; - /* bug - FW with MLO has status notification */ - WARN_ON(ieee80211_vif_is_mld(vif)); - d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index edae13755ee6..43cf94c9a36b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1135,8 +1135,9 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) for (u16 i = 0; i < data.block_list_size; i++) cmd_v5.block_list_array[i] = cpu_to_le16(data.block_list_array[i]); - cmd_v5.tas_config_info.table_source = data.table_source; - cmd_v5.tas_config_info.table_revision = data.table_revision; + cmd_v5.tas_config_info.hdr.table_source = data.table_source; + cmd_v5.tas_config_info.hdr.table_revision = + data.table_revision; cmd_v5.tas_config_info.value = cpu_to_le32(data.tas_selection); } else if (fw_ver == 4) { cmd_size = sizeof(cmd_v2_v4.common) + sizeof(cmd_v2_v4.v4); @@ -1165,13 +1166,208 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret); } +static __le32 iwl_mvm_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) +{ + int ret; + u32 val; + __le32 config_bitmap = 0; + + switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) { + case IWL_CFG_RF_TYPE_HR1: + case IWL_CFG_RF_TYPE_HR2: + case IWL_CFG_RF_TYPE_JF1: + case IWL_CFG_RF_TYPE_JF2: + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, + &val); + + if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); + break; + default: + break; + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); + if (!ret) { + if (val == DSM_VALUE_SRD_PASSIVE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); + else if (val == DSM_VALUE_SRD_DISABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + } + + if (fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) { + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, + &val); + /* + * China 2022 enable if the BIOS object does not exist or + * if it is enabled in BIOS. + */ + if (ret < 0 || val & DSM_MASK_CHINA_22_REG) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK); + } + + return config_bitmap; +} + +static size_t iwl_mvm_get_lari_config_cmd_size(u8 cmd_ver) +{ + size_t cmd_size; + + switch (cmd_ver) { + case 12: + cmd_size = offsetof(struct iwl_lari_config_change_cmd, + oem_11bn_allow_bitmap); + break; + case 8: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8); + break; + case 6: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6); + break; + default: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); + break; + } + return cmd_size; +} + +static int iwl_mvm_fill_lari_config(struct iwl_fw_runtime *fwrt, + struct iwl_lari_config_change_cmd *cmd, + size_t *cmd_size) +{ + int ret; + u32 value; + bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), 1); + + memset(cmd, 0, sizeof(*cmd)); + *cmd_size = iwl_mvm_get_lari_config_cmd_size(cmd_ver); + + cmd->config_bitmap = iwl_mvm_get_lari_config_bitmap(fwrt); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_11AX_ALLOW_BITMAP; + cmd->oem_11ax_allow_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_UNII4_ALLOW_BITMAP; + + /* Since version 12, bits 4 and 5 are supported + * regardless of this capability, By pass this masking + * if firmware has capability of accepting raw DSM table. + */ + if (!has_raw_dsm_capa && cmd_ver < 12 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA)) + value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK | + DSM_VALUE_UNII4_CANADA_EN_MSK); + + cmd->oem_unii4_allow_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; + + if (!has_raw_dsm_capa && cmd_ver < 8) + value &= ~ACTIVATE_5G2_IN_WW_MASK; + + /* Since version 12, bits 5 and 6 are supported + * regardless of this capability, By pass this masking + * if firmware has capability of accepting raw DSM table. + */ + if (!has_raw_dsm_capa && cmd_ver < 12 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA)) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V8; + + cmd->chan_state_active_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value); + if (!ret) + cmd->oem_uhb_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP; + cmd->force_disable_channels_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, + &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_EDT_ALLOWED_BITMAP; + cmd->edt_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_wbem(fwrt, &value); + if (!ret) + cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value); + if (!ret) + cmd->oem_11be_allow_bitmap = cpu_to_le32(value); + + if (cmd->config_bitmap || + cmd->oem_uhb_allow_bitmap || + cmd->oem_11ax_allow_bitmap || + cmd->oem_unii4_allow_bitmap || + cmd->chan_state_active_bitmap || + cmd->force_disable_channels_bitmap || + cmd->edt_bitmap || + cmd->oem_320mhz_allow_bitmap || + cmd->oem_11be_allow_bitmap) { + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->config_bitmap), + le32_to_cpu(cmd->oem_11ax_allow_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n", + le32_to_cpu(cmd->oem_unii4_allow_bitmap), + le32_to_cpu(cmd->chan_state_active_bitmap), + cmd_ver); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n", + le32_to_cpu(cmd->oem_uhb_allow_bitmap), + le32_to_cpu(cmd->force_disable_channels_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->edt_bitmap), + le32_to_cpu(cmd->oem_320mhz_allow_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->oem_11be_allow_bitmap)); + } else { + return 1; + } + + return 0; +} + static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { struct iwl_lari_config_change_cmd cmd; size_t cmd_size; int ret; - ret = iwl_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size); + ret = iwl_mvm_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size); if (!ret) { ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 738facceb240..b5d252ece2d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -285,28 +285,6 @@ int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return ret; } -u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - /* relevant data is written with both locks held, so read with either */ - lockdep_assert(lockdep_is_held(&mvmvif->mvm->mutex) || - lockdep_is_held(&mvmvif->mvm->hw->wiphy->mtx)); - - if (!ieee80211_vif_is_mld(vif)) - return 0; - - /* In AP mode, there is no primary link */ - if (vif->type == NL80211_IFTYPE_AP) - return __ffs(vif->active_links); - - if (mvmvif->esr_active && - !WARN_ON(!(BIT(mvmvif->primary_link) & vif->active_links))) - return mvmvif->primary_link; - - return __ffs(vif->active_links); -} - void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link) { link->bcast_sta.sta_id = IWL_INVALID_STA; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 867807abde66..0e5820c13523 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -873,7 +873,6 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_supported_band *sband; unsigned long basic = vif->bss_conf.basic_rates; u16 lowest_cck = IWL_RATE_COUNT, lowest_ofdm = IWL_RATE_COUNT; @@ -883,16 +882,6 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm, u8 rate; u32 i; - if (link_id == IEEE80211_LINK_UNSPECIFIED && ieee80211_vif_is_mld(vif)) { - for (i = 0; i < ARRAY_SIZE(mvmvif->link); i++) { - if (!mvmvif->link[i]) - continue; - /* shouldn't do this when >1 link is active */ - WARN_ON_ONCE(link_id != IEEE80211_LINK_UNSPECIFIED); - link_id = i; - } - } - if (link_id < IEEE80211_LINK_UNSPECIFIED) { struct ieee80211_bss_conf *link_conf; @@ -1761,6 +1750,20 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, mvmvif = iwl_mvm_vif_from_mac80211(vif); + /* + * len_low should be 2 + n*13 (where n is the number of descriptors. + * 13 is the size of a NoA descriptor). We can have either one or two + * descriptors. + */ + if (IWL_FW_CHECK(mvm, notif->noa_active && + notif->noa_attr.len_low != 2 + + sizeof(struct ieee80211_p2p_noa_desc) && + notif->noa_attr.len_low != 2 + + sizeof(struct ieee80211_p2p_noa_desc) * 2, + "Invalid noa_attr.len_low (%d)\n", + notif->noa_attr.len_low)) + return; + new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); if (!new_data) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 44029ceb8f77..169c87588938 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1109,7 +1109,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->ba_enabled = false; mvmvif->ap_sta = NULL; - mvmvif->esr_active = false; vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE; for_each_mvm_vif_valid_link(mvmvif, link_id) { @@ -1129,39 +1128,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL); } -static void iwl_mvm_cleanup_sta_iterator(void *data, struct ieee80211_sta *sta) -{ - struct iwl_mvm *mvm = data; - struct iwl_mvm_sta *mvm_sta; - struct ieee80211_vif *vif; - int link_id; - - mvm_sta = iwl_mvm_sta_from_mac80211(sta); - vif = mvm_sta->vif; - - if (!sta->valid_links) - return; - - for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) { - struct iwl_mvm_link_sta *mvm_link_sta; - - mvm_link_sta = - rcu_dereference_check(mvm_sta->link[link_id], - lockdep_is_held(&mvm->mutex)); - if (mvm_link_sta && !(vif->active_links & BIT(link_id))) { - /* - * We have a link STA but the link is inactive in - * mac80211. This will happen if we failed to - * deactivate the link but mac80211 roll back the - * deactivation of the link. - * Delete the stale data to avoid issues later on. - */ - iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta, - link_id); - } - } -} - static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { iwl_mvm_stop_device(mvm); @@ -1184,10 +1150,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) */ ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm); - /* cleanup stations as links may be gone after restart */ - ieee80211_iterate_stations_atomic(mvm->hw, - iwl_mvm_cleanup_sta_iterator, mvm); - mvm->p2p_device_vif = NULL; iwl_mvm_reset_phy_ctxts(mvm); @@ -2639,7 +2601,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, } void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 duration_override, unsigned int link_id) + u32 duration_override) { u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS; u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS; @@ -2659,8 +2621,7 @@ void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) iwl_mvm_schedule_session_protection(mvm, vif, 900, - min_duration, false, - link_id); + min_duration, false); else iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); @@ -2860,7 +2821,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * time could be small without us having heard * a beacon yet. */ - iwl_mvm_protect_assoc(mvm, vif, 0, 0); + iwl_mvm_protect_assoc(mvm, vif, 0); } iwl_mvm_sf_update(mvm, vif, false); @@ -3921,12 +3882,6 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, mvmvif->authorized = 1; - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - mvmvif->link_selection_res = vif->active_links; - mvmvif->link_selection_primary = - vif->active_links ? __ffs(vif->active_links) : 0; - } - callbacks->mac_ctxt_changed(mvm, vif, false); iwl_mvm_mei_host_associated(mvm, vif, mvm_sta); } @@ -3972,7 +3927,6 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, * time. */ mvmvif->authorized = 0; - mvmvif->link_selection_res = 0; /* disable beacon filtering */ iwl_mvm_disable_beacon_filter(mvm, vif); @@ -4197,7 +4151,7 @@ void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, return; guard(mvm)(mvm); - iwl_mvm_protect_assoc(mvm, vif, info->duration, info->link_id); + iwl_mvm_protect_assoc(mvm, vif, info->duration); } void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw, @@ -5568,8 +5522,7 @@ static int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, if (!vif->cfg.assoc || !vif->bss_conf.dtim_period) return -EBUSY; - if (chsw->delay > IWL_MAX_CSA_BLOCK_TX && - hweight16(vif->valid_links) <= 1) + if (chsw->delay > IWL_MAX_CSA_BLOCK_TX) schedule_delayed_work(&mvmvif->csa_work, 0); if (chsw->block_tx) { @@ -5733,15 +5686,8 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return; } - if (!drop && hweight16(vif->active_links) <= 1) { - int link_id = vif->active_links ? __ffs(vif->active_links) : 0; - struct ieee80211_bss_conf *link_conf; - - link_conf = wiphy_dereference(hw->wiphy, - vif->link_conf[link_id]); - if (WARN_ON(!link_conf)) - return; - if (link_conf->csa_active && mvmvif->csa_blocks_tx) + if (!drop) { + if (vif->bss_conf.csa_active && mvmvif->csa_blocks_tx) drop = true; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index ef0be44207e1..9bb253dcf4a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 - 2024 Intel Corporation + * Copyright (C) 2022 - 2025 Intel Corporation */ #include <linux/kernel.h> #include <net/mac80211.h> @@ -43,11 +43,11 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm, * group keys have no sta pointer), so we don't have a STA now. * Since this happens for group keys only, just use the link_info as * the group keys are per link; make sure that is the case by checking - * we do have a link_id or are not doing MLO. + * we do have a link_id. * Of course the same can be done during add as well, but we must do * it during remove, since we don't have the mvmvif->ap_sta pointer. */ - if (!sta && (keyconf->link_id >= 0 || !ieee80211_vif_is_mld(vif))) + if (!sta && keyconf->link_id >= 0) return BIT(link_info->ap_sta_id); /* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 2d116a41913c..bf54b90a7c51 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -56,23 +56,6 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, if (iwlwifi_mod_params.disable_11ax) return; - /* If we have MLO enabled, then the firmware needs to enable - * address translation for the station(s) we add. That depends - * on having EHT enabled in firmware, which in turn depends on - * mac80211 in the code below. - * However, mac80211 doesn't enable HE/EHT until it has parsed - * the association response successfully, so just skip all that - * and enable both when we have MLO. - */ - if (ieee80211_vif_is_mld(vif)) { - iwl_mvm_mld_set_he_support(mvm, vif, cmd, cmd_ver); - if (cmd_ver == 2) - cmd->wifi_gen_v2.eht_support = cpu_to_le32(1); - else - cmd->wifi_gen.eht_support = 1; - return; - } - rcu_read_lock(); for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) { link_conf = rcu_dereference(vif->link_conf[link_id]); @@ -116,7 +99,6 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, u32 action, bool force_assoc_off) { struct iwl_mac_config_cmd cmd = {}; - u16 esr_transition_timeout; WARN_ON(vif->type != NL80211_IFTYPE_STATION); @@ -154,17 +136,6 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, } cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid); - if (ieee80211_vif_is_mld(vif)) { - esr_transition_timeout = - u16_get_bits(vif->cfg.eml_cap, - IEEE80211_EML_CAP_TRANSITION_TIMEOUT); - - cmd.client.esr_transition_timeout = - min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU, - esr_transition_timeout); - cmd.client.medium_sync_delay = - cpu_to_le16(vif->cfg.eml_med_sync_delay); - } if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p) cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 380b6f8a53fd..075ff09e93cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -60,19 +60,12 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw, IEEE80211_VIF_SUPPORTS_CQM_RSSI; } - /* We want link[0] to point to the default link, unless we have MLO and - * in this case this will be modified later by .change_vif_links() - * If we are in the restart flow with an MLD connection, we will wait - * to .change_vif_links() to setup the links. - */ - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || - !ieee80211_vif_is_mld(vif)) { - mvmvif->link[0] = &mvmvif->deflink; + /* We want link[0] to point to the default link. */ + mvmvif->link[0] = &mvmvif->deflink; - ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); - if (ret) - goto out_free_bf; - } + ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); + if (ret) + goto out_free_bf; /* Save a pointer to p2p device vif, so it can later be used to * update the p2p device MAC when a GO is started/stopped @@ -181,58 +174,6 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw, } } -static unsigned int iwl_mvm_mld_count_active_links(struct iwl_mvm_vif *mvmvif) -{ - unsigned int n_active = 0; - int i; - - for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { - if (mvmvif->link[i] && mvmvif->link[i]->phy_ctxt) - n_active++; - } - - return n_active; -} - -static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int link_id, ret = 0; - - mvmvif->esr_active = true; - - /* Indicate to mac80211 that EML is enabled */ - vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE; - - iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW, - IEEE80211_SMPS_OFF); - - for_each_mvm_vif_valid_link(mvmvif, link_id) { - struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id]; - - if (!link->phy_ctxt) - continue; - - ret = iwl_mvm_phy_send_rlc(mvm, link->phy_ctxt, 2, 2); - if (ret) - break; - - link->phy_ctxt->rlc_disabled = true; - } - - if (vif->active_links == mvmvif->link_selection_res && - !WARN_ON(!(vif->active_links & BIT(mvmvif->link_selection_primary)))) - mvmvif->primary_link = mvmvif->link_selection_primary; - else - mvmvif->primary_link = __ffs(vif->active_links); - - iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP, - NULL); - - return ret; -} - static int __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -243,17 +184,12 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif); unsigned int link_id = link_conf->link_id; int ret; if (WARN_ON_ONCE(!mvmvif->link[link_id])) return -EINVAL; - /* if the assigned one was not counted yet, count it now */ - if (!mvmvif->link[link_id]->phy_ctxt) - n_active++; - /* mac parameters such as HE support can change at this stage * For sta, need first to configure correct state from drv_sta_state * and only after that update mac config. @@ -268,15 +204,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, mvmvif->link[link_id]->phy_ctxt = phy_ctxt; - if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) { - mvmvif->link[link_id]->listen_lmac = true; - ret = iwl_mvm_esr_mode_active(mvm, vif); - if (ret) { - IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret); - goto out; - } - } - if (switching_chanctx) { /* reactivate if we turned this off during channel switch */ if (vif->type == NL80211_IFTYPE_AP) @@ -341,55 +268,6 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw, return __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false); } -static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct ieee80211_bss_conf *link_conf; - int link_id, ret = 0; - - mvmvif->esr_active = false; - - vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE; - - iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW, - IEEE80211_SMPS_AUTOMATIC); - - for_each_vif_active_link(vif, link_conf, link_id) { - struct ieee80211_chanctx_conf *chanctx_conf; - struct iwl_mvm_phy_ctxt *phy_ctxt; - u8 static_chains, dynamic_chains; - - mvmvif->link[link_id]->listen_lmac = false; - - rcu_read_lock(); - - chanctx_conf = rcu_dereference(link_conf->chanctx_conf); - phy_ctxt = mvmvif->link[link_id]->phy_ctxt; - - if (!chanctx_conf || !phy_ctxt) { - rcu_read_unlock(); - continue; - } - - phy_ctxt->rlc_disabled = false; - static_chains = chanctx_conf->rx_chains_static; - dynamic_chains = chanctx_conf->rx_chains_dynamic; - - rcu_read_unlock(); - - ret = iwl_mvm_phy_send_rlc(mvm, phy_ctxt, static_chains, - dynamic_chains); - if (ret) - break; - } - - iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_DOWN, - NULL); - - return ret; -} - static void __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -399,7 +277,6 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif); unsigned int link_id = link_conf->link_id; /* shouldn't happen, but verify link_id is valid before accessing */ @@ -421,14 +298,6 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, iwl_mvm_link_changed(mvm, vif, link_conf, LINK_CONTEXT_MODIFY_ACTIVE, false); - if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) { - int ret = iwl_mvm_esr_mode_inactive(mvm, vif); - - if (ret) - IWL_ERR(mvm, "failed to deactivate ESR mode (%d)\n", - ret); - } - if (vif->type == NL80211_IFTYPE_MONITOR) iwl_mvm_mld_rm_snif_sta(mvm, vif); @@ -448,9 +317,8 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); __iwl_mvm_mld_unassign_vif_chanctx(mvm, vif, link_conf, ctx, false); - /* in the non-MLD case, remove/re-add the link to clean up FW state */ - if (!ieee80211_vif_is_mld(vif) && !mvmvif->ap_sta && - !WARN_ON_ONCE(vif->cfg.assoc)) { + /* Remove/re-add the link to clean up FW state */ + if (!mvmvif->ap_sta && !WARN_ON_ONCE(vif->cfg.assoc)) { iwl_mvm_remove_link(mvm, vif, link_conf); iwl_mvm_add_link(mvm, vif, link_conf); } @@ -785,12 +653,6 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && protect) { - /* We are in assoc so only one link is active- - * The association link - */ - unsigned int link_id = - ffs(vif->active_links) - 1; - /* If we're not restarting and still haven't * heard a beacon (dtim period unknown) then * make sure we still have enough minimum time @@ -800,7 +662,7 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, * time could be small without us having heard * a beacon yet. */ - iwl_mvm_protect_assoc(mvm, vif, 0, link_id); + iwl_mvm_protect_assoc(mvm, vif, 0); } iwl_mvm_sf_update(mvm, vif, false); @@ -1096,14 +958,6 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, if (new_links == 0) { mvmvif->link[0] = &mvmvif->deflink; err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); - if (err == 0) - mvmvif->primary_link = 0; - } else if (!(new_links & BIT(mvmvif->primary_link))) { - /* - * Ensure we always have a valid primary_link, the real - * decision happens later when PHY is activated. - */ - mvmvif->primary_link = __ffs(new_links); } out_err: @@ -1128,44 +982,17 @@ iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw, return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links); } -bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - const struct wiphy_iftype_ext_capab *ext_capa; - - lockdep_assert_held(&mvm->mutex); - - if (!ieee80211_vif_is_mld(vif) || !vif->cfg.assoc || - hweight16(ieee80211_vif_usable_links(vif)) == 1) - return false; - - if (!(vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)) - return false; - - ext_capa = cfg80211_get_iftype_ext_capa(mvm->hw->wiphy, - ieee80211_vif_type_p2p(vif)); - return (ext_capa && - (ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP)); -} - static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 desired_links) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int n_links = hweight16(desired_links); if (n_links <= 1) return true; - guard(mvm)(mvm); - - /* Check if HW supports the wanted number of links */ - if (n_links > iwl_mvm_max_active_links(mvm, vif)) - return false; - - /* If it is an eSR device, check that we can enter eSR */ - return iwl_mvm_is_esr_supported(mvm->fwrt.trans) && - iwl_mvm_vif_has_esr_cap(mvm, vif); + WARN_ON(1); + return false; } static enum ieee80211_neg_ttlm_res diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index d9a2801636cf..1100d763ceb6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -9,40 +9,14 @@ u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int filter_link_id) { - struct ieee80211_link_sta *link_sta; struct iwl_mvm_sta *mvmsta; - struct ieee80211_vif *vif; - unsigned int link_id; - u32 result = 0; if (!sta) return 0; mvmsta = iwl_mvm_sta_from_mac80211(sta); - vif = mvmsta->vif; - - /* it's easy when the STA is not an MLD */ - if (!sta->valid_links) - return BIT(mvmsta->deflink.sta_id); - - /* but if it is an MLD, get the mask of all the FW STAs it has ... */ - for_each_sta_active_link(vif, sta, link_sta, link_id) { - struct iwl_mvm_link_sta *mvm_link_sta; - - /* unless we have a specific link in mind */ - if (filter_link_id >= 0 && link_id != filter_link_id) - continue; - - mvm_link_sta = - rcu_dereference_check(mvmsta->link[link_id], - lockdep_is_held(&mvm->mutex)); - if (!mvm_link_sta) - continue; - - result |= BIT(mvm_link_sta->sta_id); - } - return result; + return BIT(mvmsta->deflink.sta_id); } static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 301d590fe0bd..db5f9804b529 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -120,7 +120,6 @@ struct iwl_mvm_time_event_data { * if the te is in the time event list or not (when id == TE_MAX) */ u32 id; - s8 link_id; }; /* Power management */ @@ -380,14 +379,7 @@ struct iwl_mvm_vif_link_info { * @bcn_prot: beacon protection data (keys; FIXME: needs to be per link) * @deflink: default link data for use in non-MLO * @link: link data for each link in MLO - * @esr_active: indicates eSR mode is active * @pm_enabled: indicates powersave is enabled - * @link_selection_res: bitmap of active links as it was decided in the last - * link selection. Valid only for a MLO vif after assoc. 0 if there wasn't - * any link selection yet. - * @link_selection_primary: primary link selected by link selection - * @primary_link: primary link in eSR. Valid only for an associated MLD vif, - * and in eSR mode. Valid only for a STA. * @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 @@ -434,7 +426,6 @@ struct iwl_mvm_vif { bool ap_ibss_active; bool pm_enabled; bool monitor_active; - bool esr_active; bool session_prot_connection_loss; u8 low_latency: 6; @@ -515,10 +506,6 @@ struct iwl_mvm_vif { u16 max_tx_op; - u16 link_selection_res; - u8 link_selection_primary; - u8 primary_link; - struct iwl_mvm_vif_link_info deflink; struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; }; @@ -1619,40 +1606,6 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CTDP_SUPPORT); } -static inline bool iwl_mvm_is_esr_supported(struct iwl_trans *trans) -{ - if (CSR_HW_RFID_IS_CDB(trans->info.hw_rf_id)) - return false; - - switch (CSR_HW_RFID_TYPE(trans->info.hw_rf_id)) { - case IWL_CFG_RF_TYPE_FM: - /* Step A doesn't support eSR */ - return CSR_HW_RFID_STEP(trans->info.hw_rf_id); - case IWL_CFG_RF_TYPE_WH: - case IWL_CFG_RF_TYPE_PE: - return true; - default: - return false; - } -} - -static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_trans *trans = mvm->fwrt.trans; - - if (vif->type == NL80211_IFTYPE_AP) - return mvm->fw->ucode_capa.num_beacons; - - /* Check if HW supports eSR or STR */ - if (iwl_mvm_is_esr_supported(trans) || - (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_FM && - CSR_HW_RFID_IS_CDB(trans->info.hw_rf_id))) - return IWL_FW_MAX_ACTIVE_LINKS_NUM; - - return 1; -} - extern const u8 iwl_mvm_ac_to_tx_fifo[]; extern const u8 iwl_mvm_ac_to_gen2_tx_fifo[]; extern const u8 iwl_mvm_ac_to_bz_tx_fifo[]; @@ -2008,15 +1961,6 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); -u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif); - -struct iwl_mvm_link_sel_data { - u8 link_id; - const struct cfg80211_chan_def *chandef; - s32 signal; - u16 grade; -}; - #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) extern const struct iwl_hcmd_arr iwl_mvm_groups[]; extern const unsigned int iwl_mvm_groups_size; @@ -2064,7 +2008,7 @@ int iwl_mvm_cancel_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /*Session Protection */ void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 duration_override, unsigned int link_id); + u32 duration_override); /* Quota management */ static inline size_t iwl_mvm_quota_cmd_size(struct iwl_mvm *mvm) @@ -2884,8 +2828,6 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int duration, enum iwl_roc_activity activity); -/* EMLSR */ -bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index d35c63a673b6..7f0b4f5daa21 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -2254,17 +2254,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, IWL_RX_MPDU_STATUS_STA_ID); if (!WARN_ON_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations)) { - struct ieee80211_link_sta *link_sta; - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); if (IS_ERR(sta)) sta = NULL; - link_sta = rcu_dereference(mvm->fw_id_to_link_sta[sta_id]); - - if (sta && sta->valid_links && link_sta) { - rx_status->link_valid = 1; - rx_status->link_id = link_sta->link_id; - } } } else if (!is_multicast_ether_addr(hdr->addr2)) { /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index b588f1dcf20d..9c51953d255d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -2568,16 +2568,16 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, bitmap_ssid, version); return 0; - } else { - pb->preq = params->preq; } - cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); - cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; - cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS; + pb->preq = params->preq; iwl_mvm_umac_scan_fill_6g_chan_list(mvm, params, pb); + /* Explicitly clear the flags since most of them are not + * relevant for 6 GHz scan. + */ + cp->flags = 0; cp->count = iwl_mvm_umac_scan_cfg_channels_v7_6g(mvm, params, params->n_channels, pb, cp, vif->type, @@ -3023,12 +3023,8 @@ static int _iwl_mvm_single_scan_start(struct iwl_mvm *mvm, params.iter_notif = true; params.tsf_report_link_id = req->tsf_report_link_id; - if (params.tsf_report_link_id < 0) { - if (vif->active_links) - params.tsf_report_link_id = __ffs(vif->active_links); - else - params.tsf_report_link_id = 0; - } + if (params.tsf_report_link_id < 0) + params.tsf_report_link_id = 0; iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index 36379b738de1..4945ebf19f6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020, 2022-2024 Intel Corporation + * Copyright (C) 2018-2020, 2022-2025 Intel Corporation */ #include <linux/etherdevice.h> #include "mvm.h" @@ -155,7 +155,7 @@ void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) iwl_mvm_schedule_session_protection(mvm, vif, duration, - duration, true, link_id); + duration, true); else iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 0b12ee8ad618..2b52a4f3bff9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -42,7 +42,6 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, te_data->uid = 0; te_data->id = TE_MAX; te_data->vif = NULL; - te_data->link_id = -1; } static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) @@ -721,8 +720,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, /* Determine whether mac or link id should be used, and validate the link id */ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - s8 link_id) + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ver = iwl_fw_lookup_cmd_ver(mvm->fw, @@ -732,22 +730,18 @@ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, if (ver < 2) return mvmvif->id; - if (WARN(link_id < 0 || !mvmvif->link[link_id], - "Invalid link ID for session protection: %u\n", link_id)) - return -EINVAL; - - if (WARN(!mvmvif->link[link_id]->active, - "Session Protection on an inactive link: %u\n", link_id)) + if (WARN(!mvmvif->deflink.active, + "Session Protection on an inactive link\n")) return -EINVAL; - return mvmvif->link[link_id]->fw_link_id; + return mvmvif->deflink.fw_link_id; } static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 id, s8 link_id) + u32 id) { - int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, link_id); + int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif); struct iwl_session_prot_cmd cmd = { .id_and_color = cpu_to_le32(mac_link_id), .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), @@ -791,7 +785,6 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif = te_data->vif; struct iwl_mvm_vif *mvmvif; enum nl80211_iftype iftype; - s8 link_id; bool p2p_aux = iwl_mvm_has_p2p_over_aux(mvm); u8 roc_ver = iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); @@ -811,7 +804,6 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, /* Save time event uid before clearing its data */ *uid = te_data->uid; id = te_data->id; - link_id = te_data->link_id; /* * The clear_data function handles time events that were already removed @@ -837,8 +829,7 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, */ if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) { /* Session protection is still ongoing. Cancel it */ - iwl_mvm_cancel_session_protection(mvm, vif, id, - link_id); + iwl_mvm_cancel_session_protection(mvm, vif, id); if (iftype == NL80211_IFTYPE_P2P_DEVICE) { iwl_mvm_roc_finished(mvm); } @@ -1007,7 +998,6 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) { /* End TE, notify mac80211 */ mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID; - mvmvif->time_event_data.link_id = -1; /* set the bit so the ROC cleanup will actually clean up */ set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status); iwl_mvm_roc_finished(mvm); @@ -1132,7 +1122,7 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_session_prot_cmd cmd = { .id_and_color = - cpu_to_le32(iwl_mvm_get_session_prot_id(mvm, vif, 0)), + cpu_to_le32(iwl_mvm_get_session_prot_id(mvm, vif)), .action = cpu_to_le32(FW_CTXT_ACTION_ADD), .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), }; @@ -1143,8 +1133,6 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, * protection's configuration. */ - mvmvif->time_event_data.link_id = 0; - switch (type) { case IEEE80211_ROC_TYPE_NORMAL: mvmvif->time_event_data.id = @@ -1290,8 +1278,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return; } iwl_mvm_cancel_session_protection(mvm, vif, - te_data->id, - te_data->link_id); + te_data->id); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, &mvmvif->hs_time_event_data); @@ -1423,14 +1410,13 @@ static bool iwl_mvm_session_prot_notif(struct iwl_notif_wait_data *notif_wait, void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 duration, u32 min_duration, - bool wait_for_notif, - unsigned int link_id) + bool wait_for_notif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; const u16 notif[] = { WIDE_ID(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF) }; struct iwl_notification_wait wait_notif; - int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, (s8)link_id); + int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif); struct iwl_session_prot_cmd cmd = { .id_and_color = cpu_to_le32(mac_link_id), .action = cpu_to_le32(FW_CTXT_ACTION_ADD), @@ -1444,7 +1430,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); spin_lock_bh(&mvm->time_event_lock); - if (te_data->running && te_data->link_id == link_id && + if (te_data->running && time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) { IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", jiffies_to_msecs(te_data->end_jiffies - jiffies)); @@ -1461,7 +1447,6 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, te_data->id = le32_to_cpu(cmd.conf_id); te_data->duration = le32_to_cpu(cmd.duration_tu); te_data->vif = vif; - te_data->link_id = link_id; spin_unlock_bh(&mvm->time_event_lock); IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 1ef8768756db..3f8628cbd480 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -210,13 +210,11 @@ iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) * @duration: the requested duration of the protection * @min_duration: the minimum duration of the protection * @wait_for_notif: if true, will block until the start of the protection - * @link_id: The link to schedule a session protection for */ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 duration, u32 min_duration, - bool wait_for_notif, - unsigned int link_id); + bool wait_for_notif); /** * iwl_mvm_rx_session_protect_notif - handles %SESSION_PROTECTION_NOTIF diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index bb97837baeda..bca13417e82c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -817,28 +817,15 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) NL80211_IFTYPE_P2P_DEVICE || info.control.vif->type == NL80211_IFTYPE_AP || info.control.vif->type == NL80211_IFTYPE_ADHOC) { - u32 link_id = u32_get_bits(info.control.flags, - IEEE80211_TX_CTRL_MLO_LINK); - struct iwl_mvm_vif_link_info *link; - - if (link_id == IEEE80211_LINK_UNSPECIFIED) { - if (info.control.vif->active_links) - link_id = ffs(info.control.vif->active_links) - 1; - else - link_id = 0; - } - - link = mvmvif->link[link_id]; - if (WARN_ON(!link)) - return -1; if (!ieee80211_is_data(hdr->frame_control)) - sta_id = link->bcast_sta.sta_id; + sta_id = mvmvif->deflink.bcast_sta.sta_id; else - sta_id = link->mcast_sta.sta_id; + sta_id = mvmvif->deflink.mcast_sta.sta_id; - queue = iwl_mvm_get_ctrl_vif_queue(mvm, link, &info, - skb); + queue = iwl_mvm_get_ctrl_vif_queue(mvm, + &mvmvif->deflink, + &info, skb); } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) { queue = mvm->snif_queue; sta_id = mvm->snif_sta.sta_id; @@ -895,33 +882,9 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, */ val = mvmsta->max_amsdu_len; - if (hweight16(sta->valid_links) <= 1) { - if (sta->valid_links) { - struct ieee80211_bss_conf *link_conf; - unsigned int link = ffs(sta->valid_links) - 1; + band = mvmsta->vif->bss_conf.chanreq.oper.chan->band; - rcu_read_lock(); - link_conf = rcu_dereference(mvmsta->vif->link_conf[link]); - if (WARN_ON(!link_conf)) - band = NL80211_BAND_2GHZ; - else - band = link_conf->chanreq.oper.chan->band; - rcu_read_unlock(); - } else { - band = mvmsta->vif->bss_conf.chanreq.oper.chan->band; - } - - lmac = iwl_mvm_get_lmac_id(mvm, band); - } else if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) { - /* for real MLO restrict to both LMACs if they exist */ - lmac = IWL_LMAC_5G_INDEX; - val = min_t(unsigned int, val, - mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256); - lmac = IWL_LMAC_24G_INDEX; - } else { - lmac = IWL_LMAC_24G_INDEX; - } + lmac = iwl_mvm_get_lmac_id(mvm, band); return min_t(unsigned int, val, mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 1a6c1f8706e1..4a33a032c2a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -308,10 +308,6 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, smps_mode = IEEE80211_SMPS_DYNAMIC; } - /* SMPS is disabled in eSR */ - if (mvmvif->esr_active) - smps_mode = IEEE80211_SMPS_OFF; - ieee80211_request_smps(vif, link_id, smps_mode); } diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index 2ec3655f1a9c..57a62108cbc3 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -143,8 +143,10 @@ static int p54_beacon_update(struct p54_common *priv, if (!beacon) return -ENOMEM; ret = p54_beacon_format_ie_tim(beacon); - if (ret) + if (ret) { + dev_kfree_skb_any(beacon); return ret; + } /* * During operation, the firmware takes care of beaconing. diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index c06ad064f37c..f9a527f6a175 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -7826,6 +7826,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, goto err_set_intfdata; hw->vif_data_size = sizeof(struct rtl8xxxu_vif); + hw->sta_data_size = sizeof(struct rtl8xxxu_sta_info); hw->wiphy->max_scan_ssids = 1; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index 0bc4afa4fda3..fd967006b3e1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -206,7 +206,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, } /* - *If a country IE has been recieved check its rule for this + *If a country IE has been received check its rule for this *channel first before enabling active scan. The passive scan *would have been enforced by the initial processing of our *custom regulatory domain. diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index fa0ed39cb199..c4f9758b4e96 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -730,10 +730,10 @@ void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel) } EXPORT_SYMBOL(rtw_set_rx_freq_band); -void rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period) +void rtw_set_dtim_period(struct rtw_dev *rtwdev, u8 dtim_period) { rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_TIMIE); - rtw_write8(rtwdev, REG_DTIM_COUNTER_ROOT, dtim_period - 1); + rtw_write8(rtwdev, REG_DTIM_COUNTER_ROOT, dtim_period ? dtim_period - 1 : 0); } void rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel, @@ -1483,6 +1483,8 @@ void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); set_bit(RTW_FLAG_SCANNING, rtwdev->flags); + + rtw_phy_dig_set_max_coverage(rtwdev); } void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, @@ -1494,6 +1496,7 @@ void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, if (!rtwvif) return; + rtw_phy_dig_reset(rtwdev); clear_bit(RTW_FLAG_SCANNING, rtwdev->flags); clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); @@ -1658,14 +1661,41 @@ static u16 rtw_get_max_scan_ie_len(struct rtw_dev *rtwdev) return len; } +static struct ieee80211_supported_band * +rtw_sband_dup(struct rtw_dev *rtwdev, + const struct ieee80211_supported_band *sband) +{ + struct ieee80211_supported_band *dup; + + dup = devm_kmemdup(rtwdev->dev, sband, sizeof(*sband), GFP_KERNEL); + if (!dup) + return NULL; + + dup->channels = devm_kmemdup_array(rtwdev->dev, sband->channels, + sband->n_channels, + sizeof(*sband->channels), + GFP_KERNEL); + if (!dup->channels) + return NULL; + + dup->bitrates = devm_kmemdup_array(rtwdev->dev, sband->bitrates, + sband->n_bitrates, + sizeof(*sband->bitrates), + GFP_KERNEL); + if (!dup->bitrates) + return NULL; + + return dup; +} + static void rtw_set_supported_band(struct ieee80211_hw *hw, const struct rtw_chip_info *chip) { - struct rtw_dev *rtwdev = hw->priv; struct ieee80211_supported_band *sband; + struct rtw_dev *rtwdev = hw->priv; if (chip->band & RTW_BAND_2G) { - sband = kmemdup(&rtw_band_2ghz, sizeof(*sband), GFP_KERNEL); + sband = rtw_sband_dup(rtwdev, &rtw_band_2ghz); if (!sband) goto err_out; if (chip->ht_supported) @@ -1674,7 +1704,7 @@ static void rtw_set_supported_band(struct ieee80211_hw *hw, } if (chip->band & RTW_BAND_5G) { - sband = kmemdup(&rtw_band_5ghz, sizeof(*sband), GFP_KERNEL); + sband = rtw_sband_dup(rtwdev, &rtw_band_5ghz); if (!sband) goto err_out; if (chip->ht_supported) @@ -1690,13 +1720,6 @@ err_out: rtw_err(rtwdev, "failed to set supported band\n"); } -static void rtw_unset_supported_band(struct ieee80211_hw *hw, - const struct rtw_chip_info *chip) -{ - kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]); - kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]); -} - static void rtw_vif_smps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -2320,10 +2343,7 @@ EXPORT_SYMBOL(rtw_register_hw); void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) { - const struct rtw_chip_info *chip = rtwdev->chip; - ieee80211_unregister_hw(hw); - rtw_unset_supported_band(hw, chip); rtw_debugfs_deinit(rtwdev); rtw_led_deinit(rtwdev); } @@ -2444,10 +2464,10 @@ void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable) if (enable) { rtw_write32_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); - rtw_write32_clr(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); + rtw_write8_clr(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); } else { rtw_write32_clr(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); - rtw_write32_set(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); + rtw_write8_set(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); } } diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 43ed6d6b4291..1ab70214ce36 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -2226,7 +2226,7 @@ enum nl80211_band rtw_hw_to_nl80211_band(enum rtw_supported_band hw_band) } void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel); -void rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period); +void rtw_set_dtim_period(struct rtw_dev *rtwdev, u8 dtim_period); void rtw_get_channel_params(struct cfg80211_chan_def *chandef, struct rtw_channel_params *ch_param); bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target); diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 55be0d8e0c28..e2ac5c6fd500 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -370,6 +370,26 @@ static void rtw_phy_statistics(struct rtw_dev *rtwdev) #define DIG_CVRG_MIN 0x1c #define DIG_RSSI_GAIN_OFFSET 15 +void rtw_phy_dig_set_max_coverage(struct rtw_dev *rtwdev) +{ + /* Lower values result in greater coverage. */ + rtw_dbg(rtwdev, RTW_DBG_PHY, "Setting IGI=%#x for max coverage\n", + DIG_CVRG_MIN); + + rtw_phy_dig_write(rtwdev, DIG_CVRG_MIN); +} + +void rtw_phy_dig_reset(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 last_igi; + + last_igi = dm_info->igi_history[0]; + rtw_dbg(rtwdev, RTW_DBG_PHY, "Resetting IGI=%#x\n", last_igi); + + rtw_phy_dig_write(rtwdev, last_igi); +} + static bool rtw_phy_dig_check_damping(struct rtw_dm_info *dm_info) { diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index c9e6b869661d..8449936497bb 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -146,6 +146,8 @@ static inline int rtw_check_supported_rfe(struct rtw_dev *rtwdev) } void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi); +void rtw_phy_dig_reset(struct rtw_dev *rtwdev); +void rtw_phy_dig_set_max_coverage(struct rtw_dev *rtwdev); struct rtw_power_params { u8 pwr_base; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723cs.c b/drivers/net/wireless/realtek/rtw88/rtw8723cs.c index 1f98d35a8dd1..2018c9d76dd1 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723cs.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723cs.c @@ -23,9 +23,9 @@ static struct sdio_driver rtw_8723cs_driver = { .id_table = rtw_8723cs_id_table, .probe = rtw_sdio_probe, .remove = rtw_sdio_remove, + .shutdown = rtw_sdio_shutdown, .drv = { .pm = &rtw_sdio_pm_ops, - .shutdown = rtw_sdio_shutdown }}; module_sdio_driver(rtw_8723cs_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723ds.c b/drivers/net/wireless/realtek/rtw88/rtw8723ds.c index 206b77e5b98e..e38c90b769a2 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723ds.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723ds.c @@ -28,10 +28,10 @@ static struct sdio_driver rtw_8723ds_driver = { .name = KBUILD_MODNAME, .probe = rtw_sdio_probe, .remove = rtw_sdio_remove, + .shutdown = rtw_sdio_shutdown, .id_table = rtw_8723ds_id_table, .drv = { .pm = &rtw_sdio_pm_ops, - .shutdown = rtw_sdio_shutdown, } }; module_sdio_driver(rtw_8723ds_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821cs.c b/drivers/net/wireless/realtek/rtw88/rtw8821cs.c index 6d94162213c6..58e0ef219cdc 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821cs.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821cs.c @@ -23,10 +23,10 @@ static struct sdio_driver rtw_8821cs_driver = { .name = KBUILD_MODNAME, .probe = rtw_sdio_probe, .remove = rtw_sdio_remove, + .shutdown = rtw_sdio_shutdown, .id_table = rtw_8821cs_id_table, .drv = { .pm = &rtw_sdio_pm_ops, - .shutdown = rtw_sdio_shutdown, } }; module_sdio_driver(rtw_8821cs_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c index 7a0fffc359e2..8cd09d66655d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821cu.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821cu.c @@ -37,6 +37,8 @@ static const struct usb_device_id rtw_8821cu_id_table[] = { .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd811, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Edimax */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0105, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* Mercusys */ {}, }; MODULE_DEVICE_TABLE(usb, rtw_8821cu_id_table); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 89b6485b229a..4d88cc2f4148 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -1005,7 +1005,8 @@ static int rtw8822b_set_antenna(struct rtw_dev *rtwdev, hal->antenna_tx = antenna_tx; hal->antenna_rx = antenna_rx; - rtw8822b_config_trx_mode(rtwdev, antenna_tx, antenna_rx, false); + if (test_bit(RTW_FLAG_POWERON, rtwdev->flags)) + rtw8822b_config_trx_mode(rtwdev, antenna_tx, antenna_rx, false); return 0; } diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822bs.c b/drivers/net/wireless/realtek/rtw88/rtw8822bs.c index 744781dcb419..2de9b11540c5 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822bs.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822bs.c @@ -23,10 +23,10 @@ static struct sdio_driver rtw_8822bs_driver = { .name = KBUILD_MODNAME, .probe = rtw_sdio_probe, .remove = rtw_sdio_remove, + .shutdown = rtw_sdio_shutdown, .id_table = rtw_8822bs_id_table, .drv = { .pm = &rtw_sdio_pm_ops, - .shutdown = rtw_sdio_shutdown, } }; module_sdio_driver(rtw_8822bs_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822cs.c b/drivers/net/wireless/realtek/rtw88/rtw8822cs.c index 322281e07eb8..b00ef4173962 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822cs.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822cs.c @@ -23,10 +23,10 @@ static struct sdio_driver rtw_8822cs_driver = { .name = KBUILD_MODNAME, .probe = rtw_sdio_probe, .remove = rtw_sdio_remove, + .shutdown = rtw_sdio_shutdown, .id_table = rtw_8822cs_id_table, .drv = { .pm = &rtw_sdio_pm_ops, - .shutdown = rtw_sdio_shutdown, } }; module_sdio_driver(rtw_8822cs_driver); diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index e35de52d8eb4..138e9e348c6c 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -1414,9 +1414,8 @@ void rtw_sdio_remove(struct sdio_func *sdio_func) } EXPORT_SYMBOL(rtw_sdio_remove); -void rtw_sdio_shutdown(struct device *dev) +void rtw_sdio_shutdown(struct sdio_func *sdio_func) { - struct sdio_func *sdio_func = dev_to_sdio_func(dev); const struct rtw_chip_info *chip; struct ieee80211_hw *hw; struct rtw_dev *rtwdev; diff --git a/drivers/net/wireless/realtek/rtw88/sdio.h b/drivers/net/wireless/realtek/rtw88/sdio.h index 3c659ed180f0..457e8b02380e 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.h +++ b/drivers/net/wireless/realtek/rtw88/sdio.h @@ -166,7 +166,7 @@ extern const struct dev_pm_ops rtw_sdio_pm_ops; int rtw_sdio_probe(struct sdio_func *sdio_func, const struct sdio_device_id *id); void rtw_sdio_remove(struct sdio_func *sdio_func); -void rtw_sdio_shutdown(struct device *dev); +void rtw_sdio_shutdown(struct sdio_func *sdio_func); static inline bool rtw_sdio_is_sdio30_supported(struct rtw_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index 9370cbda945c..9f63d67777fa 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -1140,3 +1140,137 @@ void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, le32_encode_bits(mld_bssid[5], DCTLINFO_V2_W12_MLD_BSSID_5); h2c->m12 = cpu_to_le32(DCTLINFO_V2_W12_ALL); } + +void rtw89_cam_fill_dctl_sec_cam_info_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct rtw89_h2c_dctlinfo_ud_v3 *h2c) +{ + 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_link ? rtwsta_link->mac_id : + rtwvif_link->mac_id, + DCTLINFO_V3_C0_MACID) | + le32_encode_bits(1, DCTLINFO_V3_C0_OP); + + h2c->w2 = le32_encode_bits(is_mld, DCTLINFO_V3_W2_IS_MLD); + h2c->m2 = cpu_to_le32(DCTLINFO_V3_W2_IS_MLD); + + h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0], + DCTLINFO_V3_W4_SEC_ENT0_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[1], + DCTLINFO_V3_W4_SEC_ENT1_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[2], + DCTLINFO_V3_W4_SEC_ENT2_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[3], + DCTLINFO_V3_W4_SEC_ENT3_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[4], + DCTLINFO_V3_W4_SEC_ENT4_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[5], + DCTLINFO_V3_W4_SEC_ENT5_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[6], + DCTLINFO_V3_W4_SEC_ENT6_KEYID); + h2c->m4 = cpu_to_le32(DCTLINFO_V3_W4_SEC_ENT0_KEYID | + DCTLINFO_V3_W4_SEC_ENT1_KEYID | + DCTLINFO_V3_W4_SEC_ENT2_KEYID | + DCTLINFO_V3_W4_SEC_ENT3_KEYID | + DCTLINFO_V3_W4_SEC_ENT4_KEYID | + DCTLINFO_V3_W4_SEC_ENT5_KEYID | + DCTLINFO_V3_W4_SEC_ENT6_KEYID); + + h2c->w5 = le32_encode_bits(addr_cam->sec_cam_map[0], + DCTLINFO_V3_W5_SEC_ENT_VALID_V1); + h2c->m5 = cpu_to_le32(DCTLINFO_V3_W5_SEC_ENT_VALID_V1); + + h2c->w6 = le32_encode_bits(addr_cam->sec_ent[0], + DCTLINFO_V3_W6_SEC_ENT0_V2) | + le32_encode_bits(addr_cam->sec_ent[1], + DCTLINFO_V3_W6_SEC_ENT1_V2) | + le32_encode_bits(addr_cam->sec_ent[2], + DCTLINFO_V3_W6_SEC_ENT2_V2); + h2c->m6 = cpu_to_le32(DCTLINFO_V3_W6_SEC_ENT0_V2 | + DCTLINFO_V3_W6_SEC_ENT1_V2 | + DCTLINFO_V3_W6_SEC_ENT2_V2); + + h2c->w7 = le32_encode_bits(addr_cam->sec_ent[3], + DCTLINFO_V3_W7_SEC_ENT3_V2) | + le32_encode_bits(addr_cam->sec_ent[4], + DCTLINFO_V3_W7_SEC_ENT4_V2) | + le32_encode_bits(addr_cam->sec_ent[5], + DCTLINFO_V3_W7_SEC_ENT5_V2); + h2c->m7 = cpu_to_le32(DCTLINFO_V3_W7_SEC_ENT3_V2 | + DCTLINFO_V3_W7_SEC_ENT4_V2 | + DCTLINFO_V3_W7_SEC_ENT5_V2); + + h2c->w8 = le32_encode_bits(addr_cam->sec_ent[6], + DCTLINFO_V3_W8_SEC_ENT6_V2); + h2c->m8 = cpu_to_le32(DCTLINFO_V3_W8_SEC_ENT6_V2); + + if (rtw_wow->ptk_alg) { + h2c->w0 = le32_encode_bits(ptk_tx_iv[0] | ptk_tx_iv[1] << 8, + DCTLINFO_V3_W0_AES_IV_L); + h2c->m0 = cpu_to_le32(DCTLINFO_V3_W0_AES_IV_L); + + h2c->w1 = le32_encode_bits(ptk_tx_iv[4] | + ptk_tx_iv[5] << 8 | + ptk_tx_iv[6] << 16 | + ptk_tx_iv[7] << 24, + DCTLINFO_V3_W1_AES_IV_H); + h2c->m1 = cpu_to_le32(DCTLINFO_V3_W1_AES_IV_H); + + h2c->w4 |= le32_encode_bits(rtw_wow->ptk_keyidx, + DCTLINFO_V3_W4_SEC_KEY_ID); + h2c->m4 |= cpu_to_le32(DCTLINFO_V3_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->w9 = le32_encode_bits(mld_sma[0], DCTLINFO_V3_W9_MLD_SMA_0_V2) | + le32_encode_bits(mld_sma[1], DCTLINFO_V3_W9_MLD_SMA_1_V2) | + le32_encode_bits(mld_sma[2], DCTLINFO_V3_W9_MLD_SMA_2_V2) | + le32_encode_bits(mld_sma[3], DCTLINFO_V3_W9_MLD_SMA_3_V2); + h2c->m9 = cpu_to_le32(DCTLINFO_V3_W9_ALL); + + h2c->w10 = le32_encode_bits(mld_sma[4], DCTLINFO_V3_W10_MLD_SMA_4_V2) | + le32_encode_bits(mld_sma[5], DCTLINFO_V3_W10_MLD_SMA_5_V2) | + le32_encode_bits(mld_tma[0], DCTLINFO_V3_W10_MLD_TMA_0_V2) | + le32_encode_bits(mld_tma[1], DCTLINFO_V3_W10_MLD_TMA_1_V2); + h2c->m10 = cpu_to_le32(DCTLINFO_V3_W10_ALL); + + h2c->w11 = le32_encode_bits(mld_tma[2], DCTLINFO_V3_W11_MLD_TMA_2_V2) | + le32_encode_bits(mld_tma[3], DCTLINFO_V3_W11_MLD_TMA_3_V2) | + le32_encode_bits(mld_tma[4], DCTLINFO_V3_W11_MLD_TMA_4_V2) | + le32_encode_bits(mld_tma[5], DCTLINFO_V3_W11_MLD_TMA_5_V2); + h2c->m11 = cpu_to_le32(DCTLINFO_V3_W11_ALL); + + h2c->w12 = le32_encode_bits(mld_bssid[0], DCTLINFO_V3_W12_MLD_TA_BSSID_0_V2) | + le32_encode_bits(mld_bssid[1], DCTLINFO_V3_W12_MLD_TA_BSSID_1_V2) | + le32_encode_bits(mld_bssid[2], DCTLINFO_V3_W12_MLD_TA_BSSID_2_V2) | + le32_encode_bits(mld_bssid[3], DCTLINFO_V3_W12_MLD_TA_BSSID_3_V2); + h2c->m12 = cpu_to_le32(DCTLINFO_V3_W12_ALL); + + h2c->w13 = le32_encode_bits(mld_bssid[4], DCTLINFO_V3_W13_MLD_TA_BSSID_4_V2) | + le32_encode_bits(mld_bssid[5], DCTLINFO_V3_W13_MLD_TA_BSSID_5_V2); + h2c->m13 = cpu_to_le32(DCTLINFO_V3_W13_ALL); +} diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h index c46b6f91bbdb..22868f262243 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.h +++ b/drivers/net/wireless/realtek/rtw89/cam.h @@ -302,6 +302,131 @@ struct rtw89_h2c_dctlinfo_ud_v2 { #define DCTLINFO_V2_W12_MLD_BSSID_5 GENMASK(15, 8) #define DCTLINFO_V2_W12_ALL GENMASK(15, 0) +struct rtw89_h2c_dctlinfo_ud_v3 { + __le32 c0; + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 m0; + __le32 m1; + __le32 m2; + __le32 m3; + __le32 m4; + __le32 m5; + __le32 m6; + __le32 m7; + __le32 m8; + __le32 m9; + __le32 m10; + __le32 m11; + __le32 m12; + __le32 m13; + __le32 m14; + __le32 m15; +} __packed; + +#define DCTLINFO_V3_C0_MACID GENMASK(15, 0) +#define DCTLINFO_V3_C0_OP BIT(16) + +#define DCTLINFO_V3_W0_QOS_FIELD_H GENMASK(7, 0) +#define DCTLINFO_V3_W0_HW_EXSEQ_MACID GENMASK(14, 8) +#define DCTLINFO_V3_W0_QOS_DATA BIT(15) +#define DCTLINFO_V3_W0_AES_IV_L GENMASK(31, 16) +#define DCTLINFO_V3_W0_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W1_AES_IV_H GENMASK(31, 0) +#define DCTLINFO_V3_W1_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W2_SEQ0 GENMASK(11, 0) +#define DCTLINFO_V3_W2_SEQ1 GENMASK(23, 12) +#define DCTLINFO_V3_W2_AMSDU_MAX_LEN GENMASK(26, 24) +#define DCTLINFO_V3_W2_STA_AMSDU_EN BIT(27) +#define DCTLINFO_V3_W2_CHKSUM_OFLD_EN BIT(28) +#define DCTLINFO_V3_W2_WITH_LLC BIT(29) +#define DCTLINFO_V3_W2_NAT25_EN BIT(30) +#define DCTLINFO_V3_W2_IS_MLD BIT(31) +#define DCTLINFO_V3_W2_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W3_SEQ2 GENMASK(11, 0) +#define DCTLINFO_V3_W3_SEQ3 GENMASK(23, 12) +#define DCTLINFO_V3_W3_TGT_IND GENMASK(27, 24) +#define DCTLINFO_V3_W3_TGT_IND_EN BIT(28) +#define DCTLINFO_V3_W3_HTC_LB GENMASK(31, 29) +#define DCTLINFO_V3_W3_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W4_VLAN_TAG_SEL GENMASK(7, 5) +#define DCTLINFO_V3_W4_HTC_ORDER BIT(8) +#define DCTLINFO_V3_W4_SEC_KEY_ID GENMASK(10, 9) +#define DCTLINFO_V3_W4_VLAN_RX_DYNAMIC_PCP_EN BIT(11) +#define DCTLINFO_V3_W4_VLAN_RX_PKT_DROP BIT(12) +#define DCTLINFO_V3_W4_VLAN_RX_VALID BIT(13) +#define DCTLINFO_V3_W4_VLAN_TX_VALID BIT(14) +#define DCTLINFO_V3_W4_WAPI BIT(15) +#define DCTLINFO_V3_W4_SEC_ENT_MODE GENMASK(17, 16) +#define DCTLINFO_V3_W4_SEC_ENT0_KEYID GENMASK(19, 18) +#define DCTLINFO_V3_W4_SEC_ENT1_KEYID GENMASK(21, 20) +#define DCTLINFO_V3_W4_SEC_ENT2_KEYID GENMASK(23, 22) +#define DCTLINFO_V3_W4_SEC_ENT3_KEYID GENMASK(25, 24) +#define DCTLINFO_V3_W4_SEC_ENT4_KEYID GENMASK(27, 26) +#define DCTLINFO_V3_W4_SEC_ENT5_KEYID GENMASK(29, 28) +#define DCTLINFO_V3_W4_SEC_ENT6_KEYID GENMASK(31, 30) +#define DCTLINFO_V3_W4_ALL GENMASK(31, 5) +#define DCTLINFO_V3_W5_SEC_ENT7_KEYID GENMASK(1, 0) +#define DCTLINFO_V3_W5_SEC_ENT8_KEYID GENMASK(3, 2) +#define DCTLINFO_V3_W5_SEC_ENT_VALID_V1 GENMASK(23, 8) +#define DCTLINFO_V3_W5_ALL (GENMASK(23, 8) | GENMASK(3, 0)) +#define DCTLINFO_V3_W6_SEC_ENT0_V2 GENMASK(8, 0) +#define DCTLINFO_V3_W6_SEC_ENT1_V2 GENMASK(18, 10) +#define DCTLINFO_V3_W6_SEC_ENT2_V2 GENMASK(28, 20) +#define DCTLINFO_V3_W6_ALL GENMASK(28, 0) +#define DCTLINFO_V3_W7_SEC_ENT3_V2 GENMASK(8, 0) +#define DCTLINFO_V3_W7_SEC_ENT4_V2 GENMASK(18, 10) +#define DCTLINFO_V3_W7_SEC_ENT5_V2 GENMASK(28, 20) +#define DCTLINFO_V3_W7_ALL GENMASK(28, 0) +#define DCTLINFO_V3_W8_SEC_ENT6_V2 GENMASK(8, 0) +#define DCTLINFO_V3_W8_SEC_ENT7_V1 GENMASK(18, 10) +#define DCTLINFO_V3_W8_SEC_ENT8_V1 GENMASK(28, 20) +#define DCTLINFO_V3_W8_ALL GENMASK(28, 0) +#define DCTLINFO_V3_W9_MLD_SMA_0_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W9_MLD_SMA_1_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W9_MLD_SMA_2_V2 GENMASK(23, 16) +#define DCTLINFO_V3_W9_MLD_SMA_3_V2 GENMASK(31, 24) +#define DCTLINFO_V3_W9_MLD_SMA_L_V2 GENMASK(31, 0) +#define DCTLINFO_V3_W9_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W10_MLD_SMA_4_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W10_MLD_SMA_5_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W10_MLD_SMA_H_V2 GENMASK(15, 0) +#define DCTLINFO_V3_W10_MLD_TMA_0_V2 GENMASK(23, 16) +#define DCTLINFO_V3_W10_MLD_TMA_1_V2 GENMASK(31, 24) +#define DCTLINFO_V3_W10_MLD_TMA_L_V2 GENMASK(31, 16) +#define DCTLINFO_V3_W10_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W11_MLD_TMA_2_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W11_MLD_TMA_3_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W11_MLD_TMA_4_V2 GENMASK(23, 16) +#define DCTLINFO_V3_W11_MLD_TMA_5_V2 GENMASK(31, 24) +#define DCTLINFO_V3_W11_MLD_TMA_H_V2 GENMASK(31, 0) +#define DCTLINFO_V3_W11_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_0_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_1_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_2_V2 GENMASK(23, 16) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_3_V2 GENMASK(31, 24) +#define DCTLINFO_V3_W12_MLD_TA_BSSID_L_V2 GENMASK(31, 0) +#define DCTLINFO_V3_W12_ALL GENMASK(31, 0) +#define DCTLINFO_V3_W13_MLD_TA_BSSID_4_V2 GENMASK(7, 0) +#define DCTLINFO_V3_W13_MLD_TA_BSSID_5_V2 GENMASK(15, 8) +#define DCTLINFO_V3_W13_MLD_TA_BSSID_H_V2 GENMASK(15, 0) +#define DCTLINFO_V3_W13_HW_EXSEQ_MACID_V1 GENMASK(24, 16) +#define DCTLINFO_V3_W13_ALL GENMASK(24, 0) + 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, @@ -328,6 +453,10 @@ void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v2 *h2c); +void rtw89_cam_fill_dctl_sec_cam_info_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct rtw89_h2c_dctlinfo_ud_v3 *h2c); int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 86f1b39a967f..0b5509468582 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -295,6 +295,8 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev) mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE; } + hal->entity_force_hw = RTW89_PHY_NUM; + rtw89_config_default_chandef(rtwdev); } @@ -417,12 +419,43 @@ dflt: } EXPORT_SYMBOL(__rtw89_mgnt_chan_get); +bool rtw89_entity_check_hw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + switch (rtwdev->mlo_dbcc_mode) { + case MLO_2_PLUS_0_1RF: + return phy_idx == RTW89_PHY_0; + case MLO_0_PLUS_2_1RF: + return phy_idx == RTW89_PHY_1; + default: + return false; + } +} + +void rtw89_entity_force_hw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + rtwdev->hal.entity_force_hw = phy_idx; + + if (phy_idx != RTW89_PHY_NUM) + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "%s: %d\n", __func__, phy_idx); + else + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "%s: (none)\n", __func__); +} + static enum rtw89_mlo_dbcc_mode rtw89_entity_sel_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws) { if (rtwdev->chip->chip_gen != RTW89_CHIP_BE) return MLO_DBCC_NOT_SUPPORT; + switch (rtwdev->hal.entity_force_hw) { + case RTW89_PHY_0: + return MLO_2_PLUS_0_1RF; + case RTW89_PHY_1: + return MLO_0_PLUS_2_1RF; + default: + break; + } + switch (active_hws) { case BIT(0): return MLO_2_PLUS_0_1RF; @@ -2608,17 +2641,20 @@ bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role) { + struct rtw89_vif_link *rtwvif_link = role->rtwvif_link; struct ieee80211_vif *vif; bool start_detect; int ret; ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false, RTW89_MCC_PROBE_TIMEOUT); - if (ret) + if (ret && + READ_ONCE(rtwvif_link->sync_bcn_tsf) == rtwvif_link->last_sync_bcn_tsf) role->probe_count++; else role->probe_count = 0; + rtwvif_link->last_sync_bcn_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); if (role->probe_count < RTW89_MCC_PROBE_MAX_TRIES) return; diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 5b22764d5329..c797cda2e763 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -166,6 +166,8 @@ void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev, const struct cfg80211_chan_def *chandef); void rtw89_entity_init(struct rtw89_dev *rtwdev); enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev); +bool rtw89_entity_check_hw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw89_entity_force_hw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev); void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 0824940c91ae..6e77522bcd8f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -470,6 +470,32 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev) __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_1); } +void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + bool mon = !!rtwdev->pure_monitor_mode_vif; + bool prehdl_link = false; + + if (chip->chip_gen != RTW89_CHIP_AX && + !RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw) && + !mon && !rtw89_entity_check_hw(rtwdev, rtwvif_link->phy_idx)) + prehdl_link = true; + + if (prehdl_link) { + rtw89_entity_force_hw(rtwdev, rtwvif_link->phy_idx); + rtw89_set_channel(rtwdev); + } + + if (chip->ops->rfk_channel) + chip->ops->rfk_channel(rtwdev, rtwvif_link); + + if (prehdl_link) { + rtw89_entity_force_hw(rtwdev, RTW89_PHY_NUM); + rtw89_set_channel(rtwdev); + } +} + static void rtw89_chip_rfk_channel_for_pure_mon_vif(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -548,7 +574,7 @@ rtw89_core_get_tx_type(struct rtw89_dev *rtwdev, struct ieee80211_hdr *hdr = (void *)skb->data; __le16 fc = hdr->frame_control; - if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) + if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) return RTW89_CORE_TX_TYPE_MGMT; return RTW89_CORE_TX_TYPE_DATA; @@ -833,6 +859,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, desc_info->qsel = qsel; desc_info->ch_dma = ch_dma; + desc_info->sw_mld = true; 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; @@ -1051,6 +1078,7 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, desc_info->ch_dma = ch_dma; desc_info->tid_indicate = tid_indicate; desc_info->qsel = qsel; + desc_info->sw_mld = false; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->port = desc_info->hiq ? rtwvif_link->port : 0; desc_info->er_cap = rtwsta_link ? rtwsta_link->er_cap : false; @@ -1207,7 +1235,7 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, if (addr_cam->valid && desc_info->mlo) upd_wlan_hdr = true; - if (rtw89_is_tx_rpt_skb(rtwdev, tx_req->skb)) + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS || tx_req->with_wait) rtw89_tx_rpt_init(rtwdev, tx_req); is_bmc = (is_broadcast_ether_addr(hdr->addr1) || @@ -1326,7 +1354,7 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev, static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, - struct sk_buff *skb, int *qsel, bool sw_mld, + struct sk_buff *skb, int *qsel, struct rtw89_tx_wait_info *wait) { struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link); @@ -1341,14 +1369,15 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, tx_req.sta = sta; tx_req.rtwvif_link = rtwvif_link; tx_req.rtwsta_link = rtwsta_link; - tx_req.desc_info.sw_mld = sw_mld; - rcu_assign_pointer(skb_data->wait, wait); + tx_req.with_wait = !!wait; rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true); rtw89_wow_parse_akm(rtwdev, skb); rtw89_core_tx_update_desc_info(rtwdev, &tx_req); rtw89_core_tx_wake(rtwdev, &tx_req); + rcu_assign_pointer(skb_data->wait, wait); + ret = rtw89_hci_tx_write(rtwdev, &tx_req); if (ret) { rtw89_err(rtwdev, "failed to transmit skb to HCI\n"); @@ -1385,8 +1414,7 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, } } - return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false, - NULL); + return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, NULL); } static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info) @@ -1631,6 +1659,17 @@ static __le32 rtw89_build_txwd_body2_v2(struct rtw89_tx_desc_info *desc_info) return cpu_to_le32(dword); } +static __le32 rtw89_build_txwd_body2_v3(struct rtw89_tx_desc_info *desc_info) +{ + u32 dword = FIELD_PREP(BE_TXD_BODY2_TID_IND_V1, desc_info->tid_indicate) | + FIELD_PREP(BE_TXD_BODY2_QSEL_V1, desc_info->qsel) | + FIELD_PREP(BE_TXD_BODY2_TXPKTSIZE, desc_info->pkt_size) | + FIELD_PREP(BE_TXD_BODY2_AGG_EN, desc_info->agg_en) | + FIELD_PREP(BE_TXD_BODY2_MACID_V1, desc_info->mac_id); + + return cpu_to_le32(dword); +} + static __le32 rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq) | @@ -1640,6 +1679,16 @@ static __le32 rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info *desc_info) return cpu_to_le32(dword); } +static __le32 rtw89_build_txwd_body3_v3(struct rtw89_tx_desc_info *desc_info) +{ + u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq) | + FIELD_PREP(BE_TXD_BODY3_MLO_FLAG, desc_info->mlo) | + FIELD_PREP(BE_TXD_BODY3_IS_MLD_SW_EN, desc_info->sw_mld) | + FIELD_PREP(BE_TXD_BODY3_BK_V1, desc_info->bk); + + return cpu_to_le32(dword); +} + static __le32 rtw89_build_txwd_body4_v2(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(BE_TXD_BODY4_SEC_IV_L0, desc_info->sec_seq[0]) | @@ -1711,6 +1760,15 @@ static __le32 rtw89_build_txwd_info2_v2(struct rtw89_tx_desc_info *desc_info) return cpu_to_le32(dword); } +static __le32 rtw89_build_txwd_info2_v3(struct rtw89_tx_desc_info *desc_info) +{ + u32 dword = FIELD_PREP(BE_TXD_INFO2_AMPDU_DENSITY, desc_info->ampdu_density) | + FIELD_PREP(BE_TXD_INFO2_FORCE_KEY_EN_V1, desc_info->sec_en) | + FIELD_PREP(BE_TXD_INFO2_SEC_CAM_IDX_V1, desc_info->sec_cam_idx); + + return cpu_to_le32(dword); +} + static __le32 rtw89_build_txwd_info4_v2(struct rtw89_tx_desc_info *desc_info) { bool rts_en = !desc_info->is_bmc; @@ -1749,6 +1807,35 @@ void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_core_fill_txdesc_v2); +void rtw89_core_fill_txdesc_v3(struct rtw89_dev *rtwdev, + struct rtw89_tx_desc_info *desc_info, + void *txdesc) +{ + struct rtw89_txwd_body_v2 *txwd_body = txdesc; + struct rtw89_txwd_info_v2 *txwd_info; + + txwd_body->dword0 = rtw89_build_txwd_body0_v2(desc_info); + txwd_body->dword1 = rtw89_build_txwd_body1_v2(desc_info); + txwd_body->dword2 = rtw89_build_txwd_body2_v3(desc_info); + txwd_body->dword3 = rtw89_build_txwd_body3_v3(desc_info); + if (desc_info->sec_en) { + 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) + return; + + txwd_info = (struct rtw89_txwd_info_v2 *)(txwd_body + 1); + txwd_info->dword0 = rtw89_build_txwd_info0_v2(desc_info); + txwd_info->dword1 = rtw89_build_txwd_info1_v2(desc_info); + txwd_info->dword2 = rtw89_build_txwd_info2_v3(desc_info); + txwd_info->dword4 = rtw89_build_txwd_info4_v2(desc_info); +} +EXPORT_SYMBOL(rtw89_core_fill_txdesc_v3); + static __le32 rtw89_build_txwd_fwcmd0_v1(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(AX_RXD_RPKT_LEN_MASK, desc_info->pkt_size) | @@ -2785,7 +2872,7 @@ static void rtw89_core_bcn_track_assoc(struct rtw89_dev *rtwdev, rcu_read_lock(); bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); - beacon_int = bss_conf->beacon_int; + beacon_int = bss_conf->beacon_int ?: 100; dtim = bss_conf->dtim_period; rcu_read_unlock(); @@ -2815,9 +2902,7 @@ static void rtw89_core_bcn_track_reset(struct rtw89_dev *rtwdev) memset(&rtwdev->bcn_track, 0, sizeof(rtwdev->bcn_track)); } -static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, - struct ieee80211_bss_conf *bss_conf, - struct sk_buff *skb) +static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, struct sk_buff *skb) { #define RTW89_APPEND_TSF_2GHZ 384 #define RTW89_APPEND_TSF_5GHZ 52 @@ -2826,7 +2911,7 @@ static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; - u32 bcn_intvl_us = ieee80211_tu_to_usec(bss_conf->beacon_int); + u32 bcn_intvl_us = ieee80211_tu_to_usec(bcn_track->beacon_int); u64 tsf = le64_to_cpu(mgmt->u.beacon.timestamp); u8 wp, num = bcn_stat->num; u16 append; @@ -2834,6 +2919,10 @@ static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) return; + /* Skip if not yet associated */ + if (!bcn_intvl_us) + return; + switch (rx_status->band) { default: case NL80211_BAND_2GHZ: @@ -2921,7 +3010,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, pkt_stat->beacon_rate = desc_info->data_rate; pkt_stat->beacon_len = skb->len; - rtw89_vif_rx_bcn_stat(rtwdev, bss_conf, skb); + rtw89_vif_rx_bcn_stat(rtwdev, skb); } if (!ether_addr_equal(bss_conf->addr, hdr->addr1)) @@ -3408,6 +3497,79 @@ void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_core_query_rxdesc_v2); +void rtw89_core_query_rxdesc_v3(struct rtw89_dev *rtwdev, + struct rtw89_rx_desc_info *desc_info, + u8 *data, u32 data_offset) +{ + struct rtw89_rxdesc_phy_rpt_v2 *rxd_rpt; + struct rtw89_rxdesc_short_v3 *rxd_s; + struct rtw89_rxdesc_long_v3 *rxd_l; + u16 shift_len, drv_info_len, phy_rtp_len, hdr_cnv_len; + + rxd_s = (struct rtw89_rxdesc_short_v3 *)(data + data_offset); + + desc_info->pkt_size = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_LEN_MASK); + desc_info->drv_info_size = le32_get_bits(rxd_s->dword0, BE_RXD_DRV_INFO_SZ_MASK); + desc_info->phy_rpt_size = le32_get_bits(rxd_s->dword0, BE_RXD_PHY_RPT_SZ_MASK); + desc_info->hdr_cnv_size = le32_get_bits(rxd_s->dword0, BE_RXD_HDR_CNV_SZ_MASK); + desc_info->shift = le32_get_bits(rxd_s->dword0, BE_RXD_SHIFT_MASK); + desc_info->long_rxdesc = le32_get_bits(rxd_s->dword0, BE_RXD_LONG_RXD); + desc_info->pkt_type = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_TYPE_MASK); + desc_info->bb_sel = le32_get_bits(rxd_s->dword0, BE_RXD_BB_SEL); + if (desc_info->pkt_type == RTW89_CORE_RX_TYPE_PPDU_STAT) + desc_info->mac_info_valid = true; + + desc_info->frame_type = le32_get_bits(rxd_s->dword2, BE_RXD_TYPE_MASK); + desc_info->mac_id = le32_get_bits(rxd_s->dword2, BE_RXD_MAC_ID_V1); + desc_info->addr_cam_valid = le32_get_bits(rxd_s->dword2, BE_RXD_ADDR_CAM_VLD); + + desc_info->icv_err = le32_get_bits(rxd_s->dword3, BE_RXD_ICV_ERR); + desc_info->crc32_err = le32_get_bits(rxd_s->dword3, BE_RXD_CRC32_ERR); + desc_info->hw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_HW_DEC); + desc_info->sw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_SW_DEC); + desc_info->addr1_match = le32_get_bits(rxd_s->dword3, BE_RXD_A1_MATCH); + + desc_info->bw = le32_get_bits(rxd_s->dword4, BE_RXD_BW_MASK); + desc_info->data_rate = le32_get_bits(rxd_s->dword4, BE_RXD_RX_DATARATE_MASK); + desc_info->gi_ltf = le32_get_bits(rxd_s->dword4, BE_RXD_RX_GI_LTF_MASK); + desc_info->ppdu_cnt = le32_get_bits(rxd_s->dword4, BE_RXD_PPDU_CNT_MASK); + desc_info->ppdu_type = le32_get_bits(rxd_s->dword4, BE_RXD_PPDU_TYPE_MASK); + + desc_info->free_run_cnt = le32_to_cpu(rxd_s->dword5); + + shift_len = desc_info->shift << 1; /* 2-byte unit */ + drv_info_len = desc_info->drv_info_size << 3; /* 8-byte unit */ + phy_rtp_len = desc_info->phy_rpt_size << 3; /* 8-byte unit */ + hdr_cnv_len = desc_info->hdr_cnv_size << 4; /* 16-byte unit */ + desc_info->offset = data_offset + shift_len + drv_info_len + + phy_rtp_len + hdr_cnv_len; + + if (desc_info->long_rxdesc) + desc_info->rxd_len = sizeof(struct rtw89_rxdesc_long_v3); + else + desc_info->rxd_len = sizeof(struct rtw89_rxdesc_short_v3); + desc_info->ready = true; + + if (phy_rtp_len == sizeof(*rxd_rpt)) { + rxd_rpt = (struct rtw89_rxdesc_phy_rpt_v2 *)(data + data_offset + + desc_info->rxd_len); + desc_info->rssi = le32_get_bits(rxd_rpt->dword0, BE_RXD_PHY_RSSI); + } + + if (!desc_info->long_rxdesc) + return; + + rxd_l = (struct rtw89_rxdesc_long_v3 *)(data + data_offset); + + desc_info->sr_en = le32_get_bits(rxd_l->dword6, BE_RXD_SR_EN); + desc_info->user_id = le32_get_bits(rxd_l->dword6, BE_RXD_USER_ID_MASK); + desc_info->addr_cam_id = le32_get_bits(rxd_l->dword6, BE_RXD_ADDR_CAM_V1); + desc_info->sec_cam_id = le32_get_bits(rxd_l->dword6, BE_RXD_SEC_CAM_IDX_V1); + + desc_info->rx_pl_id = le32_get_bits(rxd_l->dword7, BE_RXD_RX_PL_ID_MASK); +} +EXPORT_SYMBOL(rtw89_core_query_rxdesc_v3); + struct rtw89_core_iter_rx_status { struct rtw89_dev *rtwdev; struct ieee80211_rx_status *rx_status; @@ -4091,8 +4253,7 @@ int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rt goto out; } - ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true, - wait); + ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, wait); if (ret) { rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret); dev_kfree_skb_any(skb); @@ -5085,7 +5246,7 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev, } vht_cap->vht_supported = true; - vht_cap->cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + vht_cap->cap = chip->max_vht_mpdu_cap | IEEE80211_VHT_CAP_SHORT_GI_80 | IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_HTC_VHT | @@ -5213,7 +5374,7 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | - le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + le16_encode_bits(chip->max_vht_mpdu_cap, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); iftype_data->he_6ghz_capa.capa = capa; } @@ -5234,7 +5395,7 @@ static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev, u8 val, val_mcs13; int sts = 8; - if (chip->chip_gen == RTW89_CHIP_AX) + if (chip->chip_gen == RTW89_CHIP_AX || hal->no_eht) return; if (hal->no_mcs_12_13) @@ -5251,7 +5412,7 @@ static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev, eht_cap->has_eht = true; eht_cap_elem->mac_cap_info[0] = - u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991, + u8_encode_bits(chip->max_eht_mpdu_cap, IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); eht_cap_elem->mac_cap_info[1] = 0; @@ -5657,6 +5818,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) rtw89_phy_dm_init(rtwdev); + rtw89_mac_set_edcca_mode_bands(rtwdev, true); rtw89_mac_cfg_ppdu_status_bands(rtwdev, true); rtw89_mac_cfg_phy_rpt_bands(rtwdev, true); rtw89_mac_update_rts_threshold(rtwdev); @@ -5923,6 +6085,9 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) struct rtw89_btc *btc = &rtwdev->btc; u8 band; + bitmap_or(rtwdev->quirks, rtwdev->quirks, &rtwdev->chip->default_quirks, + NUM_OF_RTW89_QUIRKS); + INIT_LIST_HEAD(&rtwdev->ba_list); INIT_LIST_HEAD(&rtwdev->forbid_ba_list); INIT_LIST_HEAD(&rtwdev->rtwvifs_list); @@ -6080,7 +6245,9 @@ void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; int ret; + u8 val2; u8 val; u8 cv; @@ -6092,14 +6259,28 @@ static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev) cv = CHIP_CBV; } - rtwdev->hal.cv = cv; + hal->cv = cv; - if (rtw89_is_rtl885xb(rtwdev)) { + if (rtw89_is_rtl885xb(rtwdev) || chip->chip_gen >= RTW89_CHIP_BE) { ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CV, &val); if (ret) return; - rtwdev->hal.acv = u8_get_bits(val, XTAL_SI_ACV_MASK); + hal->acv = u8_get_bits(val, XTAL_SI_ACV_MASK); + } + + if (chip->chip_gen >= RTW89_CHIP_BE) { + hal->cid = + rtw89_read32_mask(rtwdev, R_BE_SYS_CHIPINFO, B_BE_HW_ID_MASK); + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CHIP_ID_L, &val); + if (ret) + return; + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CHIP_ID_H, &val2); + if (ret) + return; + + hal->aid = val | val2 << 8; } } @@ -6198,7 +6379,8 @@ int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, goto wake_queue; } - rtw89_chip_rfk_channel(rtwdev, target); + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) + rtw89_chip_rfk_channel(rtwdev, target); rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR; @@ -6309,6 +6491,8 @@ void rtw89_core_rfkill_poll(struct rtw89_dev *rtwdev, bool force) int rtw89_chip_info_setup(struct rtw89_dev *rtwdev) { + struct rtw89_efuse *efuse = &rtwdev->efuse; + struct rtw89_hal *hal = &rtwdev->hal; int ret; rtw89_read_chip_ver(rtwdev); @@ -6348,6 +6532,9 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev) rtw89_core_setup_rfe_parms(rtwdev); rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev); + rtw89_info(rtwdev, "chip info CID: %x, CV: %x, AID: %x, ACV: %x, RFE: %d\n", + hal->cid, hal->cv, hal->aid, hal->acv, efuse->rfe_type); + out: rtw89_mac_pwr_off(rtwdev); @@ -6398,8 +6585,8 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) hw->extra_tx_headroom = tx_headroom; hw->queues = IEEE80211_NUM_ACS; - hw->max_rx_aggregation_subframes = RTW89_MAX_RX_AGG_NUM; - hw->max_tx_aggregation_subframes = RTW89_MAX_TX_AGG_NUM; + hw->max_rx_aggregation_subframes = chip->max_rx_agg_num; + hw->max_tx_aggregation_subframes = chip->max_tx_agg_num; hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a9cb47ea0b93..1abd09d9d29c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -25,6 +25,7 @@ struct rtw89_fw_txpwr_track_cfg; struct rtw89_phy_rfk_log_fmt; struct rtw89_debugfs; struct rtw89_regd_data; +struct rtw89_wow_cam_info; extern const struct ieee80211_ops rtw89_ops; @@ -158,6 +159,17 @@ enum rtw89_core_chip_id { RTL8922D, }; +enum rtw89_core_chip_cid { + RTL8922D_CID7025 = 0x74, + RTL8922D_CID7090 = 0x79, +}; + +enum rtw89_core_chip_aid { + RTL8922D_AID1348 = 0x1348, + RTL8922D_AID7060 = 0x7060, + RTL8922D_AID7102 = 0x7102, +}; + enum rtw89_chip_gen { RTW89_CHIP_AX, RTW89_CHIP_BE, @@ -1125,6 +1137,15 @@ struct rtw89_rxdesc_short_v2 { __le32 dword5; } __packed; +struct rtw89_rxdesc_short_v3 { + __le32 dword0; + __le32 dword1; + __le32 dword2; + __le32 dword3; + __le32 dword4; + __le32 dword5; +} __packed; + struct rtw89_rxdesc_long { __le32 dword0; __le32 dword1; @@ -1149,6 +1170,19 @@ struct rtw89_rxdesc_long_v2 { __le32 dword9; } __packed; +struct rtw89_rxdesc_long_v3 { + __le32 dword0; + __le32 dword1; + __le32 dword2; + __le32 dword3; + __le32 dword4; + __le32 dword5; + __le32 dword6; + __le32 dword7; + __le32 dword8; + __le32 dword9; +} __packed; + struct rtw89_rxdesc_phy_rpt_v2 { __le32 dword0; __le32 dword1; @@ -1211,6 +1245,8 @@ struct rtw89_core_tx_request { struct rtw89_vif_link *rtwvif_link; struct rtw89_sta_link *rtwsta_link; struct rtw89_tx_desc_info desc_info; + + bool with_wait; }; struct rtw89_txq { @@ -3404,9 +3440,6 @@ struct rtw89_ra_info { #define RTW89_PPDU_MAC_RX_CNT_SIZE 96 #define RTW89_PPDU_MAC_RX_CNT_SIZE_V1 128 -#define RTW89_MAX_RX_AGG_NUM 64 -#define RTW89_MAX_TX_AGG_NUM 128 - struct rtw89_ampdu_params { u16 agg_num; bool amsdu; @@ -3833,6 +3866,8 @@ struct rtw89_chip_ops { struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params); + int (*h2c_wow_cam_update)(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info); void (*btc_set_rfe)(struct rtw89_dev *rtwdev); void (*btc_init_cfg)(struct rtw89_dev *rtwdev); @@ -3965,6 +4000,11 @@ struct rtw89_hfc_prec_cfg { u8 h2c_full_cond; u8 wp_ch07_full_cond; u8 wp_ch811_full_cond; + /* for WiFi 7 chips after 8922D */ + u16 ch011_full_page; + u16 h2c_full_page; + u16 wp_ch07_full_page; + u16 wp_ch811_full_page; }; struct rtw89_hfc_param { @@ -3989,13 +4029,14 @@ struct rtw89_dle_size { u16 pge_size; u16 lnk_pge_num; u16 unlnk_pge_num; - /* for WiFi 7 chips below */ + /* for WiFi 7 chips below (suffix v1) */ u32 srt_ofst; }; struct rtw89_wde_quota { u16 hif; u16 wcpu; + /* unused dcpu isn't listed */ u16 pkt_in; u16 cpu_io; }; @@ -4013,8 +4054,10 @@ struct rtw89_ple_quota { u16 wd_rel; u16 cpu_io; u16 tx_rpt; - /* for WiFi 7 chips below */ + /* for WiFi 7 chips below (suffix v1) */ u16 h2d; + /* for WiFi 7 chips after 8922D (suffix v2) */ + u16 snrpt; }; struct rtw89_rsvd_quota { @@ -4035,6 +4078,17 @@ struct rtw89_dle_rsvd_size { u32 size; }; +struct rtw89_dle_input { + u32 tx_ampdu_num_b0; + u32 tx_ampdu_num_b1; + u32 tx_amsdu_size; /* unit: KB */ + u32 h2c_max_size; + u32 rx_amsdu_size; /* unit: KB */ + u32 c2h_max_size; + u32 mpdu_info_tbl_b0; + u32 mpdu_info_tbl_b1; +}; + struct rtw89_dle_mem { enum rtw89_qta_mode mode; const struct rtw89_dle_size *wde_size; @@ -4047,6 +4101,8 @@ struct rtw89_dle_mem { const struct rtw89_rsvd_quota *rsvd_qt; const struct rtw89_dle_rsvd_size *rsvd0_size; const struct rtw89_dle_rsvd_size *rsvd1_size; + /* for WiFi 7 chips after 8922D */ + const struct rtw89_dle_input *dle_input; }; struct rtw89_reg_def { @@ -4325,6 +4381,13 @@ struct rtw89_rfkill_regs { struct rtw89_reg3_def mode; }; +struct rtw89_sb_regs { + struct { + u32 cfg; + u32 get; + } n[2]; +}; + struct rtw89_dig_regs { u32 seg0_pd_reg; u32 pd_lower_bound_mask; @@ -4424,6 +4487,10 @@ struct rtw89_chip_info { bool small_fifo_size; u32 dle_scc_rsvd_size; u16 max_amsdu_limit; + u16 max_vht_mpdu_cap; + u16 max_eht_mpdu_cap; + u16 max_tx_agg_num; + u16 max_rx_agg_num; bool dis_2g_40m_ul_ofdma; u32 rsvd_ple_ofst; const struct rtw89_hfc_param_ini *hfc_param_ini[RTW89_HCI_TYPE_NUM]; @@ -4538,10 +4605,12 @@ struct rtw89_chip_info { u32 bss_clr_map_reg; const struct rtw89_rfkill_regs *rfkill_init; struct rtw89_reg_def rfkill_get; + struct rtw89_sb_regs btc_sb; u32 dma_ch_mask; const struct rtw89_edcca_regs *edcca_regs; const struct wiphy_wowlan_support *wowlan_stub; const struct rtw89_xtal_info *xtal_info; + unsigned long default_quirks; /* bitmap of rtw89_quirks */ }; struct rtw89_chip_variant { @@ -4572,6 +4641,7 @@ enum rtw89_hcifc_mode { struct rtw89_dle_info { const struct rtw89_rsvd_quota *rsvd_qt; + const struct rtw89_dle_input *dle_input; enum rtw89_qta_mode qta_mode; u16 ple_pg_size; u16 ple_free_pg; @@ -4664,8 +4734,17 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_MACID_PAUSE_SLEEP, RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V0, RTW89_FW_FEATURE_WOW_REASON_V1, - RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, - RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V1, + RTW89_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V1, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V2, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V3, + ), + RTW89_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY_MCC, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_MCC_V0, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_MCC_V1, + RTW89_FW_FEATURE_RFK_PRE_NOTIFY_MCC_V2, + ), RTW89_FW_FEATURE_RFK_RXDCK_V0, RTW89_FW_FEATURE_RFK_IQK_V0, RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, @@ -4680,6 +4759,10 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_LPS_DACK_BY_C2H_REG, RTW89_FW_FEATURE_BEACON_TRACKING, RTW89_FW_FEATURE_ADDR_CAM_V0, + RTW89_FW_FEATURE_SER_L1_BY_EVENT, + RTW89_FW_FEATURE_SIM_SER_L0L1_BY_HALT_H2C, + + NUM_OF_RTW89_FW_FEATURES, }; struct rtw89_fw_suit { @@ -4771,20 +4854,28 @@ struct rtw89_fw_info { struct rtw89_fw_suit bbmcu0; struct rtw89_fw_suit bbmcu1; struct rtw89_fw_log log; - u32 feature_map; struct rtw89_fw_elm_info elm_info; struct rtw89_fw_secure sec; + + DECLARE_BITMAP(feature_map, NUM_OF_RTW89_FW_FEATURES); }; #define RTW89_CHK_FW_FEATURE(_feat, _fw) \ - (!!((_fw)->feature_map & BIT(RTW89_FW_FEATURE_ ## _feat))) + test_bit(RTW89_FW_FEATURE_ ## _feat, (_fw)->feature_map) #define RTW89_CHK_FW_FEATURE_GROUP(_grp, _fw) \ - (!!((_fw)->feature_map & GENMASK(RTW89_FW_FEATURE_ ## _grp ## _MAX, \ - RTW89_FW_FEATURE_ ## _grp ## _MIN))) +({ \ + unsigned int bit = find_next_bit((_fw)->feature_map, \ + NUM_OF_RTW89_FW_FEATURES, \ + RTW89_FW_FEATURE_ ## _grp ## _MIN); \ + bit <= RTW89_FW_FEATURE_ ## _grp ## _MAX; \ +}) #define RTW89_SET_FW_FEATURE(_fw_feature, _fw) \ - ((_fw)->feature_map |= BIT(_fw_feature)) + set_bit(_fw_feature, (_fw)->feature_map) + +#define RTW89_CLR_FW_FEATURE(_fw_feature, _fw) \ + clear_bit(_fw_feature, (_fw)->feature_map) struct rtw89_cam_info { DECLARE_BITMAP(addr_cam_map, RTW89_MAX_ADDR_CAM_NUM); @@ -5026,7 +5117,9 @@ enum rtw89_dm_type { struct rtw89_hal { u32 rx_fltr; u8 cv; + u8 cid; /* enum rtw89_core_chip_cid */ u8 acv; + u16 aid; /* enum rtw89_core_chip_aid */ u32 antenna_tx; u32 antenna_rx; u8 tx_nss; @@ -5037,6 +5130,7 @@ struct rtw89_hal { bool support_cckpd; bool support_igi; bool no_mcs_12_13; + bool no_eht; atomic_t roc_chanctx_idx; u8 roc_link_index; @@ -5051,6 +5145,8 @@ struct rtw89_hal { enum rtw89_entity_mode entity_mode; struct rtw89_entity_mgnt entity_mgnt; + enum rtw89_phy_idx entity_force_hw; + u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */ u8 thermal_prot_th; @@ -5065,6 +5161,8 @@ enum rtw89_flags { RTW89_FLAG_DMAC_FUNC, RTW89_FLAG_CMAC0_FUNC, RTW89_FLAG_CMAC1_FUNC, + RTW89_FLAG_CMAC0_PWR, + RTW89_FLAG_CMAC1_PWR, RTW89_FLAG_FW_RDY, RTW89_FLAG_RUNNING, RTW89_FLAG_PROBE_DONE, @@ -5095,13 +5193,15 @@ enum 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, + RTW89_CUSTID_NONE = 0, + RTW89_CUSTID_HP = 1, + RTW89_CUSTID_ASUS = 2, + RTW89_CUSTID_ACER = 3, + RTW89_CUSTID_LENOVO = 4, + RTW89_CUSTID_NEC = 5, + RTW89_CUSTID_AMD = 6, + RTW89_CUSTID_FUJITSU = 7, + RTW89_CUSTID_DELL = 8, }; enum rtw89_pkt_drop_sel { @@ -5216,6 +5316,7 @@ struct rtw89_rfk_mcc_info_data { u8 ch[RTW89_RFK_CHS_NR]; u8 band[RTW89_RFK_CHS_NR]; u8 bw[RTW89_RFK_CHS_NR]; + u32 rf18[RTW89_RFK_CHS_NR]; u8 table_idx; }; @@ -5793,7 +5894,7 @@ struct rtw89_phy_efuse_gain { struct rtw89_wow_cam_info { bool r_w; u8 idx; - u32 mask[RTW89_MAX_PATTERN_MASK_SIZE]; + __le32 mask[RTW89_MAX_PATTERN_MASK_SIZE]; u16 crc; bool negative_pattern_match; bool skip_mac_hdr; @@ -7100,15 +7201,6 @@ static inline void rtw89_chip_rfk_init_late(struct rtw89_dev *rtwdev) chip->ops->rfk_init_late(rtwdev); } -static inline void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev, - 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_link); -} - static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan) @@ -7558,6 +7650,9 @@ void rtw89_core_fill_txdesc_v1(struct rtw89_dev *rtwdev, void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); +void rtw89_core_fill_txdesc_v3(struct rtw89_dev *rtwdev, + struct rtw89_tx_desc_info *desc_info, + void *txdesc); void rtw89_core_fill_txdesc_fwcmd_v1(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); @@ -7576,6 +7671,9 @@ void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev, void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev, struct rtw89_rx_desc_info *desc_info, u8 *data, u32 data_offset); +void rtw89_core_query_rxdesc_v3(struct rtw89_dev *rtwdev, + struct rtw89_rx_desc_info *desc_info, + u8 *data, u32 data_offset); 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); @@ -7622,6 +7720,8 @@ 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_chip_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); const struct rtw89_6ghz_span * rtw89_get_6ghz_span(struct rtw89_dev *rtwdev, u32 center_freq); void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef); diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 1264c2f82600..2b48ccea27fb 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -79,6 +79,7 @@ struct rtw89_debugfs { struct rtw89_debugfs_priv send_h2c; struct rtw89_debugfs_priv early_h2c; struct rtw89_debugfs_priv fw_crash; + struct rtw89_debugfs_priv ser_counters; struct rtw89_debugfs_priv btc_info; struct rtw89_debugfs_priv btc_manual; struct rtw89_debugfs_priv fw_log_manual; @@ -3537,6 +3538,14 @@ out: return count; } +static int rtw89_dbg_trigger_ctrl_error_by_halt_h2c(struct rtw89_dev *rtwdev) +{ + if (!test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) + return -EBUSY; + + return rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RESET_FORCE); +} + static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -3544,6 +3553,9 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) u16 pkt_id; int ret; + if (RTW89_CHK_FW_FEATURE(SIM_SER_L0L1_BY_HALT_H2C, &rtwdev->fw)) + return rtw89_dbg_trigger_ctrl_error_by_halt_h2c(rtwdev); + rtw89_leave_ps_mode(rtwdev); ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id); @@ -3600,10 +3612,21 @@ static int rtw89_dbg_trigger_mac_error_be(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_dbg_trigger_mac_error_by_halt_h2c(struct rtw89_dev *rtwdev) +{ + if (!test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) + return -EBUSY; + + return rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L0_RESET_FORCE); +} + static int rtw89_dbg_trigger_mac_error(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + if (RTW89_CHK_FW_FEATURE(SIM_SER_L0L1_BY_HALT_H2C, &rtwdev->fw)) + return rtw89_dbg_trigger_mac_error_by_halt_h2c(rtwdev); + rtw89_leave_ps_mode(rtwdev); switch (chip->chip_gen) { @@ -3680,6 +3703,60 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev, return count; } +struct rtw89_dbg_ser_counters { + unsigned int l0; + unsigned int l1; + unsigned int l0_to_l1; +}; + +static void rtw89_dbg_get_ser_counters_ax(struct rtw89_dev *rtwdev, + struct rtw89_dbg_ser_counters *cnt) +{ + const u32 val = rtw89_read32(rtwdev, R_AX_SER_DBG_INFO); + + cnt->l0 = u32_get_bits(val, B_AX_SER_L0_COUNTER_MASK); + cnt->l1 = u32_get_bits(val, B_AX_SER_L1_COUNTER_MASK); + cnt->l0_to_l1 = u32_get_bits(val, B_AX_L0_TO_L1_EVENT_MASK); +} + +static void rtw89_dbg_get_ser_counters_be(struct rtw89_dev *rtwdev, + struct rtw89_dbg_ser_counters *cnt) +{ + const u32 val = rtw89_read32(rtwdev, R_BE_SER_DBG_INFO); + + cnt->l0 = u32_get_bits(val, B_BE_SER_L0_COUNTER_MASK); + cnt->l1 = u32_get_bits(val, B_BE_SER_L1_COUNTER_MASK); + cnt->l0_to_l1 = u32_get_bits(val, B_BE_SER_L0_PROMOTE_L1_EVENT_MASK); +} + +static ssize_t rtw89_debug_priv_ser_counters_get(struct rtw89_dev *rtwdev, + struct rtw89_debugfs_priv *debugfs_priv, + char *buf, size_t bufsz) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_dbg_ser_counters cnt = {}; + char *p = buf, *end = buf + bufsz; + + rtw89_leave_ps_mode(rtwdev); + + switch (chip->chip_gen) { + case RTW89_CHIP_AX: + rtw89_dbg_get_ser_counters_ax(rtwdev, &cnt); + break; + case RTW89_CHIP_BE: + rtw89_dbg_get_ser_counters_be(rtwdev, &cnt); + break; + default: + return -EOPNOTSUPP; + } + + p += scnprintf(p, end - p, "SER L0 Count: %d\n", cnt.l0); + p += scnprintf(p, end - p, "SER L1 Count: %d\n", cnt.l1); + p += scnprintf(p, end - p, "SER L0 promote event: %d\n", cnt.l0_to_l1); + + return p - buf; +} + static ssize_t rtw89_debug_priv_btc_info_get(struct rtw89_dev *rtwdev, struct rtw89_debugfs_priv *debugfs_priv, char *buf, size_t bufsz) @@ -4767,6 +4844,7 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = { .send_h2c = rtw89_debug_priv_set(send_h2c), .early_h2c = rtw89_debug_priv_set_and_get(early_h2c, RWLOCK), .fw_crash = rtw89_debug_priv_set_and_get(fw_crash, WLOCK), + .ser_counters = rtw89_debug_priv_get(ser_counters, RLOCK), .btc_info = rtw89_debug_priv_get(btc_info, RSIZE_12K), .btc_manual = rtw89_debug_priv_set(btc_manual), .fw_log_manual = rtw89_debug_priv_set(fw_log_manual, WLOCK), @@ -4814,6 +4892,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top rtw89_debugfs_add_w(send_h2c); rtw89_debugfs_add_rw(early_h2c); rtw89_debugfs_add_rw(fw_crash); + rtw89_debugfs_add_r(ser_counters); rtw89_debugfs_add_r(btc_info); rtw89_debugfs_add_w(btc_manual); rtw89_debugfs_add_w(fw_log_manual); diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index 6c6c763510af..a2757a88d55d 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -7,10 +7,6 @@ #include "mac.h" #include "reg.h" -#define EF_FV_OFSET 0x5ea -#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) diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index a96fc1044791..a14a9dfed8e8 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -11,6 +11,11 @@ #define RTW89_EFUSE_BLOCK_SIZE_MASK GENMASK(15, 0) #define RTW89_EFUSE_MAX_BLOCK_SIZE 0x10000 +#define EF_FV_OFSET 0x5EA +#define EF_FV_OFSET_BE_V1 0x17CA +#define EF_CV_MASK GENMASK(7, 4) +#define EF_CV_INV 15 + struct rtw89_efuse_block_cfg { u32 offset; u32 size; @@ -26,5 +31,6 @@ 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); +int rtw89_efuse_read_ecv_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 64768923b0f0..70c1b8be662e 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse_be.c +++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c @@ -512,3 +512,29 @@ out: return 0; } + +int rtw89_efuse_read_ecv_be(struct rtw89_dev *rtwdev) +{ + u32 dump_addr; + u8 buff[4]; /* efuse access must 4 bytes align */ + int ret; + u8 ecv; + u8 val; + + dump_addr = ALIGN_DOWN(EF_FV_OFSET_BE_V1, 4); + + ret = rtw89_dump_physical_efuse_map_be(rtwdev, buff, dump_addr, 4, false); + if (ret) + return ret; + + val = buff[EF_FV_OFSET_BE_V1 & 0x3]; + + ecv = u8_get_bits(val, EF_CV_MASK); + if (ecv == EF_CV_INV) + return -ENOENT; + + rtwdev->hal.cv = ecv; + + return 0; +} +EXPORT_SYMBOL(rtw89_efuse_read_ecv_be); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 7b9d9989e517..f09387e089a2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -812,6 +812,8 @@ struct __fw_feat_cfg { enum rtw89_fw_feature feature; u32 ver_code; bool (*cond)(u32 suit_ver_code, u32 comp_ver_code); + bool disable; + int size; }; #define __CFG_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) \ @@ -822,10 +824,36 @@ struct __fw_feat_cfg { .cond = __fw_feat_cond_ ## _cond, \ } +#define __S_DIS_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) \ + { \ + .chip_id = _chip, \ + .feature = RTW89_FW_FEATURE_ ## _feat, \ + .ver_code = RTW89_FW_VER_CODE(_maj, _min, _sub, _idx), \ + .cond = __fw_feat_cond_ ## _cond, \ + .disable = true, \ + .size = 1, \ + } + +#define __G_DIS_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _grp) \ + { \ + .chip_id = _chip, \ + .feature = RTW89_FW_FEATURE_ ## _grp ## _MIN, \ + .ver_code = RTW89_FW_VER_CODE(_maj, _min, _sub, _idx), \ + .cond = __fw_feat_cond_ ## _cond, \ + .disable = true, \ + .size = RTW89_FW_FEATURE_ ## _grp ## _MAX - \ + RTW89_FW_FEATURE_ ## _grp ## _MIN + 1, \ + } + +#define __DIS_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat, _type) \ + __##_type##_DIS_FW_FEAT(_chip, _cond, _maj, _min, _sub, _idx, _feat) + static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER_TYPE_0), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), @@ -837,11 +865,14 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 15, BEACON_LOSS_COUNT_V1), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, BEACON_TRACKING), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), __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_TYPE_0), @@ -851,8 +882,10 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), - __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SER_L1_BY_EVENT), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), __CFG_FW_FEAT(RTL8852C, ge, 0, 0, 0, 0, RFK_NTFY_MCC_V0), + __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER_TYPE_0), @@ -862,25 +895,32 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 129, 1, BEACON_TRACKING), - __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), + __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 94, 0, SER_L1_BY_EVENT), + __CFG_FW_FEAT(RTL8852C, ge, 0, 29, 130, 0, SIM_SER_L0L1_BY_HALT_H2C), + __CFG_FW_FEAT(RTL8922A, ge, 0, 0, 0, 0, RFK_PRE_NOTIFY_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), - __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 21, 0, SCAN_OFFLOAD_BE_V0), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 12, 0, BEACON_FILTER), + __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 21, 0, SCAN_OFFLOAD_BE_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 28, 0, RFK_IQK_V0), - __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, RFK_PRE_NOTIFY_V0), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 31, 0, RFK_PRE_NOTIFY_V1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, LPS_CH_INFO), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 42, 0, RFK_RXDCK_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 46, 0, NOTIFY_AP_INFO), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 47, 0, CH_INFO_BE_V0), - __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 49, 0, RFK_PRE_NOTIFY_V1), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 49, 0, RFK_PRE_NOTIFY_V2), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 49, 0, RFK_PRE_NOTIFY_MCC_V0), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 51, 0, NO_PHYCAP_P1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 80, 0, BEACON_TRACKING), + __DIS_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, WITH_RFK_PRE_NOTIFY, G), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, RFK_PRE_NOTIFY_MCC_V1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 84, 0, ADDR_CAM_V0), }; @@ -896,8 +936,16 @@ static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, if (chip->chip_id != ent->chip_id) continue; - if (ent->cond(ver_code, ent->ver_code)) + if (!ent->cond(ver_code, ent->ver_code)) + continue; + + if (!ent->disable) { RTW89_SET_FW_FEATURE(ent->feature, fw); + continue; + } + + for (int n = 0; n < ent->size; n++) + RTW89_CLR_FW_FEATURE(ent->feature + n, fw); } } @@ -1013,42 +1061,47 @@ int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev, const union rtw89_fw_element_arg arg) { struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; - struct rtw89_phy_table *tbl; + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_phy_table *tbl, **pp; struct rtw89_reg2_def *regs; - enum rtw89_rf_path rf_path; + bool radio = false; u32 n_regs, i; + u16 aid; u8 idx; - tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); - if (!tbl) - return -ENOMEM; - switch (le32_to_cpu(elm->id)) { case RTW89_FW_ELEMENT_ID_BB_REG: - elm_info->bb_tbl = tbl; + pp = &elm_info->bb_tbl; break; case RTW89_FW_ELEMENT_ID_BB_GAIN: - elm_info->bb_gain = tbl; + pp = &elm_info->bb_gain; break; case RTW89_FW_ELEMENT_ID_RADIO_A: case RTW89_FW_ELEMENT_ID_RADIO_B: case RTW89_FW_ELEMENT_ID_RADIO_C: case RTW89_FW_ELEMENT_ID_RADIO_D: - rf_path = arg.rf_path; idx = elm->u.reg2.idx; + pp = &elm_info->rf_radio[idx]; - elm_info->rf_radio[idx] = tbl; - tbl->rf_path = rf_path; - tbl->config = rtw89_phy_config_rf_reg_v1; + radio = true; break; case RTW89_FW_ELEMENT_ID_RF_NCTL: - elm_info->rf_nctl = tbl; + pp = &elm_info->rf_nctl; break; default: - kfree(tbl); return -ENOENT; } + aid = le16_to_cpu(elm->aid); + if (aid && aid != hal->aid) + return 1; /* ignore if aid not matched */ + else if (*pp) + return 1; /* ignore if an element is existing */ + + tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); + if (!tbl) + return -ENOMEM; + n_regs = le32_to_cpu(elm->size) / sizeof(tbl->regs[0]); regs = kcalloc(n_regs, sizeof(*regs), GFP_KERNEL); if (!regs) @@ -1062,6 +1115,13 @@ int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev, tbl->n_regs = n_regs; tbl->regs = regs; + if (radio) { + tbl->rf_path = arg.rf_path; + tbl->config = rtw89_phy_config_rf_reg_v1; + } + + *pp = tbl; + return 0; out: @@ -1481,11 +1541,12 @@ 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) { + const struct rtw89_chip_info *chip = rtwdev->chip; struct fwcmd_hdr *hdr; hdr = (struct fwcmd_hdr *)skb_push(skb, 8); - if (!(rtwdev->fw.h2c_seq % 4)) + if (chip->chip_gen == RTW89_CHIP_AX && !(rtwdev->fw.h2c_seq % 4)) rack = true; hdr->hdr0 = cpu_to_le32(FIELD_PREP(H2C_HDR_DEL_TYPE, type) | FIELD_PREP(H2C_HDR_CAT, cat) | @@ -2267,6 +2328,45 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2); +int rtw89_fw_h2c_dctl_sec_cam_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + struct rtw89_h2c_dctlinfo_ud_v3 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for dctl sec cam\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_dctlinfo_ud_v3 *)skb->data; + + rtw89_cam_fill_dctl_sec_cam_info_v3(rtwdev, rtwvif_link, rtwsta_link, h2c); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_DCTLINFO_UD_V3, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v3); + int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link) @@ -2322,6 +2422,62 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v2); +int rtw89_fw_h2c_default_dmac_tbl_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; + struct rtw89_h2c_dctlinfo_ud_v3 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for dctl v2\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_dctlinfo_ud_v3 *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, DCTLINFO_V3_C0_MACID) | + le32_encode_bits(1, DCTLINFO_V3_C0_OP); + + h2c->m0 = cpu_to_le32(DCTLINFO_V3_W0_ALL); + h2c->m1 = cpu_to_le32(DCTLINFO_V3_W1_ALL); + h2c->m2 = cpu_to_le32(DCTLINFO_V3_W2_ALL); + h2c->m3 = cpu_to_le32(DCTLINFO_V3_W3_ALL); + h2c->m4 = cpu_to_le32(DCTLINFO_V3_W4_ALL); + h2c->m5 = cpu_to_le32(DCTLINFO_V3_W5_ALL); + h2c->m6 = cpu_to_le32(DCTLINFO_V3_W6_ALL); + h2c->m7 = cpu_to_le32(DCTLINFO_V3_W7_ALL); + h2c->m8 = cpu_to_le32(DCTLINFO_V3_W8_ALL); + h2c->m9 = cpu_to_le32(DCTLINFO_V3_W9_ALL); + h2c->m10 = cpu_to_le32(DCTLINFO_V3_W10_ALL); + h2c->m11 = cpu_to_le32(DCTLINFO_V3_W11_ALL); + h2c->m12 = cpu_to_le32(DCTLINFO_V3_W12_ALL); + h2c->m13 = cpu_to_le32(DCTLINFO_V3_W13_ALL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_DCTLINFO_UD_V3, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v3); + int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, @@ -3318,6 +3474,92 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7); +int rtw89_fw_h2c_default_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; + bool preld = rtw89_mac_chk_preload_allow(rtwdev); + struct rtw89_h2c_cctlinfo_ud_be *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for default cmac be\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + h2c->w0 = le32_encode_bits(4, BE_CCTL_INFO_W0_DATARATE); + h2c->m0 = cpu_to_le32(BE_CCTL_INFO_W0_ALL); + + h2c->w1 = le32_encode_bits(4, BE_CCTL_INFO_W1_DATA_RTY_LOWEST_RATE) | + le32_encode_bits(0xa, BE_CCTL_INFO_W1_RTSRATE) | + le32_encode_bits(4, BE_CCTL_INFO_W1_RTS_RTY_LOWEST_RATE); + h2c->m1 = cpu_to_le32(BE_CCTL_INFO_W1_ALL); + + h2c->w1 = le32_encode_bits(preld, BE_CCTL_INFO_W2_PRELOAD_ENABLE); + h2c->m2 = cpu_to_le32(BE_CCTL_INFO_W2_ALL); + + h2c->m3 = cpu_to_le32(BE_CCTL_INFO_W3_ALL); + + h2c->w4 = le32_encode_bits(0xFFFF, BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(BE_CCTL_INFO_W4_ALL); + + h2c->w5 = le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING0_V1) | + le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING1_V1) | + le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING2_V1) | + le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING3_V1) | + le32_encode_bits(2, BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING4_V1); + h2c->m5 = cpu_to_le32(BE_CCTL_INFO_W5_ALL); + + h2c->w6 = le32_encode_bits(0xb, BE_CCTL_INFO_W6_RESP_REF_RATE); + h2c->m6 = cpu_to_le32(BE_CCTL_INFO_W6_ALL); + + h2c->w7 = le32_encode_bits(1, BE_CCTL_INFO_W7_NC) | + le32_encode_bits(1, BE_CCTL_INFO_W7_NR) | + le32_encode_bits(1, BE_CCTL_INFO_W7_CB) | + le32_encode_bits(0x1, BE_CCTL_INFO_W7_CSI_PARA_EN) | + le32_encode_bits(0xb, BE_CCTL_INFO_W7_CSI_FIX_RATE); + h2c->m7 = cpu_to_le32(BE_CCTL_INFO_W7_ALL); + + h2c->m8 = cpu_to_le32(BE_CCTL_INFO_W8_ALL); + + h2c->w14 = le32_encode_bits(0, BE_CCTL_INFO_W14_VO_CURR_RATE) | + le32_encode_bits(0, BE_CCTL_INFO_W14_VI_CURR_RATE) | + le32_encode_bits(0, BE_CCTL_INFO_W14_BE_CURR_RATE_L); + h2c->m14 = cpu_to_le32(BE_CCTL_INFO_W14_ALL); + + h2c->w15 = le32_encode_bits(0, BE_CCTL_INFO_W15_BE_CURR_RATE_H) | + le32_encode_bits(0, BE_CCTL_INFO_W15_BK_CURR_RATE) | + le32_encode_bits(0, BE_CCTL_INFO_W15_MGNT_CURR_RATE); + h2c->m15 = cpu_to_le32(BE_CCTL_INFO_W15_ALL); + + 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, + 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_be); + static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, struct ieee80211_link_sta *link_sta, u8 *pads) @@ -3648,6 +3890,134 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7); +int rtw89_fw_h2c_assoc_cmac_tbl_be(struct rtw89_dev *rtwdev, + 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_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_be *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; + u16 lowest_rate; + int ret; + + memset(pads, 0, sizeof(pads)); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for assoc cmac be\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) + lowest_rate = RTW89_HW_RATE_OFDM6; + else if (chan->band_type == RTW89_BAND_2G) + lowest_rate = RTW89_HW_RATE_CCK1; + else + lowest_rate = RTW89_HW_RATE_OFDM6; + + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + h2c->w0 = le32_encode_bits(1, BE_CCTL_INFO_W0_DISRTSFB) | + le32_encode_bits(1, BE_CCTL_INFO_W0_DISDATAFB); + h2c->m0 = cpu_to_le32(BE_CCTL_INFO_W0_DISRTSFB | + BE_CCTL_INFO_W0_DISDATAFB); + + h2c->w1 = le32_encode_bits(lowest_rate, BE_CCTL_INFO_W1_RTS_RTY_LOWEST_RATE); + h2c->m1 = cpu_to_le32(BE_CCTL_INFO_W1_RTS_RTY_LOWEST_RATE); + + h2c->w2 = le32_encode_bits(0, BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL); + h2c->m2 = cpu_to_le32(BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL); + + h2c->w3 = le32_encode_bits(0, BE_CCTL_INFO_W3_RTS_TXCNT_LMT_SEL); + h2c->m3 = cpu_to_le32(BE_CCTL_INFO_W3_RTS_TXCNT_LMT_SEL); + + h2c->w4 = le32_encode_bits(rtwvif_link->port, BE_CCTL_INFO_W4_MULTI_PORT_ID); + h2c->m4 = cpu_to_le32(BE_CCTL_INFO_W4_MULTI_PORT_ID); + + if (bss_conf->eht_support) { + u16 punct = bss_conf->chanreq.oper.punctured; + + h2c->w4 |= le32_encode_bits(~punct, + BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + h2c->m4 |= cpu_to_le32(BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + } + + h2c->w5 = le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_20], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING0_V1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_40], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING1_V1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_80], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING2_V1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_160], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING3_V1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_320], + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING4_V1); + h2c->m5 = cpu_to_le32(BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING0_V1 | + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING1_V1 | + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING2_V1 | + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING3_V1 | + BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING4_V1); + + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) { + h2c->w5 |= le32_encode_bits(0, BE_CCTL_INFO_W5_DATA_DCM_V1); + h2c->m5 |= cpu_to_le32(BE_CCTL_INFO_W5_DATA_DCM_V1); + } + + h2c->w6 = le32_encode_bits(vif->cfg.aid, BE_CCTL_INFO_W6_AID12_PAID) | + le32_encode_bits(vif->type == NL80211_IFTYPE_STATION ? 1 : 0, + BE_CCTL_INFO_W6_ULDL); + h2c->m6 = cpu_to_le32(BE_CCTL_INFO_W6_AID12_PAID | BE_CCTL_INFO_W6_ULDL); + + if (rtwsta_link) { + h2c->w8 = le32_encode_bits(link_sta->he_cap.has_he, + BE_CCTL_INFO_W8_BSR_QUEUE_SIZE_FORMAT_V1); + h2c->m8 = cpu_to_le32(BE_CCTL_INFO_W8_BSR_QUEUE_SIZE_FORMAT_V1); + } + + 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, + 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_be); + int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link) @@ -3714,6 +4084,72 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_g7); +int rtw89_fw_h2c_ampdu_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) +{ + struct rtw89_sta *rtwsta = rtwsta_link->rtwsta; + struct rtw89_h2c_cctlinfo_ud_be *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 agg_num = 0; + u8 ba_bmap = 0; + int ret; + u8 tid; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for ampdu cmac be\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + for_each_set_bit(tid, rtwsta->ampdu_map, IEEE80211_NUM_TIDS) { + if (agg_num == 0) + agg_num = rtwsta->ampdu_params[tid].agg_num; + else + agg_num = min(agg_num, rtwsta->ampdu_params[tid].agg_num); + } + + if (agg_num <= 0x20) + ba_bmap = 3; + else if (agg_num > 0x20 && agg_num <= 0x40) + ba_bmap = 0; + else if (agg_num > 0x40 && agg_num <= 0x80) + ba_bmap = 1; + else if (agg_num > 0x80 && agg_num <= 0x100) + ba_bmap = 2; + else if (agg_num > 0x100 && agg_num <= 0x200) + ba_bmap = 4; + else if (agg_num > 0x200 && agg_num <= 0x400) + ba_bmap = 5; + + h2c->c0 = le32_encode_bits(rtwsta_link->mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + h2c->w3 = le32_encode_bits(ba_bmap, BE_CCTL_INFO_W3_BA_BMAP); + h2c->m3 = cpu_to_le32(BE_CCTL_INFO_W3_BA_BMAP); + + 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, 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_be); + int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { @@ -3811,6 +4247,60 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_txtime_cmac_tbl_g7); +int rtw89_fw_h2c_txtime_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) +{ + struct rtw89_h2c_cctlinfo_ud_be *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for txtime_cmac_be\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + h2c->c0 = le32_encode_bits(rtwsta_link->mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + if (rtwsta_link->cctl_tx_time) { + h2c->w3 |= le32_encode_bits(1, BE_CCTL_INFO_W3_AMPDU_TIME_SEL); + h2c->m3 |= cpu_to_le32(BE_CCTL_INFO_W3_AMPDU_TIME_SEL); + + h2c->w2 |= le32_encode_bits(rtwsta_link->ampdu_max_time, + BE_CCTL_INFO_W2_AMPDU_MAX_TIME); + h2c->m2 |= cpu_to_le32(BE_CCTL_INFO_W2_AMPDU_MAX_TIME); + } + if (rtwsta_link->cctl_tx_retry_limit) { + h2c->w2 |= le32_encode_bits(1, BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL) | + le32_encode_bits(rtwsta_link->data_tx_cnt_lmt, + BE_CCTL_INFO_W2_DATA_TX_CNT_LMT); + h2c->m2 |= cpu_to_le32(BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL | + BE_CCTL_INFO_W2_DATA_TX_CNT_LMT); + } + + 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, + 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_txtime_cmac_tbl_be); + int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u16 punctured) @@ -3854,6 +4344,48 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_punctured_cmac_tbl_g7); +int rtw89_fw_h2c_punctured_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured) +{ + struct rtw89_h2c_cctlinfo_ud_be *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for punctured cmac be\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_be *)skb->data; + + h2c->c0 = le32_encode_bits(rtwvif_link->mac_id, BE_CCTL_INFO_C0_V1_MACID) | + le32_encode_bits(1, BE_CCTL_INFO_C0_V1_OP); + + h2c->w4 = le32_encode_bits(~punctured, BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(BE_CCTL_INFO_W4_ACT_SUBCH_CBW); + + 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, + 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_punctured_cmac_tbl_be); + int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { @@ -5935,27 +6467,18 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, u8 scan_offload_ver = U8_MAX; u8 cfg_len = sizeof(*h2c); unsigned int cond; - u8 ap_idx = U8_MAX; u8 ver = U8_MAX; u8 policy_val; void *ptr; + u8 txnull; u8 txbcn; int ret; u32 len; u8 i; - scan_op[0].macid = rtwvif_link->mac_id; - scan_op[0].port = rtwvif_link->port; - scan_op[0].chan = *op; - vif = rtwvif_to_vif(rtwvif_link->rtwvif); - if (vif->type == NL80211_IFTYPE_AP) - ap_idx = 0; - - if (ext->set) { - scan_op[1] = *ext; - vif = rtwvif_to_vif(ext->rtwvif_link->rtwvif); - if (vif->type == NL80211_IFTYPE_AP) - ap_idx = 1; + if (option->num_opch > RTW89_MAX_OP_NUM_BE) { + rtw89_err(rtwdev, "num of scan OP chan %d over limit\n", option->num_opch); + return -ENOENT; } rtw89_scan_get_6g_disabled_chan(rtwdev, option); @@ -6060,11 +6583,29 @@ flex_member: } for (i = 0; i < option->num_opch; i++) { - bool is_ap_idx = i == ap_idx; + struct rtw89_vif_link *rtwvif_link_op; + bool is_ap; + + switch (i) { + case 0: + scan_op[0].macid = rtwvif_link->mac_id; + scan_op[0].port = rtwvif_link->port; + scan_op[0].chan = *op; + rtwvif_link_op = rtwvif_link; + break; + case 1: + scan_op[1] = *ext; + rtwvif_link_op = ext->rtwvif_link; + break; + } - opmode = is_ap_idx ? RTW89_SCAN_OPMODE_TBTT : RTW89_SCAN_OPMODE_INTV; - policy_val = is_ap_idx ? 2 : RTW89_OFF_CHAN_TIME / 10; - txbcn = is_ap_idx ? 1 : 0; + vif = rtwvif_to_vif(rtwvif_link_op->rtwvif); + is_ap = vif->type == NL80211_IFTYPE_AP; + txnull = !is_zero_ether_addr(rtwvif_link_op->bssid) && + vif->type != NL80211_IFTYPE_AP; + opmode = is_ap ? RTW89_SCAN_OPMODE_TBTT : RTW89_SCAN_OPMODE_INTV; + policy_val = is_ap ? 2 : RTW89_OFF_CHAN_TIME / 10; + txbcn = is_ap ? 1 : 0; opch = ptr; opch->w0 = le32_encode_bits(scan_op[i].macid, @@ -6075,7 +6616,7 @@ flex_member: RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) | le32_encode_bits(opmode, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) | - le32_encode_bits(true, + le32_encode_bits(txnull, RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL) | le32_encode_bits(policy_val, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL); @@ -6349,6 +6890,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rfk_pre_info_common *common; struct rtw89_fw_h2c_rfk_pre_info_v0 *h2c_v0; struct rtw89_fw_h2c_rfk_pre_info_v1 *h2c_v1; + struct rtw89_fw_h2c_rfk_pre_info_v2 *h2c_v2; struct rtw89_fw_h2c_rfk_pre_info *h2c; u8 tbl_sel[NUM_OF_RTW89_FW_RFK_PATH]; u32 len = sizeof(*h2c); @@ -6358,7 +6900,11 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, u32 val32; int ret; - if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V1, &rtwdev->fw)) { + if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V3, &rtwdev->fw)) { + } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V2, &rtwdev->fw)) { + len = sizeof(*h2c_v2); + ver = 2; + } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V1, &rtwdev->fw)) { len = sizeof(*h2c_v1); ver = 1; } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_V0, &rtwdev->fw)) { @@ -6372,8 +6918,21 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, return -ENOMEM; } skb_put(skb, len); + + if (ver <= 2) + goto old_format; + h2c = (struct rtw89_fw_h2c_rfk_pre_info *)skb->data; - common = &h2c->base_v1.common; + + h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + h2c->phy_idx = cpu_to_le32(phy_idx); + h2c->mlo_1_1 = cpu_to_le32(rtw89_is_mlo_1_1(rtwdev)); + + goto done; + +old_format: + h2c_v2 = (struct rtw89_fw_h2c_rfk_pre_info_v2 *)skb->data; + common = &h2c_v2->base_v1.common; common->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); @@ -6400,7 +6959,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, if (ver <= 1) continue; - h2c->cur_bandwidth[path] = + h2c_v2->cur_bandwidth[path] = cpu_to_le32(rfk_mcc->data[path].bw[tbl_sel[path]]); } @@ -6431,7 +6990,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, } if (rtw89_is_mlo_1_1(rtwdev)) { - h2c_v1 = &h2c->base_v1; + h2c_v1 = &h2c_v2->base_v1; h2c_v1->mlo_1_1 = cpu_to_le32(1); } done: @@ -6453,6 +7012,104 @@ fail: return ret; } +int rtw89_fw_h2c_rf_pre_ntfy_mcc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_mcc_info *rfk_mcc_v0 = &rtwdev->rfk_mcc; + struct rtw89_fw_h2c_rfk_pre_info_mcc_v0 *h2c_v0; + struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 *h2c_v1; + struct rtw89_fw_h2c_rfk_pre_info_mcc *h2c; + struct rtw89_hal *hal = &rtwdev->hal; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u8 ver = U8_MAX; + u8 tbl, path; + u8 tbl_sel; + int ret; + + if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_MCC_V2, &rtwdev->fw)) { + } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_MCC_V1, &rtwdev->fw)) { + len = sizeof(*h2c_v1); + ver = 1; + } else if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_MCC_V0, &rtwdev->fw)) { + len = sizeof(*h2c_v0); + ver = 0; + } + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c rfk_pre_ntfy_mcc\n"); + return -ENOMEM; + } + skb_put(skb, len); + + if (ver != 0) + goto v1; + + h2c_v0 = (struct rtw89_fw_h2c_rfk_pre_info_mcc_v0 *)skb->data; + for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) { + for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { + h2c_v0->tbl_18[tbl][path] = + cpu_to_le32(rfk_mcc_v0->data[path].rf18[tbl]); + tbl_sel = rfk_mcc_v0->data[path].table_idx; + h2c_v0->cur_18[path] = + cpu_to_le32(rfk_mcc_v0->data[path].rf18[tbl_sel]); + } + } + + h2c_v0->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + goto done; + +v1: + h2c_v1 = (struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 *)skb->data; + + BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR); + + for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) + h2c_v1->tbl_18[tbl] = cpu_to_le32(rfk_mcc->rf18[tbl]); + + BUILD_BUG_ON(ARRAY_SIZE(rtwdev->rfk_mcc.data) < NUM_OF_RTW89_FW_RFK_PATH); + + /* shared table array, but tbl_sel can be independent by path */ + for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { + tbl = rfk_mcc[path].table_idx; + h2c_v1->cur_18[path] = cpu_to_le32(rfk_mcc->rf18[tbl]); + + if (path == phy_idx) + h2c_v1->tbl_idx = tbl; + } + + h2c_v1->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + h2c_v1->phy_idx = phy_idx; + + if (rtw89_is_mlo_1_1(rtwdev)) + h2c_v1->mlo_1_1 = cpu_to_le32(1); + + if (ver == 1) + goto done; + + h2c = (struct rtw89_fw_h2c_rfk_pre_info_mcc *)skb->data; + + h2c->aid = cpu_to_le32(hal->aid); + +done: + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY, + H2C_FUNC_OUTSRC_RF_MCC_INFO, 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_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, enum rtw89_tssi_mode tssi_mode) { @@ -7044,6 +7701,9 @@ static int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev, else timeout = RTW89_C2H_TIMEOUT; + if (info->timeout) + timeout = info->timeout; + ret = read_poll_timeout_atomic(rtw89_read8, val, val, 1, timeout, false, rtwdev, chip->c2h_ctrl_reg); @@ -7384,6 +8044,7 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_chan *op = &rtwdev->scan_info.op_chan; struct rtw89_pktofld_info *info; + struct ieee80211_vif *vif; u8 band, probe_count = 0; int ret; @@ -7436,7 +8097,9 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, ch_info->pri_ch = op->primary_channel; ch_info->ch_band = op->band_type; ch_info->bw = op->band_width; - ch_info->tx_null = true; + vif = rtwvif_link_to_vif(rtwvif_link); + ch_info->tx_null = !is_zero_ether_addr(rtwvif_link->bssid) && + vif->type != NL80211_IFTYPE_AP; ch_info->num_pkt = 0; break; case RTW89_CHAN_DFS: @@ -7454,7 +8117,9 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, ch_info->pri_ch = ext->chan.primary_channel; ch_info->ch_band = ext->chan.band_type; ch_info->bw = ext->chan.band_width; - ch_info->tx_null = true; + vif = rtwvif_link_to_vif(ext->rtwvif_link); + ch_info->tx_null = !is_zero_ether_addr(ext->rtwvif_link->bssid) && + vif->type != NL80211_IFTYPE_AP; ch_info->num_pkt = 0; ch_info->macid_tx = true; break; @@ -8705,44 +9370,106 @@ fail: return ret; } -#define H2C_WOW_CAM_UPD_LEN 24 -int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, - struct rtw89_wow_cam_info *cam_info) +int rtw89_fw_h2c_wow_cam_update(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info) { + struct rtw89_h2c_wow_cam_update *h2c; + u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_CAM_UPD_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { - rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); + rtw89_err(rtwdev, "failed to alloc skb for wow cam update\n"); return -ENOMEM; } + skb_put(skb, len); + h2c = (struct rtw89_h2c_wow_cam_update *)skb->data; + + h2c->w0 = le32_encode_bits(cam_info->r_w, RTW89_H2C_WOW_CAM_UPD_W0_R_W) | + le32_encode_bits(cam_info->idx, RTW89_H2C_WOW_CAM_UPD_W0_IDX); + + if (!cam_info->valid) + goto fill_valid; + + h2c->wkfm0 = cam_info->mask[0]; + h2c->wkfm1 = cam_info->mask[1]; + h2c->wkfm2 = cam_info->mask[2]; + h2c->wkfm3 = cam_info->mask[3]; + h2c->w5 = le32_encode_bits(cam_info->crc, RTW89_H2C_WOW_CAM_UPD_W5_CRC) | + le32_encode_bits(cam_info->negative_pattern_match, + RTW89_H2C_WOW_CAM_UPD_W5_NEGATIVE_PATTERN_MATCH) | + le32_encode_bits(cam_info->skip_mac_hdr, + RTW89_H2C_WOW_CAM_UPD_W5_SKIP_MAC_HDR) | + le32_encode_bits(cam_info->uc, RTW89_H2C_WOW_CAM_UPD_W5_UC) | + le32_encode_bits(cam_info->mc, RTW89_H2C_WOW_CAM_UPD_W5_MC) | + le32_encode_bits(cam_info->bc, RTW89_H2C_WOW_CAM_UPD_W5_BC); +fill_valid: + h2c->w5 |= le32_encode_bits(cam_info->valid, RTW89_H2C_WOW_CAM_UPD_W5_VALID); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_WOW, + H2C_FUNC_WOW_CAM_UPD, 0, 1, + 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; +} +EXPORT_SYMBOL(rtw89_fw_h2c_wow_cam_update); - skb_put(skb, H2C_WOW_CAM_UPD_LEN); +int rtw89_fw_h2c_wow_cam_update_v1(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info) +{ + struct rtw89_h2c_wow_payload_cam_update *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; - RTW89_SET_WOW_CAM_UPD_R_W(skb->data, cam_info->r_w); - RTW89_SET_WOW_CAM_UPD_IDX(skb->data, cam_info->idx); - if (cam_info->valid) { - RTW89_SET_WOW_CAM_UPD_WKFM1(skb->data, cam_info->mask[0]); - RTW89_SET_WOW_CAM_UPD_WKFM2(skb->data, cam_info->mask[1]); - RTW89_SET_WOW_CAM_UPD_WKFM3(skb->data, cam_info->mask[2]); - RTW89_SET_WOW_CAM_UPD_WKFM4(skb->data, cam_info->mask[3]); - RTW89_SET_WOW_CAM_UPD_CRC(skb->data, cam_info->crc); - RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(skb->data, - cam_info->negative_pattern_match); - RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(skb->data, - cam_info->skip_mac_hdr); - RTW89_SET_WOW_CAM_UPD_UC(skb->data, cam_info->uc); - RTW89_SET_WOW_CAM_UPD_MC(skb->data, cam_info->mc); - RTW89_SET_WOW_CAM_UPD_BC(skb->data, cam_info->bc); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for wow payload cam update\n"); + return -ENOMEM; } - RTW89_SET_WOW_CAM_UPD_VALID(skb->data, cam_info->valid); + skb_put(skb, len); + h2c = (struct rtw89_h2c_wow_payload_cam_update *)skb->data; + h2c->w0 = le32_encode_bits(cam_info->r_w, RTW89_H2C_WOW_PLD_CAM_UPD_W0_R_W) | + le32_encode_bits(cam_info->idx, RTW89_H2C_WOW_PLD_CAM_UPD_W0_IDX); + h2c->w8 = le32_encode_bits(cam_info->valid, RTW89_H2C_WOW_PLD_CAM_UPD_W8_VALID) | + le32_encode_bits(1, RTW89_H2C_WOW_PLD_CAM_UPD_W8_WOW_PTR); + + if (!cam_info->valid) + goto done; + + h2c->wkfm0 = cam_info->mask[0]; + h2c->wkfm1 = cam_info->mask[1]; + h2c->wkfm2 = cam_info->mask[2]; + h2c->wkfm3 = cam_info->mask[3]; + h2c->w5 = le32_encode_bits(cam_info->uc, RTW89_H2C_WOW_PLD_CAM_UPD_W5_UC) | + le32_encode_bits(cam_info->mc, RTW89_H2C_WOW_PLD_CAM_UPD_W5_MC) | + le32_encode_bits(cam_info->bc, RTW89_H2C_WOW_PLD_CAM_UPD_W5_BC) | + le32_encode_bits(cam_info->skip_mac_hdr, + RTW89_H2C_WOW_PLD_CAM_UPD_W5_SKIP_MAC_HDR); + h2c->w6 = le32_encode_bits(cam_info->crc, RTW89_H2C_WOW_PLD_CAM_UPD_W6_CRC); + h2c->w7 = le32_encode_bits(cam_info->negative_pattern_match, + RTW89_H2C_WOW_PLD_CAM_UPD_W7_NEGATIVE_PATTERN_MATCH); + +done: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_WOW, - H2C_FUNC_WOW_CAM_UPD, 0, 1, - H2C_WOW_CAM_UPD_LEN); + H2C_FUNC_WOW_PLD_CAM_UPD, 0, 1, + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -8756,6 +9483,7 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_wow_cam_update_v1); int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index cedb4a47a769..018b3bed57d2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -42,6 +42,10 @@ struct rtw89_c2hreg_phycap { #define RTW89_C2HREG_PHYCAP_W0_BW GENMASK(31, 24) #define RTW89_C2HREG_PHYCAP_W1_TX_NSS GENMASK(7, 0) #define RTW89_C2HREG_PHYCAP_W1_PROT GENMASK(15, 8) +#define RTW89_C2HREG_PHYCAP_W1_PROT_11N 1 +#define RTW89_C2HREG_PHYCAP_W1_PROT_11AC 2 +#define RTW89_C2HREG_PHYCAP_W1_PROT_11AX 3 +#define RTW89_C2HREG_PHYCAP_W1_PROT_11BE 4 #define RTW89_C2HREG_PHYCAP_W1_NIC GENMASK(23, 16) #define RTW89_C2HREG_PHYCAP_W1_WL_FUNC GENMASK(31, 24) #define RTW89_C2HREG_PHYCAP_W2_HW_TYPE GENMASK(7, 0) @@ -120,6 +124,7 @@ struct rtw89_h2creg_sch_tx_en { struct rtw89_mac_c2h_info { u8 id; u8 content_len; + u32 timeout; union { u32 c2hreg[RTW89_C2HREG_MAX]; struct rtw89_c2hreg_hdr hdr; @@ -1517,6 +1522,153 @@ struct rtw89_h2c_cctlinfo_ud_g7 { #define CCTLINFO_G7_W15_MGNT_CURR_RATE GENMASK(27, 16) #define CCTLINFO_G7_W15_ALL GENMASK(27, 0) +struct rtw89_h2c_cctlinfo_ud_be { + __le32 c0; + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 m0; + __le32 m1; + __le32 m2; + __le32 m3; + __le32 m4; + __le32 m5; + __le32 m6; + __le32 m7; + __le32 m8; + __le32 m9; + __le32 m10; + __le32 m11; + __le32 m12; + __le32 m13; + __le32 m14; + __le32 m15; +} __packed; + +#define BE_CCTL_INFO_C0_V1_MACID GENMASK(9, 0) +#define BE_CCTL_INFO_C0_V1_OP BIT(10) + +#define BE_CCTL_INFO_W0_DATARATE GENMASK(11, 0) +#define BE_CCTL_INFO_W0_DATA_GI_LTF GENMASK(14, 12) +#define BE_CCTL_INFO_W0_TRYRATE BIT(15) +#define BE_CCTL_INFO_W0_ARFR_CTRL GENMASK(17, 16) +#define BE_CCTL_INFO_W0_DIS_HE1SS_STBC BIT(18) +#define BE_CCTL_INFO_W0_ACQ_RPT_EN BIT(20) +#define BE_CCTL_INFO_W0_MGQ_RPT_EN BIT(21) +#define BE_CCTL_INFO_W0_ULQ_RPT_EN BIT(22) +#define BE_CCTL_INFO_W0_TWTQ_RPT_EN BIT(23) +#define BE_CCTL_INFO_W0_FORCE_TXOP BIT(24) +#define BE_CCTL_INFO_W0_DISRTSFB BIT(25) +#define BE_CCTL_INFO_W0_DISDATAFB BIT(26) +#define BE_CCTL_INFO_W0_NSTR_EN BIT(27) +#define BE_CCTL_INFO_W0_AMPDU_DENSITY GENMASK(31, 28) +#define BE_CCTL_INFO_W0_ALL (GENMASK(31, 20) | GENMASK(18, 0)) +#define BE_CCTL_INFO_W1_DATA_RTY_LOWEST_RATE GENMASK(11, 0) +#define BE_CCTL_INFO_W1_RTS_TXCNT_LMT GENMASK(15, 12) +#define BE_CCTL_INFO_W1_RTSRATE GENMASK(27, 16) +#define BE_CCTL_INFO_W1_RTS_RTY_LOWEST_RATE GENMASK(31, 28) +#define BE_CCTL_INFO_W1_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W2_DATA_TX_CNT_LMT GENMASK(5, 0) +#define BE_CCTL_INFO_W2_DATA_TXCNT_LMT_SEL BIT(6) +#define BE_CCTL_INFO_W2_MAX_AGG_NUM_SEL BIT(7) +#define BE_CCTL_INFO_W2_RTS_EN BIT(8) +#define BE_CCTL_INFO_W2_CTS2SELF_EN BIT(9) +#define BE_CCTL_INFO_W2_CCA_RTS GENMASK(11, 10) +#define BE_CCTL_INFO_W2_HW_RTS_EN BIT(12) +#define BE_CCTL_INFO_W2_RTS_DROP_DATA_MODE GENMASK(14, 13) +#define BE_CCTL_INFO_W2_PRELOAD_ENABLE BIT(15) +#define BE_CCTL_INFO_W2_AMPDU_MAX_LEN GENMASK(26, 16) +#define BE_CCTL_INFO_W2_UL_MU_DIS BIT(27) +#define BE_CCTL_INFO_W2_AMPDU_MAX_TIME GENMASK(31, 28) +#define BE_CCTL_INFO_W2_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W3_MAX_AGG_NUM GENMASK(7, 0) +#define BE_CCTL_INFO_W3_DATA_BW GENMASK(10, 8) +#define BE_CCTL_INFO_W3_DATA_BW_ER BIT(11) +#define BE_CCTL_INFO_W3_BA_BMAP GENMASK(14, 12) +#define BE_CCTL_INFO_W3_VCS_STBC BIT(15) +#define BE_CCTL_INFO_W3_VO_LFTIME_SEL GENMASK(18, 16) +#define BE_CCTL_INFO_W3_VI_LFTIME_SEL GENMASK(21, 19) +#define BE_CCTL_INFO_W3_BE_LFTIME_SEL GENMASK(24, 22) +#define BE_CCTL_INFO_W3_BK_LFTIME_SEL GENMASK(27, 25) +#define BE_CCTL_INFO_W3_AMPDU_TIME_SEL BIT(28) +#define BE_CCTL_INFO_W3_AMPDU_LEN_SEL BIT(29) +#define BE_CCTL_INFO_W3_RTS_TXCNT_LMT_SEL BIT(30) +#define BE_CCTL_INFO_W3_LSIG_TXOP_EN BIT(31) +#define BE_CCTL_INFO_W3_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W4_MULTI_PORT_ID GENMASK(2, 0) +#define BE_CCTL_INFO_W4_BYPASS_PUNC BIT(3) +#define BE_CCTL_INFO_W4_MBSSID GENMASK(7, 4) +#define BE_CCTL_INFO_W4_TID_DISABLE_V1 GENMASK(15, 8) +#define BE_CCTL_INFO_W4_ACT_SUBCH_CBW GENMASK(31, 16) +#define BE_CCTL_INFO_W4_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W5_ADDR_CAM_INDEX_V1 GENMASK(9, 0) +#define BE_CCTL_INFO_W5_SR_MCS_SU GENMASK(14, 10) +#define BE_CCTL_INFO_W5_A_CTRL_BQR_V1 BIT(15) +#define BE_CCTL_INFO_W5_A_CTRL_BSR_V1 BIT(16) +#define BE_CCTL_INFO_W5_A_CTRL_CAS_V1 BIT(17) +#define BE_CCTL_INFO_W5_DATA_ER_V1 BIT(18) +#define BE_CCTL_INFO_W5_DATA_DCM_V1 BIT(19) +#define BE_CCTL_INFO_W5_DATA_LDPC_V1 BIT(20) +#define BE_CCTL_INFO_W5_DATA_STBC_V1 BIT(21) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING0_V1 GENMASK(23, 22) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING1_V1 GENMASK(25, 24) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING2_V1 GENMASK(27, 26) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING3_V1 GENMASK(29, 28) +#define BE_CCTL_INFO_W5_NOMINAL_PKT_PADDING4_V1 GENMASK(31, 30) +#define BE_CCTL_INFO_W5_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W6_AID12_PAID GENMASK(11, 0) +#define BE_CCTL_INFO_W6_RESP_REF_RATE GENMASK(23, 12) +#define BE_CCTL_INFO_W6_ULDL BIT(31) +#define BE_CCTL_INFO_W6_ALL (BIT(31) | GENMASK(23, 0)) +#define BE_CCTL_INFO_W7_NC GENMASK(2, 0) +#define BE_CCTL_INFO_W7_NR GENMASK(5, 3) +#define BE_CCTL_INFO_W7_NG GENMASK(7, 6) +#define BE_CCTL_INFO_W7_CB GENMASK(9, 8) +#define BE_CCTL_INFO_W7_CS GENMASK(11, 10) +#define BE_CCTL_INFO_W7_CSI_STBC_EN BIT(13) +#define BE_CCTL_INFO_W7_CSI_LDPC_EN BIT(14) +#define BE_CCTL_INFO_W7_CSI_PARA_EN BIT(15) +#define BE_CCTL_INFO_W7_CSI_FIX_RATE GENMASK(27, 16) +#define BE_CCTL_INFO_W7_CSI_BW GENMASK(31, 29) +#define BE_CCTL_INFO_W7_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W8_ALL_ACK_SUPPORT_V1 BIT(0) +#define BE_CCTL_INFO_W8_BSR_QUEUE_SIZE_FORMAT_V1 BIT(1) +#define BE_CCTL_INFO_W8_BSR_OM_UPD_EN_V1 BIT(2) +#define BE_CCTL_INFO_W8_MACID_FWD_IDC_V1 BIT(3) +#define BE_CCTL_INFO_W8_AZ_SEC_EN BIT(4) +#define BE_CCTL_INFO_W8_BF_SEC_EN BIT(5) +#define BE_CCTL_INFO_W8_FIX_UL_ADDRCAM_IDX_V1 BIT(6) +#define BE_CCTL_INFO_W8_CTRL_CNT_VLD_V1 BIT(7) +#define BE_CCTL_INFO_W8_CTRL_CNT_V1 GENMASK(11, 8) +#define BE_CCTL_INFO_W8_RESP_SEC_TYPE GENMASK(15, 12) +#define BE_CCTL_INFO_W8_ALL GENMASK(15, 0) +#define BE_CCTL_INFO_W9_EMLSR_TRANS_DLY GENMASK(2, 0) +#define BE_CCTL_INFO_W9_ALL GENMASK(2, 0) +#define BE_CCTL_INFO_W10_SW_EHT_NLTF GENMASK(1, 0) +#define BE_CCTL_INFO_W10_TB_MLO_MODE BIT(2) +#define BE_CCTL_INFO_W10_ALL GENMASK(2, 0) +#define BE_CCTL_INFO_W14_VO_CURR_RATE GENMASK(11, 0) +#define BE_CCTL_INFO_W14_VI_CURR_RATE GENMASK(23, 12) +#define BE_CCTL_INFO_W14_BE_CURR_RATE_L GENMASK(31, 24) +#define BE_CCTL_INFO_W14_ALL GENMASK(31, 0) +#define BE_CCTL_INFO_W15_BE_CURR_RATE_H GENMASK(3, 0) +#define BE_CCTL_INFO_W15_BK_CURR_RATE GENMASK(15, 4) +#define BE_CCTL_INFO_W15_MGNT_CURR_RATE GENMASK(27, 16) +#define BE_CCTL_INFO_W15_ALL GENMASK(27, 0) + struct rtw89_h2c_bcn_upd { __le32 w0; __le32 w1; @@ -2052,70 +2204,55 @@ static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(void *h2c, u32 val) le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); } -static inline void RTW89_SET_WOW_CAM_UPD_R_W(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_IDX(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 1)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_WKFM1(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_WKFM2(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 2, val, GENMASK(31, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_WKFM3(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 3, val, GENMASK(31, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_WKFM4(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 4, val, GENMASK(31, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_CRC(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, GENMASK(15, 0)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(22)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(23)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_UC(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(24)); -} - -static inline void RTW89_SET_WOW_CAM_UPD_MC(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(25)); -} +struct rtw89_h2c_wow_cam_update { + __le32 w0; + __le32 wkfm0; + __le32 wkfm1; + __le32 wkfm2; + __le32 wkfm3; + __le32 w5; +} __packed; -static inline void RTW89_SET_WOW_CAM_UPD_BC(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(26)); -} +#define RTW89_H2C_WOW_CAM_UPD_W0_R_W BIT(0) +#define RTW89_H2C_WOW_CAM_UPD_W0_IDX GENMASK(7, 1) +#define RTW89_H2C_WOW_CAM_UPD_WKFM0 GENMASK(31, 0) +#define RTW89_H2C_WOW_CAM_UPD_WKFM1 GENMASK(31, 0) +#define RTW89_H2C_WOW_CAM_UPD_WKFM2 GENMASK(31, 0) +#define RTW89_H2C_WOW_CAM_UPD_WKFM3 GENMASK(31, 0) +#define RTW89_H2C_WOW_CAM_UPD_W5_CRC GENMASK(15, 0) +#define RTW89_H2C_WOW_CAM_UPD_W5_NEGATIVE_PATTERN_MATCH BIT(22) +#define RTW89_H2C_WOW_CAM_UPD_W5_SKIP_MAC_HDR BIT(23) +#define RTW89_H2C_WOW_CAM_UPD_W5_UC BIT(24) +#define RTW89_H2C_WOW_CAM_UPD_W5_MC BIT(25) +#define RTW89_H2C_WOW_CAM_UPD_W5_BC BIT(26) +#define RTW89_H2C_WOW_CAM_UPD_W5_VALID BIT(31) + +struct rtw89_h2c_wow_payload_cam_update { + __le32 w0; + __le32 wkfm0; + __le32 wkfm1; + __le32 wkfm2; + __le32 wkfm3; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; +} __packed; -static inline void RTW89_SET_WOW_CAM_UPD_VALID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 5, val, BIT(31)); -} +#define RTW89_H2C_WOW_PLD_CAM_UPD_W0_R_W BIT(0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W0_IDX GENMASK(7, 1) +#define RTW89_H2C_WOW_PLD_CAM_UPD_WKFM0 GENMASK(31, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_WKFM1 GENMASK(31, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_WKFM2 GENMASK(31, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_WKFM3 GENMASK(31, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W5_UC BIT(0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W5_MC BIT(1) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W5_BC BIT(2) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W5_SKIP_MAC_HDR BIT(7) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W6_CRC GENMASK(15, 0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W7_NEGATIVE_PATTERN_MATCH BIT(0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W8_VALID BIT(0) +#define RTW89_H2C_WOW_PLD_CAM_UPD_W8_WOW_PTR BIT(1) struct rtw89_h2c_wow_gtk_ofld { __le32 w0; @@ -2826,6 +2963,7 @@ struct rtw89_h2c_scanofld_be_macc_role { __le32 w0; } __packed; +#define RTW89_MAX_OP_NUM_BE 2 #define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_BAND GENMASK(1, 0) #define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_PORT GENMASK(4, 2) #define RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_MACID GENMASK(23, 8) @@ -4177,7 +4315,8 @@ struct rtw89_fw_element_hdr { __le32 id; /* enum rtw89_fw_element_id */ __le32 size; /* exclude header size */ u8 ver[4]; - __le32 rsvd0; + __le16 aid; /* should match rtw89_hal::aid */ + __le16 rsvd0; __le32 rsvd1; __le32 rsvd2; union { @@ -4307,6 +4446,7 @@ enum rtw89_wow_h2c_func { H2C_FUNC_WAKEUP_CTRL = 0x8, H2C_FUNC_WOW_CAM_UPD = 0xC, H2C_FUNC_AOAC_REPORT_REQ = 0xD, + H2C_FUNC_WOW_PLD_CAM_UPD = 0x12, NUM_OF_RTW89_WOW_H2C_FUNC, }; @@ -4347,6 +4487,7 @@ enum rtw89_ps_h2c_func { #define H2C_FUNC_MAC_CCTLINFO_UD_V1 0xa #define H2C_FUNC_MAC_DCTLINFO_UD_V2 0xc #define H2C_FUNC_MAC_BCN_UPD_BE 0xd +#define H2C_FUNC_MAC_DCTLINFO_UD_V3 0x10 #define H2C_FUNC_MAC_CCTLINFO_UD_G7 0x11 /* CLASS 6 - Address CAM */ @@ -4483,6 +4624,7 @@ enum rtw89_mrc_h2c_func { #define H2C_CL_OUTSRC_RF_REG_B 0x9 #define H2C_CL_OUTSRC_RF_FW_NOTIFY 0xa #define H2C_FUNC_OUTSRC_RF_GET_MCCCH 0x2 +#define H2C_FUNC_OUTSRC_RF_MCC_INFO 0xf #define H2C_FUNC_OUTSRC_RF_PS_INFO 0x10 #define H2C_CL_OUTSRC_RF_FW_RFK 0xb @@ -4586,11 +4728,38 @@ struct rtw89_fw_h2c_rfk_pre_info_v1 { __le32 mlo_1_1; } __packed; -struct rtw89_fw_h2c_rfk_pre_info { +struct rtw89_fw_h2c_rfk_pre_info_v2 { struct rtw89_fw_h2c_rfk_pre_info_v1 base_v1; __le32 cur_bandwidth[NUM_OF_RTW89_FW_RFK_PATH]; } __packed; +struct rtw89_fw_h2c_rfk_pre_info { + __le32 mlo_mode; + __le32 phy_idx; + __le32 mlo_1_1; +} __packed; + +struct rtw89_fw_h2c_rfk_pre_info_mcc_v0 { + __le32 tbl_18[NUM_OF_RTW89_FW_RFK_TBL][NUM_OF_RTW89_FW_RFK_PATH]; + __le32 cur_18[NUM_OF_RTW89_FW_RFK_PATH]; + __le32 mlo_mode; +} __packed; + +struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 { + __le32 tbl_18[NUM_OF_RTW89_FW_RFK_TBL]; + __le32 cur_18[NUM_OF_RTW89_FW_RFK_PATH]; + __le32 mlo_mode; + __le32 mlo_1_1; + u8 phy_idx; + u8 tbl_idx; +} __packed; + +struct rtw89_fw_h2c_rfk_pre_info_mcc { + struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 base; + u8 rsvd[2]; + __le32 aid; +} __packed; + struct rtw89_h2c_rf_tssi { __le16 len; u8 phy; @@ -4858,25 +5027,42 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_default_cmac_tbl_be(struct rtw89_dev *rtwdev, + 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_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_default_dmac_tbl_v3(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, 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 rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_assoc_cmac_tbl_be(struct rtw89_dev *rtwdev, + 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 rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_ampdu_cmac_tbl_be(struct rtw89_dev *rtwdev, + 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_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_txtime_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u16 punctured); +int rtw89_fw_h2c_punctured_cmac_tbl_be(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, @@ -4895,6 +5081,9 @@ int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_dctl_sec_cam_v3(struct rtw89_dev *rtwdev, + 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 wiphy *wiphy, struct wiphy_work *work); void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev); @@ -4948,6 +5137,7 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_rf_pre_ntfy_mcc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); int rtw89_fw_h2c_mcc_dig(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx chanctx_idx, u8 mcc_role_idx, u8 pd_val, bool en); @@ -5054,8 +5244,10 @@ int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtw bool enable); int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, 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_cam_update(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info); +int rtw89_fw_h2c_wow_cam_update_v1(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_link *rtwvif_link, bool enable); @@ -5219,6 +5411,15 @@ int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, return 0; } +static inline +int rtw89_chip_h2c_wow_cam_update(struct rtw89_dev *rtwdev, + struct rtw89_wow_cam_info *cam_info) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_wow_cam_update(rtwdev, cam_info); +} + /* Must consider compatibility; don't insert new in the mid. * Fill each field's default value in rtw89_regd_entcpy(). */ diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index d78fbe73e365..1435e4c664b6 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -848,6 +848,7 @@ EXPORT_SYMBOL(rtw89_mac_get_err_status); int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err) { struct rtw89_ser *ser = &rtwdev->ser; + bool ser_l1_hdl = false; u32 halt; int ret = 0; @@ -856,6 +857,12 @@ int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err) return -EINVAL; } + if (err == MAC_AX_ERR_L1_DISABLE_EN || err == MAC_AX_ERR_L1_RCVY_EN) + ser_l1_hdl = true; + + if (RTW89_CHK_FW_FEATURE(SER_L1_BY_EVENT, &rtwdev->fw) && ser_l1_hdl) + goto set; + ret = read_poll_timeout(rtw89_read32, halt, (halt == 0x0), 1000, 100000, false, rtwdev, R_AX_HALT_H2C_CTRL); if (ret) { @@ -863,10 +870,10 @@ int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err) return -EFAULT; } +set: rtw89_write32(rtwdev, R_AX_HALT_H2C, err); - if (ser->prehandle_l1 && - (err == MAC_AX_ERR_L1_DISABLE_EN || err == MAC_AX_ERR_L1_RCVY_EN)) + if (ser->prehandle_l1 && ser_l1_hdl) return 0; rtw89_write32(rtwdev, R_AX_HALT_H2C_CTRL, B_AX_HALT_H2C_TRIGGER); @@ -1476,15 +1483,37 @@ static void rtw89_mac_power_switch_boot_mode(struct rtw89_dev *rtwdev) rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); } +static int rtw89_mac_pwr_off_func_for_unplugged(struct rtw89_dev *rtwdev) +{ + /* + * Avoid accessing IO for unplugged power-off to prevent warnings, + * especially XTAL SI. + */ + return 0; +} + +static void rtw89_mac_update_scoreboard(struct rtw89_dev *rtwdev, u8 val) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(chip->btc_sb.n); i++) { + reg = chip->btc_sb.n[i].cfg; + if (!reg) + continue; + + rtw89_write8(rtwdev, reg + 3, val); + } +} + 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); int ret; - u8 val; rtw89_mac_power_switch_boot_mode(rtwdev); @@ -1492,17 +1521,22 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) cfg_seq = chip->pwr_on_seq; cfg_func = chip->ops->pwr_on_func; } else { - cfg_seq = chip->pwr_off_seq; - cfg_func = chip->ops->pwr_off_func; + if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) { + cfg_seq = NULL; + cfg_func = rtw89_mac_pwr_off_func_for_unplugged; + } else { + cfg_seq = chip->pwr_off_seq; + cfg_func = chip->ops->pwr_off_func; + } } if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) __rtw89_leave_ps_mode(rtwdev); - val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, B_AX_WLMAC_PWR_STE_MASK); - if (on && val == PWR_ACT) { - rtw89_err(rtwdev, "MAC has already powered on\n"); - return -EBUSY; + if (on) { + ret = mac->reset_pwr_state(rtwdev); + if (ret) + return ret; } ret = cfg_func ? cfg_func(rtwdev) : rtw89_mac_pwr_seq(rtwdev, cfg_seq); @@ -1510,26 +1544,31 @@ 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)) + if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) { + rtw89_mac_efuse_read_ecv(rtwdev); 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); - rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_TP_MAJOR); + + rtw89_mac_update_scoreboard(rtwdev, MAC_AX_NOTIFY_TP_MAJOR); } else { clear_bit(RTW89_FLAG_POWERON, rtwdev->flags); clear_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); + clear_bit(RTW89_FLAG_CMAC0_PWR, rtwdev->flags); + clear_bit(RTW89_FLAG_CMAC1_PWR, rtwdev->flags); clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); - rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_PWR_MAJOR); + + rtw89_mac_update_scoreboard(rtwdev, MAC_AX_NOTIFY_PWR_MAJOR); rtw89_set_entity_state(rtwdev, RTW89_PHY_0, false); rtw89_set_entity_state(rtwdev, RTW89_PHY_1, false); } return 0; -#undef PWR_ACT } int rtw89_mac_pwr_on(struct rtw89_dev *rtwdev) @@ -1664,8 +1703,8 @@ static int sys_init_ax(struct rtw89_dev *rtwdev) const struct rtw89_mac_size_set rtw89_mac_size = { .hfc_preccfg_pcie = {2, 40, 0, 0, 1, 0, 0, 0}, - .hfc_prec_cfg_c0 = {2, 32, 0, 0, 0, 0, 0, 0}, - .hfc_prec_cfg_c2 = {0, 256, 0, 0, 0, 0, 0, 0}, + .hfc_prec_cfg_c0 = {2, 32, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0}, + .hfc_prec_cfg_c2 = {0, 256, 0, 0, 0, 0, 0, 0, 0, 256, 0, 0}, /* PCIE 64 */ .wde_size0 = {RTW89_WDE_PG_64, 4095, 1,}, .wde_size0_v1 = {RTW89_WDE_PG_64, 3328, 0, 0,}, @@ -1680,10 +1719,12 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_size7 = {RTW89_WDE_PG_64, 510, 2,}, /* DLFW */ .wde_size9 = {RTW89_WDE_PG_64, 0, 1024,}, + .wde_size16_v1 = {RTW89_WDE_PG_64, 639, 1, 0,}, /* 8852C USB3.0 */ .wde_size17 = {RTW89_WDE_PG_64, 354, 30,}, /* 8852C DLFW */ .wde_size18 = {RTW89_WDE_PG_64, 0, 2048,}, + .wde_size18_v1 = {RTW89_WDE_PG_64, 0, 640, 0,}, /* 8852C PCIE SCC */ .wde_size19 = {RTW89_WDE_PG_64, 3328, 0,}, .wde_size23 = {RTW89_WDE_PG_64, 1022, 2,}, @@ -1710,6 +1751,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_size18 = {RTW89_PLE_PG_128, 2544, 16,}, /* 8852C PCIE SCC */ .ple_size19 = {RTW89_PLE_PG_128, 1904, 16,}, + .ple_size20_v1 = {RTW89_PLE_PG_128, 2554, 182, 40960,}, + .ple_size22_v1 = {RTW89_PLE_PG_128, 2736, 0, 40960,}, /* 8852B USB2.0 SCC */ .ple_size32 = {RTW89_PLE_PG_128, 620, 20,}, /* 8852B USB3.0 SCC */ @@ -1721,6 +1764,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_qt0_v1 = {3302, 6, 0, 20,}, /* 8852A USB */ .wde_qt1 = {512, 196, 0, 60,}, + .wde_qt3 = {0, 0, 0, 0,}, /* DLFW */ .wde_qt4 = {0, 0, 0, 0,}, /* PCIE 64 */ @@ -1733,6 +1777,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .wde_qt17 = {0, 0, 0, 0,}, /* 8852C PCIE SCC */ .wde_qt18 = {3228, 60, 0, 40,}, + .wde_qt19_v1 = {613, 6, 0, 20,}, .wde_qt23 = {958, 48, 0, 16,}, /* 8852B USB2.0/USB3.0 SCC */ .wde_qt25 = {152, 2, 0, 8,}, @@ -1744,6 +1789,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt4 = {264, 0, 16, 20, 26, 13, 356, 0, 32, 40, 8,}, /* PCIE SCC */ .ple_qt5 = {264, 0, 32, 20, 64, 13, 1101, 0, 64, 128, 120,}, + .ple_qt5_v2 = {0, 0, 32, 256, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,}, .ple_qt9 = {0, 0, 32, 256, 0, 0, 0, 0, 0, 0, 1, 0, 0,}, /* DLFW */ .ple_qt13 = {0, 0, 16, 48, 0, 0, 0, 0, 0, 0, 0,}, @@ -1754,8 +1800,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt26 = {2654, 0, 1134, 48, 64, 13, 1478, 0, 64, 128, 120, 0,}, /* USB 52C USB3.0 */ .ple_qt42 = {1068, 0, 16, 48, 4, 13, 178, 0, 16, 1, 8, 16, 0,}, + .ple_qt42_v2 = {91, 91, 32, 16, 19, 13, 91, 91, 44, 18, 1, 4, 0, 0,}, /* USB 52C USB3.0 */ .ple_qt43 = {3068, 0, 32, 48, 4, 13, 178, 0, 16, 1, 8, 16, 0,}, + .ple_qt43_v2 = {645, 645, 32, 16, 2062, 2056, 2134, 2134, 2087, 2061, 1, 2047, 0, 0,}, /* DLFW 52C */ .ple_qt44 = {0, 0, 16, 256, 0, 0, 0, 0, 0, 0, 0, 0,}, /* DLFW 52C */ @@ -1789,8 +1837,13 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt_51b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, .ple_rsvd_qt0 = {2, 107, 107, 6, 6, 6, 6, 0, 0, 0,}, .ple_rsvd_qt1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ple_rsvd_qt9 = {1, 44, 44, 6, 6, 6, 6, 69, 0, 0,}, .rsvd0_size0 = {212992, 0,}, + .rsvd0_size6 = {40960, 0,}, .rsvd1_size0 = {587776, 2048,}, + .rsvd1_size2 = {391168, 2048,}, + .dle_input3 = {0, 0, 0, 16384, 0, 2048, 0, 0,}, + .dle_input18 = {128, 128, 11454, 2048, 0, 2048, 24, 24,}, }; EXPORT_SYMBOL(rtw89_mac_size); @@ -1811,6 +1864,7 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, } mac->dle_info.rsvd_qt = cfg->rsvd_qt; + mac->dle_info.dle_input = cfg->dle_input; mac->dle_info.ple_pg_size = cfg->ple_size->pge_size; mac->dle_info.ple_free_pg = cfg->ple_size->lnk_pge_num; mac->dle_info.qta_mode = mode; @@ -2231,8 +2285,8 @@ error: return ret; } -static int preload_init_set(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, - enum rtw89_qta_mode mode) +static int preload_init_set_ax(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_qta_mode mode) { u32 reg, max_preld_size, min_rsvd_size; @@ -2260,13 +2314,14 @@ static bool is_qta_poh(struct rtw89_dev *rtwdev) int rtw89_mac_preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, enum rtw89_qta_mode mode) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev) || !is_qta_poh(rtwdev)) return 0; - return preload_init_set(rtwdev, mac_idx, mode); + return mac->preload_init(rtwdev, mac_idx, mode); } static bool dle_is_txq_empty(struct rtw89_dev *rtwdev) @@ -3061,6 +3116,7 @@ static int rtw89_mac_setup_phycap_part0(struct rtw89_dev *rtwdev) struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_mac_c2h_info c2h_info = {}; struct rtw89_hal *hal = &rtwdev->hal; + u8 protocol; u8 tx_nss; u8 rx_nss; u8 tx_ant; @@ -3108,6 +3164,10 @@ static int rtw89_mac_setup_phycap_part0(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_FW, "TX path diversity=%d\n", hal->tx_path_diversity); rtw89_debug(rtwdev, RTW89_DBG_FW, "Antenna diversity=%d\n", hal->ant_diversity); + protocol = u32_get_bits(phycap->w1, RTW89_C2HREG_PHYCAP_W1_PROT); + if (protocol < RTW89_C2HREG_PHYCAP_W1_PROT_11BE) + hal->no_eht = true; + return 0; } @@ -3931,6 +3991,29 @@ static int rtw89_mac_feat_init(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_mac_reset_pwr_state_ax(struct rtw89_dev *rtwdev) +{ + u8 val; + + val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, B_AX_WLMAC_PWR_STE_MASK); + if (val == MAC_AX_MAC_ON) { + /* + * A USB adapter might play as USB mass storage with driver and + * then switch to WiFi adapter, causing it stays on power-on + * state when doing WiFi USB probe. Return EAGAIN to caller to + * power-off and power-on again to reset the state. + */ + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB && + !test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) + return -EAGAIN; + + rtw89_err(rtwdev, "MAC has already powered on\n"); + return -EBUSY; + } + + return 0; +} + static void rtw89_disable_fw_watchdog(struct rtw89_dev *rtwdev) { u32 val32; @@ -4145,12 +4228,19 @@ int rtw89_mac_partial_init(struct rtw89_dev *rtwdev, bool include_bb) int rtw89_mac_preinit(struct rtw89_dev *rtwdev) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; ret = rtw89_mac_pwr_on(rtwdev); if (ret) return ret; + if (mac->mac_func_en) { + ret = mac->mac_func_en(rtwdev); + if (ret) + return ret; + } + return 0; } @@ -4341,6 +4431,7 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, #define BCN_HOLD_DEF 200 #define BCN_MASK_DEF 0 #define TBTT_ERLY_DEF 5 +#define TBTT_AGG_DEF 1 #define BCN_SET_UNIT 32 #define BCN_ERLY_SET_DLY (10 * 2) @@ -4644,6 +4735,16 @@ static void rtw89_mac_port_cfg_tbtt_early(struct rtw89_dev *rtwdev, B_AX_TBTTERLY_MASK, TBTT_ERLY_DEF); } +static void rtw89_mac_port_cfg_tbtt_agg(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_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_agg, + B_AX_TBTT_AGG_NUM_MASK, TBTT_AGG_DEF); +} + static void rtw89_mac_port_cfg_bss_color(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { @@ -4904,6 +5005,7 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvi 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_agg(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); @@ -5198,10 +5300,10 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l if (start_detect) return; - ieee80211_connection_loss(vif); - } else { - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); + ieee80211_beacon_loss(vif); } + + 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; @@ -6358,9 +6460,11 @@ int rtw89_mac_cfg_plt_ax(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) void rtw89_mac_cfg_sb(struct rtw89_dev *rtwdev, u32 val) { + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 reg = chip->btc_sb.n[0].cfg; u32 fw_sb; - fw_sb = rtw89_read32(rtwdev, R_AX_SCOREBOARD); + fw_sb = rtw89_read32(rtwdev, reg); fw_sb = FIELD_GET(B_MAC_AX_SB_FW_MASK, fw_sb); fw_sb = fw_sb & ~B_MAC_AX_BTGS1_NOTIFY; if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) @@ -6371,13 +6475,16 @@ void rtw89_mac_cfg_sb(struct rtw89_dev *rtwdev, u32 val) val = B_AX_TOGGLE | FIELD_PREP(B_MAC_AX_SB_DRV_MASK, val) | FIELD_PREP(B_MAC_AX_SB_FW_MASK, fw_sb); - rtw89_write32(rtwdev, R_AX_SCOREBOARD, val); + rtw89_write32(rtwdev, reg, val); fsleep(1000); /* avoid BT FW loss information */ } u32 rtw89_mac_get_sb(struct rtw89_dev *rtwdev) { - return rtw89_read32(rtwdev, R_AX_SCOREBOARD); + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 reg = chip->btc_sb.n[0].get; + + return rtw89_read32(rtwdev, reg); } int rtw89_mac_cfg_ctrl_path(struct rtw89_dev *rtwdev, bool wl) @@ -6942,6 +7049,12 @@ int rtw89_mac_write_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 m return ret; } + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags) && + (u32_get_bits(val32, B_AX_WL_XTAL_SI_ADDR_MASK) != offset || + u32_get_bits(val32, B_AX_WL_XTAL_SI_DATA_MASK) != val)) + rtw89_warn(rtwdev, "xtal si write: offset=%x val=%x poll=%x\n", + offset, val, val32); + return 0; } @@ -6965,7 +7078,12 @@ int rtw89_mac_read_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 *val) return ret; } - *val = rtw89_read8(rtwdev, R_AX_WLAN_XTAL_SI_CTRL + 1); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags) && + u32_get_bits(val32, B_AX_WL_XTAL_SI_ADDR_MASK) != offset) + rtw89_warn(rtwdev, "xtal si read: offset=%x poll=%x\n", + offset, val32); + + *val = u32_get_bits(val32, B_AX_WL_XTAL_SI_DATA_MASK); return 0; } @@ -7184,6 +7302,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .check_mac_en = rtw89_mac_check_mac_en_ax, .sys_init = sys_init_ax, .trx_init = trx_init_ax, + .preload_init = preload_init_set_ax, + .err_imr_ctrl = err_imr_ctrl_ax, + .mac_func_en = NULL, .hci_func_en = rtw89_mac_hci_func_en_ax, .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_ax, .dle_func_en = dle_func_en_ax, @@ -7193,6 +7314,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .typ_fltr_opt = rtw89_mac_typ_fltr_opt_ax, .cfg_ppdu_status = rtw89_mac_cfg_ppdu_status_ax, .cfg_phy_rpt = NULL, + .set_edcca_mode = NULL, .dle_mix_cfg = dle_mix_cfg_ax, .chk_dle_rdy = chk_dle_rdy_ax, @@ -7206,6 +7328,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .set_cpuio = set_cpuio_ax, .dle_quota_change = dle_quota_change_ax, + .reset_pwr_state = rtw89_mac_reset_pwr_state_ax, .disable_cpu = rtw89_mac_disable_cpu_ax, .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, .fwdl_get_status = rtw89_fw_get_rdy_ax, @@ -7215,6 +7338,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_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, + .efuse_read_ecv = NULL, .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 0007229d6753..14fffb660a29 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -914,6 +914,9 @@ enum mac_ax_err_info { MAC_AX_ERR_L0_CFG_DIS_NOTIFY = 0x0011, MAC_AX_ERR_L0_CFG_HANDSHAKE = 0x0012, MAC_AX_ERR_L0_RCVY_EN = 0x0013, + MAC_AX_ERR_L0_RESET_FORCE = 0x0020, + MAC_AX_ERR_L0_RESET_FORCE_C1 = 0x0021, + MAC_AX_ERR_L1_RESET_FORCE = 0x0022, MAC_AX_SET_ERR_MAX, }; @@ -929,8 +932,10 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size wde_size6; const struct rtw89_dle_size wde_size7; const struct rtw89_dle_size wde_size9; + const struct rtw89_dle_size wde_size16_v1; const struct rtw89_dle_size wde_size17; const struct rtw89_dle_size wde_size18; + const struct rtw89_dle_size wde_size18_v1; const struct rtw89_dle_size wde_size19; const struct rtw89_dle_size wde_size23; const struct rtw89_dle_size wde_size25; @@ -946,18 +951,22 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size ple_size17; const struct rtw89_dle_size ple_size18; const struct rtw89_dle_size ple_size19; + const struct rtw89_dle_size ple_size20_v1; + const struct rtw89_dle_size ple_size22_v1; const struct rtw89_dle_size ple_size32; const struct rtw89_dle_size ple_size33; const struct rtw89_dle_size ple_size34; const struct rtw89_wde_quota wde_qt0; const struct rtw89_wde_quota wde_qt1; const struct rtw89_wde_quota wde_qt0_v1; + const struct rtw89_wde_quota wde_qt3; const struct rtw89_wde_quota wde_qt4; const struct rtw89_wde_quota wde_qt6; const struct rtw89_wde_quota wde_qt7; const struct rtw89_wde_quota wde_qt16; const struct rtw89_wde_quota wde_qt17; const struct rtw89_wde_quota wde_qt18; + const struct rtw89_wde_quota wde_qt19_v1; const struct rtw89_wde_quota wde_qt23; const struct rtw89_wde_quota wde_qt25; const struct rtw89_wde_quota wde_qt31; @@ -965,13 +974,16 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt1; const struct rtw89_ple_quota ple_qt4; const struct rtw89_ple_quota ple_qt5; + const struct rtw89_ple_quota ple_qt5_v2; const struct rtw89_ple_quota ple_qt9; const struct rtw89_ple_quota ple_qt13; const struct rtw89_ple_quota ple_qt18; const struct rtw89_ple_quota ple_qt25; const struct rtw89_ple_quota ple_qt26; const struct rtw89_ple_quota ple_qt42; + const struct rtw89_ple_quota ple_qt42_v2; const struct rtw89_ple_quota ple_qt43; + const struct rtw89_ple_quota ple_qt43_v2; const struct rtw89_ple_quota ple_qt44; const struct rtw89_ple_quota ple_qt45; const struct rtw89_ple_quota ple_qt46; @@ -991,8 +1003,14 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt_51b_wow; const struct rtw89_rsvd_quota ple_rsvd_qt0; const struct rtw89_rsvd_quota ple_rsvd_qt1; + const struct rtw89_rsvd_quota ple_rsvd_qt1_v1; + const struct rtw89_rsvd_quota ple_rsvd_qt9; const struct rtw89_dle_rsvd_size rsvd0_size0; + const struct rtw89_dle_rsvd_size rsvd0_size6; const struct rtw89_dle_rsvd_size rsvd1_size0; + const struct rtw89_dle_rsvd_size rsvd1_size2; + const struct rtw89_dle_input dle_input3; + const struct rtw89_dle_input dle_input18; }; extern const struct rtw89_mac_size_set rtw89_mac_size; @@ -1019,6 +1037,10 @@ struct rtw89_mac_gen_def { enum rtw89_mac_hwmod_sel sel); int (*sys_init)(struct rtw89_dev *rtwdev); int (*trx_init)(struct rtw89_dev *rtwdev); + int (*preload_init)(struct rtw89_dev *rtwdev, u8 mac_idx, + enum rtw89_qta_mode mode); + void (*err_imr_ctrl)(struct rtw89_dev *rtwdev, bool en); + int (*mac_func_en)(struct rtw89_dev *rtwdev); void (*hci_func_en)(struct rtw89_dev *rtwdev); void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev); void (*dle_func_en)(struct rtw89_dev *rtwdev, bool enable); @@ -1033,6 +1055,7 @@ struct rtw89_mac_gen_def { u8 mac_idx); int (*cfg_ppdu_status)(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable); void (*cfg_phy_rpt)(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable); + void (*set_edcca_mode)(struct rtw89_dev *rtwdev, u8 mac_idx, bool normal); int (*dle_mix_cfg)(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg); int (*chk_dle_rdy)(struct rtw89_dev *rtwdev, bool wde_or_ple); @@ -1052,6 +1075,7 @@ struct rtw89_mac_gen_def { struct rtw89_cpuio_ctrl *ctrl_para, bool wd); int (*dle_quota_change)(struct rtw89_dev *rtwdev, bool band1_en); + int (*reset_pwr_state)(struct rtw89_dev *rtwdev); void (*disable_cpu)(struct rtw89_dev *rtwdev); int (*fwdl_enable_wcpu)(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw, bool include_bb); @@ -1062,6 +1086,7 @@ struct rtw89_mac_gen_def { 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 (*efuse_read_ecv)(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); @@ -1105,6 +1130,14 @@ u32 rtw89_mac_reg_by_idx(struct rtw89_dev *rtwdev, u32 reg_base, u8 band) return band == 0 ? reg_base : (reg_base + mac->band1_offset); } +static inline void +rtw89_write16_idx(struct rtw89_dev *rtwdev, u32 addr, u16 data, u8 band) +{ + addr = rtw89_mac_reg_by_idx(rtwdev, addr, band); + + rtw89_write16(rtwdev, addr, data); +} + static inline u32 rtw89_mac_reg_by_port(struct rtw89_dev *rtwdev, u32 base, u8 port, u8 mac_idx) { @@ -1340,6 +1373,24 @@ int rtw89_mac_cfg_ppdu_status_bands(struct rtw89_dev *rtwdev, bool enable) return rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_1, enable); } +static inline +void rtw89_mac_set_edcca_mode(struct rtw89_dev *rtwdev, u8 mac_idx, bool normal) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + if (!mac->set_edcca_mode) + return; + + mac->set_edcca_mode(rtwdev, mac_idx, normal); +} + +static inline +void rtw89_mac_set_edcca_mode_bands(struct rtw89_dev *rtwdev, bool normal) +{ + rtw89_mac_set_edcca_mode(rtwdev, RTW89_MAC_0, normal); + rtw89_mac_set_edcca_mode(rtwdev, RTW89_MAC_1, normal); +} + void rtw89_mac_set_rx_fltr(struct rtw89_dev *rtwdev, u8 mac_idx, u32 rx_fltr); void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev); void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop); @@ -1352,6 +1403,8 @@ int rtw89_mac_cfg_gnt_v1(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); int rtw89_mac_cfg_gnt_v2(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); +int rtw89_mac_cfg_gnt_v3(struct rtw89_dev *rtwdev, + const struct rtw89_mac_ax_coex_gnt *gnt_cfg); static inline int rtw89_mac_cfg_plt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt) @@ -1567,6 +1620,8 @@ enum rtw89_mac_xtal_si_offset { XTAL_SI_APBT = 0xD1, XTAL_SI_PLL = 0xE0, XTAL_SI_PLL_1 = 0xE1, + XTAL_SI_CHIP_ID_L = 0xFD, + XTAL_SI_CHIP_ID_H = 0xFE, }; static inline @@ -1597,6 +1652,16 @@ 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 int rtw89_mac_efuse_read_ecv(struct rtw89_dev *rtwdev) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + if (!mac->efuse_read_ecv) + return -ENOENT; + + return mac->efuse_read_ecv(rtwdev); +} + static inline void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) { @@ -1605,7 +1670,7 @@ void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) if (!mac->fwdl_secure_idmem_share_mode) return; - return mac->fwdl_secure_idmem_share_mode(rtwdev, mode); + mac->fwdl_secure_idmem_share_mode(rtwdev, mode); } static inline @@ -1719,4 +1784,16 @@ void rtw89_tx_rpt_skbs_purge(struct rtw89_dev *rtwdev) rtw89_tx_rpt_tx_status(rtwdev, skbs[i], RTW89_TX_MACID_DROP); } + +static inline bool rtw89_mac_chk_preload_allow(struct rtw89_dev *rtwdev) +{ + if (rtwdev->hci.type != RTW89_HCI_TYPE_PCIE) + return false; + + if (rtwdev->chip->chip_id == RTL8922D && rtwdev->hal.cid == RTL8922D_CID7090) + return true; + + return false; +} + #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index f39ca1c2ed10..ba71709a9bc9 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -127,6 +127,7 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; rtwvif_link->rand_tsf_done = false; rtwvif_link->detect_bcn_count = 0; + rtwvif_link->last_sync_bcn_tsf = 0; rcu_read_lock(); @@ -719,7 +720,8 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_MLD_VALID_LINKS) { struct rtw89_vif_link *cur = rtw89_get_designated_link(rtwvif); - rtw89_chip_rfk_channel(rtwdev, cur); + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) + rtw89_chip_rfk_channel(rtwdev, cur); if (hweight16(vif->active_links) == 1) rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR; @@ -1612,12 +1614,23 @@ static int __rtw89_ops_set_vif_links(struct rtw89_dev *rtwdev, return 0; } -static void rtw89_vif_cfg_fw_links(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - unsigned long links, bool en) +static void rtw89_vif_update_fw_links(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + u16 current_links, bool en) { + struct rtw89_vif_ml_trans *trans = &rtwvif->ml_trans; struct rtw89_vif_link *rtwvif_link; unsigned int link_id; + unsigned long links; + + /* Do follow-up when all updating links exist. */ + if (current_links != trans->mediate_links) + return; + + if (en) + links = trans->links_to_add; + else + links = trans->links_to_del; for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { rtwvif_link = rtwvif->links[link_id]; @@ -1628,20 +1641,6 @@ static void rtw89_vif_cfg_fw_links(struct rtw89_dev *rtwdev, } } -static void rtw89_vif_update_fw_links(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - u16 current_links) -{ - struct rtw89_vif_ml_trans *trans = &rtwvif->ml_trans; - - /* Do follow-up when all updating links exist. */ - if (current_links != trans->mediate_links) - return; - - rtw89_vif_cfg_fw_links(rtwdev, rtwvif, trans->links_to_del, false); - rtw89_vif_cfg_fw_links(rtwdev, rtwvif, trans->links_to_add, true); -} - static int rtw89_ops_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1683,7 +1682,7 @@ int rtw89_ops_change_vif_links(struct ieee80211_hw *hw, if (rtwdev->scanning) rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); - rtw89_vif_update_fw_links(rtwdev, rtwvif, old_links); + rtw89_vif_update_fw_links(rtwdev, rtwvif, old_links, true); if (!old_links) __rtw89_ops_clr_vif_links(rtwdev, rtwvif, @@ -1716,6 +1715,9 @@ int rtw89_ops_change_vif_links(struct ieee80211_hw *hw, BIT(RTW89_VIF_IDLE_LINK_ID)); } + if (!ret) + rtw89_vif_update_fw_links(rtwdev, rtwvif, new_links, false); + rtw89_enter_ips_by_hwflags(rtwdev); return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 556e5f98e8d4..142e892f85c4 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -89,6 +89,7 @@ static void hfc_get_mix_info_be(struct rtw89_dev *rtwdev) struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; struct rtw89_hfc_pub_cfg *pub_cfg = ¶m->pub_cfg; struct rtw89_hfc_pub_info *info = ¶m->pub_info; + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val; val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO1); @@ -116,14 +117,23 @@ static void hfc_get_mix_info_be(struct rtw89_dev *rtwdev) val = rtw89_read32(rtwdev, R_BE_CH_PAGE_CTRL); prec_cfg->ch011_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH011_V1_MASK); + if (chip->chip_id == RTL8922D) + prec_cfg->ch011_full_page = u32_get_bits(val, B_BE_FULL_WD_PG_MASK); prec_cfg->h2c_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH12_V1_MASK); val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_CTRL2); pub_cfg->pub_max = u32_get_bits(val, B_BE_PUBPG_ALL_MASK); val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL1); - prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_MASK); - prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_MASK); + if (chip->chip_id == RTL8922D) { + prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_V1_MASK); + prec_cfg->wp_ch07_full_page = u32_get_bits(val, B_BE_FULL_PAGE_WP_CH07_MASK); + prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_V1_MASK); + prec_cfg->wp_ch811_full_page = u32_get_bits(val, B_BE_FULL_PAGE_WP_CH811_MASK); + } else { + prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_MASK); + prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_MASK); + } val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL2); pub_cfg->wp_thrd = u32_get_bits(val, B_BE_WP_THRD_MASK); @@ -148,17 +158,26 @@ static void hfc_mix_cfg_be(struct rtw89_dev *rtwdev) struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; const struct rtw89_hfc_prec_cfg *prec_cfg = ¶m->prec_cfg; const struct rtw89_hfc_pub_cfg *pub_cfg = ¶m->pub_cfg; + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val; val = u32_encode_bits(prec_cfg->ch011_prec, B_BE_PREC_PAGE_CH011_V1_MASK) | u32_encode_bits(prec_cfg->h2c_prec, B_BE_PREC_PAGE_CH12_V1_MASK); + if (chip->chip_id == RTL8922D) + val = u32_replace_bits(val, prec_cfg->ch011_full_page, B_BE_FULL_WD_PG_MASK); rtw89_write32(rtwdev, R_BE_CH_PAGE_CTRL, val); val = u32_encode_bits(pub_cfg->pub_max, B_BE_PUBPG_ALL_MASK); rtw89_write32(rtwdev, R_BE_PUB_PAGE_CTRL2, val); - val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_MASK) | - u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_MASK); + if (chip->chip_id == RTL8922D) + val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_V1_MASK) | + u32_encode_bits(prec_cfg->wp_ch07_full_page, B_BE_FULL_PAGE_WP_CH07_MASK) | + u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_V1_MASK) | + u32_encode_bits(prec_cfg->wp_ch811_full_page, B_BE_FULL_PAGE_WP_CH811_MASK); + else + val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_MASK) | + u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_MASK); rtw89_write32(rtwdev, R_BE_WP_PAGE_CTRL1, val); val = u32_replace_bits(rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL), @@ -200,6 +219,9 @@ static void dle_func_en_be(struct rtw89_dev *rtwdev, bool enable) static void dle_clk_en_be(struct rtw89_dev *rtwdev, bool enable) { + if (rtwdev->chip->chip_id != RTL8922A) + return; + if (enable) rtw89_write32_set(rtwdev, R_BE_DMAC_CLK_EN, B_BE_DLE_WDE_CLK_EN | B_BE_DLE_PLE_CLK_EN); @@ -331,6 +353,11 @@ static void ple_quota_cfg_be(struct rtw89_dev *rtwdev, SET_QUOTA(cpu_io, PLE, 10); SET_QUOTA(tx_rpt, PLE, 11); SET_QUOTA(h2d, PLE, 12); + + if (rtwdev->chip->chip_id == RTL8922A) + return; + + SET_QUOTA(snrpt, PLE, 13); } static void rtw89_mac_hci_func_en_be(struct rtw89_dev *rtwdev) @@ -341,6 +368,8 @@ static void rtw89_mac_hci_func_en_be(struct rtw89_dev *rtwdev) static void rtw89_mac_dmac_func_pre_en_be(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 mask; u32 val; val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); @@ -364,12 +393,12 @@ static void rtw89_mac_dmac_func_pre_en_be(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); - rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, - B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 | - B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 | - B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | - B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11 | - B_BE_STOP_CH12 | B_BE_STOP_CH13 | B_BE_STOP_CH14); + if (chip->chip_id == RTL8922A) + mask = B_BE_TX_STOP1_MASK; + else + mask = B_BE_TX_STOP1_MASK_V1; + + rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, mask); rtw89_write32_set(rtwdev, R_BE_DMAC_TABLE_CTRL, B_BE_DMAC_ADDR_MODE); } @@ -396,6 +425,12 @@ int rtw89_mac_write_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 m return ret; } + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags) && + (u32_get_bits(val32, B_BE_WL_XTAL_SI_ADDR_MASK) != offset || + u32_get_bits(val32, B_BE_WL_XTAL_SI_DATA_MASK) != val)) + rtw89_warn(rtwdev, "xtal si write: offset=%x val=%x poll=%x\n", + offset, val, val32); + return 0; } @@ -420,7 +455,141 @@ int rtw89_mac_read_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 *val) return ret; } - *val = rtw89_read8(rtwdev, R_BE_WLAN_XTAL_SI_CTRL + 1); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags) && + u32_get_bits(val32, B_BE_WL_XTAL_SI_ADDR_MASK) != offset) + rtw89_warn(rtwdev, "xtal si read: offset=%x poll=%x\n", + offset, val32); + + *val = u32_get_bits(val32, B_BE_WL_XTAL_SI_DATA_MASK); + + return 0; +} + +static int rtw89_mac_reset_pwr_state_be(struct rtw89_dev *rtwdev) +{ + u32 val32; + int ret; + + val32 = rtw89_read32(rtwdev, R_BE_SYSON_FSM_MON); + val32 &= WLAN_FSM_MASK; + val32 |= WLAN_FSM_SET; + rtw89_write32(rtwdev, R_BE_SYSON_FSM_MON, val32); + + ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == WLAN_FSM_IDLE, + 1000, 2000000, false, + rtwdev, R_BE_SYSON_FSM_MON, WLAN_FSM_STATE_MASK); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling WLAN PMC timeout= %X\n", val32); + return ret; + } + + val32 = rtw89_read32_mask(rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK); + if (val32 == MAC_AX_MAC_OFF) { + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, + B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + } else if (val32 == MAC_AX_MAC_ON) { + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, + B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + + ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_OFF, + 1000, 2000000, false, + rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling MAC state timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + } else if (val32 == MAC_AX_MAC_LPS) { + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, + B_BE_HAXIDMA_IO_ST | B_BE_HAXIDMA_BACKUP_RESTORE_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling HAXI IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN); + + ret = read_poll_timeout(rtw89_read32_mask, val32, !val32, + 1000, 2000000, false, + rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_ST); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling WLAN IO timeout= %X\n", val32); + return ret; + } + + rtw89_write32_set(rtwdev, R_BE_WLLPS_CTRL, B_BE_FORCE_LEAVE_LPS); + + ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_ON, + 1000, 2000000, false, + rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling MAC STS timeout= %X\n", val32); + return ret; + } + + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + + ret = read_poll_timeout(rtw89_read32_mask, val32, val32 == MAC_AX_MAC_OFF, + 1000, 2000000, false, + rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC); + if (ret) { + rtw89_err(rtwdev, "[ERR]Polling MAC state timeout= %X\n", val32); + return ret; + } + + rtw89_write32_clr(rtwdev, R_BE_WLLPS_CTRL, B_BE_FORCE_LEAVE_LPS); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON); + rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS); + } return 0; } @@ -439,7 +608,8 @@ static void rtw89_mac_disable_cpu_be(struct rtw89_dev *rtwdev) val32 &= B_BE_RUN_ENV_MASK; rtw89_write32(rtwdev, R_BE_WCPU_FW_CTRL, val32); - rtw89_write32_set(rtwdev, R_BE_DCPU_PLATFORM_ENABLE, B_BE_DCPU_PLATFORM_EN); + if (rtwdev->chip->chip_id == RTL8922A) + rtw89_write32_set(rtwdev, R_BE_DCPU_PLATFORM_ENABLE, B_BE_DCPU_PLATFORM_EN); rtw89_write32(rtwdev, R_BE_UDM0, 0); rtw89_write32(rtwdev, R_BE_HALT_C2H, 0); @@ -585,31 +755,125 @@ static int rtw89_fwdl_check_path_ready_be(struct rtw89_dev *rtwdev, static int dmac_func_en_be(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->chip_id == RTL8922A) + return 0; + + rtw89_write32_set(rtwdev, R_BE_DMAC_FUNC_EN, + B_BE_MAC_FUNC_EN | B_BE_DMAC_FUNC_EN | + B_BE_MPDU_PROC_EN | B_BE_WD_RLS_EN | + B_BE_DLE_WDE_EN | B_BE_TXPKT_CTRL_EN | + B_BE_STA_SCH_EN | B_BE_DLE_PLE_EN | + B_BE_PKT_BUF_EN | B_BE_DMAC_TBL_EN | + B_BE_PKT_IN_EN | B_BE_DLE_CPUIO_EN | + B_BE_DISPATCHER_EN | B_BE_BBRPT_EN | + B_BE_MAC_SEC_EN | B_BE_H_AXIDMA_EN | + B_BE_DMAC_MLO_EN | B_BE_PLRLS_EN | + B_BE_P_AXIDMA_EN | B_BE_DLE_DATACPUIO_EN); + + return 0; +} + +static int cmac_share_func_en_be(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->chip_id == RTL8922A) + return 0; + + rtw89_write32_set(rtwdev, R_BE_CMAC_SHARE_FUNC_EN, + B_BE_CMAC_SHARE_EN | B_BE_RESPBA_EN | + B_BE_ADDRSRCH_EN | B_BE_BTCOEX_EN); + + return 0; +} + +static int cmac_pwr_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) +{ + if (mac_idx > RTW89_MAC_1) + return -EINVAL; + + if (mac_idx == RTW89_MAC_0) { + if (en == test_bit(RTW89_FLAG_CMAC0_PWR, rtwdev->flags)) + return 0; + + if (en) { + rtw89_write32_set(rtwdev, R_BE_AFE_CTRL1, + B_BE_R_SYM_WLCMAC0_ALL_EN); + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_R_SYM_ISO_CMAC02PP); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_CMAC0_FEN); + + set_bit(RTW89_FLAG_CMAC0_PWR, rtwdev->flags); + } else { + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_CMAC0_FEN); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_R_SYM_ISO_CMAC02PP); + rtw89_write32_clr(rtwdev, R_BE_AFE_CTRL1, + B_BE_R_SYM_WLCMAC0_ALL_EN); + + clear_bit(RTW89_FLAG_CMAC0_PWR, rtwdev->flags); + } + } else { + if (en == test_bit(RTW89_FLAG_CMAC1_PWR, rtwdev->flags)) + return 0; + + if (en) { + rtw89_write32_set(rtwdev, R_BE_AFE_CTRL1, + B_BE_R_SYM_WLCMAC1_ALL_EN); + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_R_SYM_ISO_CMAC12PP); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_CMAC1_FEN); + + set_bit(RTW89_FLAG_CMAC1_PWR, rtwdev->flags); + } else { + rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_CMAC1_FEN); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_R_SYM_ISO_CMAC12PP); + rtw89_write32_clr(rtwdev, R_BE_AFE_CTRL1, + B_BE_R_SYM_WLCMAC1_ALL_EN); + + clear_bit(RTW89_FLAG_CMAC1_PWR, rtwdev->flags); + } + } + return 0; } static int cmac_func_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) { + enum rtw89_flags pwr_flag, func_flag; u32 reg; if (mac_idx > RTW89_MAC_1) return -EINVAL; - if (mac_idx == RTW89_MAC_0) + if (mac_idx == RTW89_MAC_0) { + pwr_flag = RTW89_FLAG_CMAC0_PWR; + func_flag = RTW89_FLAG_CMAC0_FUNC; + } else { + pwr_flag = RTW89_FLAG_CMAC1_PWR; + func_flag = RTW89_FLAG_CMAC1_FUNC; + } + + if (!test_bit(pwr_flag, rtwdev->flags)) { + rtw89_warn(rtwdev, "CMAC %u power cut did not release\n", mac_idx); return 0; + } if (en) { - rtw89_write32_set(rtwdev, R_BE_AFE_CTRL1, B_BE_AFE_CTRL1_SET); - rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL_EXTEND, B_BE_R_SYM_ISO_CMAC12PP); - rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_CMAC1_FEN); - reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CK_EN, mac_idx); rtw89_write32_set(rtwdev, reg, B_BE_CK_EN_SET); reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx); rtw89_write32_set(rtwdev, reg, B_BE_CMAC_FUNC_EN_SET); - set_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); + set_bit(func_flag, rtwdev->flags); } else { reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx); rtw89_write32_clr(rtwdev, reg, B_BE_CMAC_FUNC_EN_SET); @@ -617,11 +881,7 @@ static int cmac_func_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CK_EN, mac_idx); rtw89_write32_clr(rtwdev, reg, B_BE_CK_EN_SET); - rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_CMAC1_FEN); - rtw89_write32_set(rtwdev, R_BE_SYS_ISO_CTRL_EXTEND, B_BE_R_SYM_ISO_CMAC12PP); - rtw89_write32_clr(rtwdev, R_BE_AFE_CTRL1, B_BE_AFE_CTRL1_SET); - - clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); + clear_bit(func_flag, rtwdev->flags); } return 0; @@ -640,6 +900,14 @@ static int sys_init_be(struct rtw89_dev *rtwdev) if (ret) return ret; + ret = cmac_share_func_en_be(rtwdev); + if (ret) + return ret; + + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_0, true); + if (ret) + return ret; + ret = cmac_func_en_be(rtwdev, RTW89_MAC_0, true); if (ret) return ret; @@ -651,11 +919,53 @@ static int sys_init_be(struct rtw89_dev *rtwdev) return ret; } +static int mac_func_en_be(struct rtw89_dev *rtwdev) +{ + u32 val; + int ret; + + ret = dmac_func_en_be(rtwdev); + if (ret) + return ret; + + ret = cmac_share_func_en_be(rtwdev); + if (ret) + return ret; + + val = rtw89_read32(rtwdev, R_BE_FEN_RST_ENABLE); + if (val & B_BE_CMAC0_FEN) { + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_0, true); + if (ret) + return ret; + + ret = cmac_func_en_be(rtwdev, RTW89_MAC_0, true); + if (ret) + return ret; + } + + if (val & B_BE_CMAC1_FEN) { + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_1, true); + if (ret) + return ret; + + ret = cmac_func_en_be(rtwdev, RTW89_MAC_1, true); + if (ret) + return ret; + } + + return 0; +} + static int sta_sch_init_be(struct rtw89_dev *rtwdev) { u32 p_val; int ret; + if (rtwdev->chip->chip_id == RTL8922D) { + rtw89_write32_set(rtwdev, R_BE_SS_LITE_TXL_MACID, B_BE_RPT_OTHER_BAND_EN); + return 0; + } + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); if (ret) return ret; @@ -685,14 +995,16 @@ static int mpdu_proc_init_be(struct rtw89_dev *rtwdev) return ret; rtw89_write32_set(rtwdev, R_BE_MPDU_PROC, B_BE_APPEND_FCS); - rtw89_write32(rtwdev, R_BE_CUT_AMSDU_CTRL, TRXCFG_MPDU_PROC_CUT_CTRL); + rtw89_write32(rtwdev, R_BE_CUT_AMSDU_CTRL, TRXCFG_MPDU_PROC_CUT_CTRL | + B_BE_CA_CHK_ADDRCAM_EN); val32 = rtw89_read32(rtwdev, R_BE_HDR_SHCUT_SETTING); val32 |= (B_BE_TX_HW_SEQ_EN | B_BE_TX_HW_ACK_POLICY_EN | B_BE_TX_MAC_MPDU_PROC_EN); val32 &= ~B_BE_TX_ADDR_MLD_TO_LIK; rtw89_write32_set(rtwdev, R_BE_HDR_SHCUT_SETTING, val32); - rtw89_write32(rtwdev, R_BE_RX_HDRTRNS, TRXCFG_MPDU_PROC_RX_HDR_CONV); + rtw89_write32(rtwdev, R_BE_RX_HDRTRNS, TRXCFG_MPDU_PROC_RX_HDR_CONV | + B_BE_HC_ADDR_HIT_EN); val32 = rtw89_read32(rtwdev, R_BE_DISP_FWD_WLAN_0); val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_0_DATA_MASK); @@ -728,7 +1040,10 @@ static int sec_eng_init_be(struct rtw89_dev *rtwdev) static int txpktctrl_init_be(struct rtw89_dev *rtwdev) { + struct rtw89_mac_info *mac = &rtwdev->mac; struct rtw89_mac_dle_rsvd_qt_cfg qt_cfg; + const struct rtw89_dle_input *dle_input; + u32 mpdu_info_b1_ofst; u32 val32; int ret; @@ -739,9 +1054,16 @@ static int txpktctrl_init_be(struct rtw89_dev *rtwdev) return ret; } + dle_input = mac->dle_info.dle_input; + if (dle_input) + mpdu_info_b1_ofst = DIV_ROUND_UP(dle_input->mpdu_info_tbl_b0, + BIT(MPDU_INFO_TBL_FACTOR)); + else + mpdu_info_b1_ofst = MPDU_INFO_B1_OFST; + val32 = rtw89_read32(rtwdev, R_BE_TXPKTCTL_MPDUINFO_CFG); val32 = u32_replace_bits(val32, qt_cfg.pktid, B_BE_MPDUINFO_PKTID_MASK); - val32 = u32_replace_bits(val32, MPDU_INFO_B1_OFST, B_BE_MPDUINFO_B1_BADDR_MASK); + val32 = u32_replace_bits(val32, mpdu_info_b1_ofst, B_BE_MPDUINFO_B1_BADDR_MASK); val32 |= B_BE_MPDUINFO_FEN; rtw89_write32(rtwdev, R_BE_TXPKTCTL_MPDUINFO_CFG, val32); @@ -750,7 +1072,9 @@ static int txpktctrl_init_be(struct rtw89_dev *rtwdev) static int mlo_init_be(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val32; + u32 reg; int ret; val32 = rtw89_read32(rtwdev, R_BE_MLO_INIT_CTL); @@ -766,7 +1090,12 @@ static int mlo_init_be(struct rtw89_dev *rtwdev) if (ret) rtw89_err(rtwdev, "[MLO]%s: MLO init polling timeout\n", __func__); - rtw89_write32_set(rtwdev, R_BE_SS_CTRL, B_BE_MLO_HW_CHGLINK_EN); + if (chip->chip_id == RTL8922A) + reg = R_BE_SS_CTRL; + else + reg = R_BE_SS_CTRL_V1; + + rtw89_write32_set(rtwdev, reg, B_BE_MLO_HW_CHGLINK_EN); rtw89_write32_set(rtwdev, R_BE_CMAC_SHARE_ACQCHK_CFG_0, B_BE_R_MACID_ACQ_CHK_EN); return ret; @@ -829,6 +1158,7 @@ static int dmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) static int scheduler_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val32; u32 reg; int ret; @@ -837,6 +1167,11 @@ static int scheduler_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) if (ret) return ret; + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_SCH_EXT_CTRL, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_CWCNT_PLUS_MODE); + } + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_HE_CTN_CHK_CCA_NAV, mac_idx); val32 = B_BE_HE_CTN_CHK_CCA_P20 | B_BE_HE_CTN_CHK_EDCCA_P20 | B_BE_HE_CTN_CHK_CCA_BITMAP | B_BE_HE_CTN_CHK_EDCCA_BITMAP | @@ -870,6 +1205,11 @@ static int scheduler_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write32_mask(rtwdev, reg, B_BE_BCNQ_CW_MASK, 0x32); rtw89_write32_mask(rtwdev, reg, B_BE_BCNQ_AIFS_MASK, BCN_IFS_25US); + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_SCH_EDCA_RST_CFG, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_TX_NAV_RST_EDCA_EN); + } + return 0; } @@ -985,6 +1325,9 @@ static int nav_ctrl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write32(rtwdev, reg, val32); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_SPECIAL_TX_SETTING, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_BMC_NAV_PROTECT); + return 0; } @@ -1008,14 +1351,22 @@ static int spatial_reuse_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) static int tmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 reg; reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TB_PPDU_CTRL, mac_idx); rtw89_write32_clr(rtwdev, reg, B_BE_QOSNULL_UPD_MUEDCA_EN); - reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMTX_TCR_BE_4, mac_idx); - rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK, 0x12); - rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_2XLTF_ZLD_USTIMER_MASK, 0xe); + if (chip->chip_id == RTL8922A) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMTX_TCR_BE_4, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK, 0x12); + rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_2XLTF_ZLD_USTIMER_MASK, 0xe); + } + + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_COMMON_PHYINTF_CTRL_0, mac_idx); + rtw89_write32_clr(rtwdev, reg, CLEAR_DTOP_DIS); + } return 0; } @@ -1040,6 +1391,15 @@ static int trxptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) val32 &= ~B_BE_MACLBK_EN; rtw89_write32(rtwdev, reg, val32); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_PHYINTF_EN); + + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_PLCP_EXT_OPTION_2, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_PLCP_PHASE_B_CRC_CHK_EN | + B_BE_PLCP_PHASE_A_CRC_CHK_EN); + } + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_0, mac_idx); val32 = rtw89_read32(rtwdev, reg); val32 = u32_replace_bits(val32, WMAC_SPEC_SIFS_CCK, @@ -1109,6 +1469,7 @@ static int rst_bacam_be(struct rtw89_dev *rtwdev) static int rmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 rx_min_qta, rx_max_len, rx_max_pg; u16 val16; u32 reg; @@ -1152,6 +1513,17 @@ static int rmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_PLCP_EXT_OPTION_1, mac_idx); rtw89_write16_set(rtwdev, reg, B_BE_PLCP_SU_PSDU_LEN_SRC); + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_BSR_UPD_CTRL, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_QSIZE_RULE); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RXGCK_CTRL, mac_idx); + rtw89_write16_mask(rtwdev, reg, B_BE_RXGCK_GCK_RATE_LIMIT_MASK, RX_GCK_LEGACY); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PLCP_HDR_FLTR, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_DIS_CHK_MIN_LEN); + } + return 0; } @@ -1175,7 +1547,7 @@ static int resp_pktctl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RESP_CSI_RESERVED_PAGE, mac_idx); rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_START_PAGE_MASK, qt_cfg.pktid); - rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_PAGE_NUM_MASK, qt_cfg.pg_num); + rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_PAGE_NUM_MASK, qt_cfg.pg_num + 1); return 0; } @@ -1210,6 +1582,7 @@ static int cmac_com_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) static int ptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val32; u8 val8; u32 reg; @@ -1224,8 +1597,9 @@ static int ptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) val32 = rtw89_read32(rtwdev, reg); val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_1K, B_BE_HW_CTS2SELF_PKT_LEN_TH_MASK); - val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_SEC_256B, - B_BE_HW_CTS2SELF_PKT_LEN_TH_TWW_MASK); + if (chip->chip_id == RTL8922A) + val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_SEC_256B, + B_BE_HW_CTS2SELF_PKT_LEN_TH_TWW_MASK); val32 |= B_BE_HW_CTS2SELF_EN; rtw89_write32(rtwdev, reg, val32); @@ -1246,7 +1620,46 @@ static int ptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write8(rtwdev, reg, val8); reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AMPDU_AGG_LIMIT, mac_idx); - rtw89_write32_mask(rtwdev, reg, B_BE_AMPDU_MAX_TIME_MASK, AMPDU_MAX_TIME); + if (chip->chip_id == RTL8922A) + val32 = AMPDU_MAX_TIME; + else + val32 = AMPDU_MAX_TIME_V1; + rtw89_write32_mask(rtwdev, reg, B_BE_AMPDU_MAX_TIME_MASK, val32); + + if (chip->chip_id == RTL8922D) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AGG_BK_0, mac_idx); + rtw89_write32_clr(rtwdev, reg, B_BE_WDBK_CFG | B_BE_EN_RTY_BK | + B_BE_EN_RTY_BK_COD); + + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AMPDU_AGG_LIMIT, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_BE_MAX_AGG_NUM_MASK, + MAX_TX_AMPDU_NUM_V1 - 1); + } + + if (rtw89_mac_chk_preload_allow(rtwdev)) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AGG_BK_0, mac_idx); + rtw89_write32_set(rtwdev, reg, B_BE_PRELD_MGQ0_EN | + B_BE_PRELD_HIQ_P4_EN | + B_BE_PRELD_HIQ_P3_EN | + B_BE_PRELD_HIQ_P2_EN | + B_BE_PRELD_HIQ_P1_EN | + B_BE_PRELD_HIQ_P0MB15_EN | + B_BE_PRELD_HIQ_P0MB14_EN | + B_BE_PRELD_HIQ_P0MB13_EN | + B_BE_PRELD_HIQ_P0MB12_EN | + B_BE_PRELD_HIQ_P0MB11_EN | + B_BE_PRELD_HIQ_P0MB10_EN | + B_BE_PRELD_HIQ_P0MB9_EN | + B_BE_PRELD_HIQ_P0MB8_EN | + B_BE_PRELD_HIQ_P0MB7_EN | + B_BE_PRELD_HIQ_P0MB6_EN | + B_BE_PRELD_HIQ_P0MB5_EN | + B_BE_PRELD_HIQ_P0MB4_EN | + B_BE_PRELD_HIQ_P0MB3_EN | + B_BE_PRELD_HIQ_P0MB2_EN | + B_BE_PRELD_HIQ_P0MB1_EN | + B_BE_PRELD_HIQ_P0_EN); + } return 0; } @@ -1533,22 +1946,22 @@ static int dle_quota_change_be(struct rtw89_dev *rtwdev, bool band1_en) static int preload_init_be(struct rtw89_dev *rtwdev, u8 mac_idx, enum rtw89_qta_mode mode) { + const struct rtw89_chip_info *chip = rtwdev->chip; u32 max_preld_size, min_rsvd_size; + u8 preld_acq, preld_miscq; u32 val32; u32 reg; + if (!(chip->chip_id == RTL8922A || rtw89_mac_chk_preload_allow(rtwdev))) + return 0; + max_preld_size = mac_idx == RTW89_MAC_0 ? PRELD_B0_ENT_NUM : PRELD_B1_ENT_NUM; + if (chip->chip_id == RTL8922D) + max_preld_size = PRELD_B01_ENT_NUM_8922D; max_preld_size *= PRELD_AMSDU_SIZE; + min_rsvd_size = PRELD_NEXT_MIN_SIZE; - reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG0 : - R_BE_TXPKTCTL_B1_PRELD_CFG0; - val32 = rtw89_read32(rtwdev, reg); - val32 = u32_replace_bits(val32, max_preld_size, B_BE_B0_PRELD_USEMAXSZ_MASK); - val32 |= B_BE_B0_PRELD_FEN; - rtw89_write32(rtwdev, reg, val32); - - min_rsvd_size = PRELD_AMSDU_SIZE; reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG1 : R_BE_TXPKTCTL_B1_PRELD_CFG1; val32 = rtw89_read32(rtwdev, reg); @@ -1556,6 +1969,24 @@ static int preload_init_be(struct rtw89_dev *rtwdev, u8 mac_idx, val32 = u32_replace_bits(val32, min_rsvd_size, B_BE_B0_PRELD_NXT_RSVMINSZ_MASK); rtw89_write32(rtwdev, reg, val32); + reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG0 : + R_BE_TXPKTCTL_B1_PRELD_CFG0; + if (chip->chip_id == RTL8922D) { + preld_acq = PRELD_ACQ_ENT_NUM_8922D; + preld_miscq = PRELD_MISCQ_ENT_NUM_8922D; + } else { + preld_acq = mac_idx == RTW89_MAC_0 ? PRELD_B0_ACQ_ENT_NUM_8922A : + PRELD_B1_ACQ_ENT_NUM_8922A; + preld_miscq = PRELD_MISCQ_ENT_NUM_8922A; + } + + val32 = rtw89_read32(rtwdev, reg); + val32 = u32_replace_bits(val32, preld_acq, B_BE_B0_PRELD_CAM_G0ENTNUM_MASK); + val32 = u32_replace_bits(val32, preld_miscq, B_BE_B0_PRELD_CAM_G1ENTNUM_MASK); + val32 = u32_replace_bits(val32, max_preld_size, B_BE_B0_PRELD_USEMAXSZ_MASK); + val32 |= B_BE_B0_PRELD_FEN; + rtw89_write32(rtwdev, reg, val32); + return 0; } @@ -1588,6 +2019,10 @@ static int enable_imr_be(struct rtw89_dev *rtwdev, u8 mac_idx, else return -EINVAL; + if (chip->chip_id == RTL8922D) + rtw89_write32_mask(rtwdev, R_BE_NO_RX_ERR_CFG, + B_BE_NO_RX_ERR_TO_MASK, 0); + for (i = 0; i < table->n_regs; i++) { reg = &table->regs[i]; addr = rtw89_mac_reg_by_idx(rtwdev, reg->addr, mac_idx); @@ -1638,6 +2073,12 @@ static int band1_enable_be(struct rtw89_dev *rtwdev) return ret; } + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_1, true); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d pwr en %d\n", RTW89_MAC_1, ret); + return ret; + } + ret = cmac_func_en_be(rtwdev, RTW89_MAC_1, true); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d func en %d\n", RTW89_MAC_1, ret); @@ -1681,6 +2122,12 @@ static int band1_disable_be(struct rtw89_dev *rtwdev) return ret; } + ret = cmac_pwr_en_be(rtwdev, RTW89_MAC_1, false); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d pwr dis %d\n", RTW89_MAC_1, ret); + return ret; + } + ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode, false); if (ret) { rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret); @@ -1731,26 +2178,40 @@ static int dbcc_enable_be(struct rtw89_dev *rtwdev, bool enable) static int set_host_rpr_be(struct rtw89_dev *rtwdev) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 val32; u32 mode; u32 fltr; + u32 qid; bool poh; poh = is_qta_poh(rtwdev); if (poh) { mode = RTW89_RPR_MODE_POH; - fltr = S_BE_WDRLS_FLTR_TXOK | S_BE_WDRLS_FLTR_RTYLMT | - S_BE_WDRLS_FLTR_LIFTIM | S_BE_WDRLS_FLTR_MACID; + qid = WDRLS_DEST_QID_POH; } else { mode = RTW89_RPR_MODE_STF; fltr = 0; + qid = WDRLS_DEST_QID_STF; + } + + if (chip_id == RTL8922A) { + fltr = S_BE_WDRLS_FLTR_TXOK | S_BE_WDRLS_FLTR_RTYLMT | + S_BE_WDRLS_FLTR_LIFTIM | S_BE_WDRLS_FLTR_MACID; + } else { + fltr = S_BE_WDRLS_FLTR_TXOK_V1 | S_BE_WDRLS_FLTR_RTYLMT_V1 | + S_BE_WDRLS_FLTR_LIFTIM_V1 | S_BE_WDRLS_FLTR_MACID_V1; } rtw89_write32_mask(rtwdev, R_BE_WDRLS_CFG, B_BE_WDRLS_MODE_MASK, mode); + rtw89_write32_mask(rtwdev, R_BE_RLSRPT0_CFG0, B_BE_RLSRPT0_QID_MASK, qid); val32 = rtw89_read32(rtwdev, R_BE_RLSRPT0_CFG1); - val32 = u32_replace_bits(val32, fltr, B_BE_RLSRPT0_FLTR_MAP_MASK); + if (chip_id == RTL8922A) + val32 = u32_replace_bits(val32, fltr, B_BE_RLSRPT0_FLTR_MAP_MASK); + else + val32 = u32_replace_bits(val32, fltr, B_BE_RLSRPT0_FLTR_MAP_V1_MASK); val32 = u32_replace_bits(val32, 30, B_BE_RLSRPT0_AGGNUM_MASK); val32 = u32_replace_bits(val32, 255, B_BE_RLSRPT0_TO_MASK); rtw89_write32(rtwdev, R_BE_RLSRPT0_CFG1, val32); @@ -1863,12 +2324,65 @@ int rtw89_mac_cfg_gnt_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_mac_cfg_gnt_v2); +int rtw89_mac_cfg_gnt_v3(struct rtw89_dev *rtwdev, + const struct rtw89_mac_ax_coex_gnt *gnt_cfg) +{ + u32 val = 0; + + if (gnt_cfg->band[0].gnt_bt) + val |= B_BE_PTA_GNT_BT0_BB_VAL | B_BE_PTA_GNT_BT0_RX_BB0_VAL | + B_BE_PTA_GNT_BT0_TX_BB0_VAL; + + if (gnt_cfg->band[0].gnt_bt_sw_en) + val |= B_BE_PTA_GNT_BT0_BB_SWCTRL | B_BE_PTA_GNT_BT0_RX_BB0_SWCTRL | + B_BE_PTA_GNT_BT0_TX_BB0_SWCTRL; + + if (gnt_cfg->band[0].gnt_wl) + val |= B_BE_PTA_GNT_WL_BB0_VAL; + + if (gnt_cfg->band[0].gnt_wl_sw_en) + val |= B_BE_PTA_GNT_WL_BB0_SWCTRL; + + if (gnt_cfg->band[1].gnt_bt) + val |= B_BE_PTA_GNT_BT0_BB_VAL | B_BE_PTA_GNT_BT0_RX_BB1_VAL | + B_BE_PTA_GNT_BT0_TX_BB1_VAL; + + if (gnt_cfg->band[1].gnt_bt_sw_en) + val |= B_BE_PTA_GNT_BT0_BB_SWCTRL | B_BE_PTA_GNT_BT0_RX_BB1_SWCTRL | + B_BE_PTA_GNT_BT0_TX_BB1_SWCTRL; + + if (gnt_cfg->band[1].gnt_wl) + val |= B_BE_PTA_GNT_WL_BB1_VAL; + + if (gnt_cfg->band[1].gnt_wl_sw_en) + val |= B_BE_PTA_GNT_WL_BB1_SWCTRL; + + if (gnt_cfg->bt[0].wlan_act_en) + val |= B_BE_PTA_WL_ACT0_SWCTRL | B_BE_PTA_WL_ACT_RX_BT0_SWCTRL | + B_BE_PTA_WL_ACT_TX_BT0_SWCTRL; + if (gnt_cfg->bt[0].wlan_act) + val |= B_BE_PTA_WL_ACT0_VAL | B_BE_PTA_WL_ACT_RX_BT0_VAL | + B_BE_PTA_WL_ACT_TX_BT0_VAL; + if (gnt_cfg->bt[1].wlan_act_en) + val |= B_BE_PTA_WL_ACT1_SWCTRL | B_BE_PTA_WL_ACT_RX_BT1_SWCTRL | + B_BE_PTA_WL_ACT_TX_BT1_SWCTRL; + if (gnt_cfg->bt[1].wlan_act) + val |= B_BE_PTA_WL_ACT1_VAL | B_BE_PTA_WL_ACT_RX_BT1_VAL | + B_BE_PTA_WL_ACT_TX_BT1_VAL; + + rtw89_write32(rtwdev, R_BE_PTA_GNT_SW_CTRL, val); + + return 0; +} +EXPORT_SYMBOL(rtw89_mac_cfg_gnt_v3); + int rtw89_mac_cfg_ctrl_path_v2(struct rtw89_dev *rtwdev, bool wl) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_mac_ax_gnt *g = dm->gnt.band; struct rtw89_mac_ax_wl_act *gbt = dm->gnt.bt; + const struct rtw89_chip_info *chip = rtwdev->chip; int i; if (wl) @@ -1883,7 +2397,11 @@ int rtw89_mac_cfg_ctrl_path_v2(struct rtw89_dev *rtwdev, bool wl) gbt[i].wlan_act_en = 0; } - return rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); + if (chip->chip_id == RTL8922A) + return rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); + else + return rtw89_mac_cfg_gnt_v3(rtwdev, &dm->gnt); + } EXPORT_SYMBOL(rtw89_mac_cfg_ctrl_path_v2); @@ -2012,6 +2530,65 @@ void rtw89_mac_cfg_phy_rpt_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) EXPORT_SYMBOL(rtw89_mac_cfg_phy_rpt_be); static +void rtw89_mac_set_edcca_mode_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool normal) +{ + u16 resp_ack, resp_rts, resp_rts_punc, resp_normal, resp_normal_punc; + + if (rtwdev->chip->chip_id == RTL8922A) + return; + + resp_ack = RESP_ACK_CFG_BE; + resp_rts = RESP_RTS_CFG_BE; + resp_rts_punc = RESP_RTS_PUNC_CFG_BE; + resp_normal = RESP_NORMAL_CFG_BE; + resp_normal_punc = RESP_NORMAL_PUNC_CFG_BE; + + if (normal) { + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_LEGACY, + resp_ack, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_HE, + resp_ack, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC, + resp_ack, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_RTS_RESP_LEGACY, + resp_rts, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_RTS_RESP_LEGACY_PUNC, + resp_rts_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_MURTS_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_MURTS_RESP_LEGACY_PUNC, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_HE, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_EHT_LEG_PUNC, + resp_normal_punc, mac_idx); + } else { + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_HE, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_RTS_RESP_LEGACY, + resp_rts, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_RTS_RESP_LEGACY_PUNC, + resp_rts_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_MURTS_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_RX_MURTS_RESP_LEGACY_PUNC, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_LEGACY, + resp_normal, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_HE, + resp_normal_punc, mac_idx); + rtw89_write16_idx(rtwdev, R_BE_WMAC_OTHERS_RESP_EHT_LEG_PUNC, + resp_normal_punc, mac_idx); + } +} + +static int rtw89_mac_cfg_ppdu_status_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) { u32 reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PPDU_STAT, mac_idx); @@ -2601,6 +3178,9 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .check_mac_en = rtw89_mac_check_mac_en_be, .sys_init = sys_init_be, .trx_init = trx_init_be, + .preload_init = preload_init_be, + .err_imr_ctrl = err_imr_ctrl_be, + .mac_func_en = mac_func_en_be, .hci_func_en = rtw89_mac_hci_func_en_be, .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_be, .dle_func_en = dle_func_en_be, @@ -2610,6 +3190,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .typ_fltr_opt = rtw89_mac_typ_fltr_opt_be, .cfg_ppdu_status = rtw89_mac_cfg_ppdu_status_be, .cfg_phy_rpt = rtw89_mac_cfg_phy_rpt_be, + .set_edcca_mode = rtw89_mac_set_edcca_mode_be, .dle_mix_cfg = dle_mix_cfg_be, .chk_dle_rdy = chk_dle_rdy_be, @@ -2623,6 +3204,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .set_cpuio = set_cpuio_be, .dle_quota_change = dle_quota_change_be, + .reset_pwr_state = rtw89_mac_reset_pwr_state_be, .disable_cpu = rtw89_mac_disable_cpu_be, .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, .fwdl_get_status = fwdl_get_status_be, @@ -2632,6 +3214,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_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, + .efuse_read_ecv = rtw89_efuse_read_ecv_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 a66fcdb0293b..093960d7279f 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -604,11 +604,16 @@ static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev, void *rpp) info->parse_rpp(rtwdev, rpp, &rpp_info); - if (rpp_info.txch == RTW89_TXCH_CH12) { + if (unlikely(rpp_info.txch == RTW89_TXCH_CH12)) { rtw89_warn(rtwdev, "should no fwcmd release report\n"); return; } + if (unlikely(rpp_info.seq >= RTW89_PCI_TXWD_NUM_MAX)) { + rtw89_warn(rtwdev, "invalid seq %d\n", rpp_info.seq); + return; + } + tx_ring = &rtwpci->tx.rings[rpp_info.txch]; wd_ring = &tx_ring->wd_ring; txwd = &wd_ring->pages[rpp_info.seq]; diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 16dfb0e79d77..b0081b694046 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -55,6 +55,8 @@ #define B_AX_CALIB_EN BIT(13) #define B_AX_DIV GENMASK(15, 14) #define RAC_SET_PPR_V1 0x31 +#define RAC_ANA41 0x41 +#define PHY_ERR_FLAG_EN BIT(6) #define R_AX_DBI_FLAG 0x1090 #define B_AX_DBI_RFLAG BIT(17) @@ -145,6 +147,11 @@ #define R_RAC_DIRECT_OFFSET_BE_LANE0_G2 0x3900 #define R_RAC_DIRECT_OFFSET_BE_LANE1_G2 0x3980 +#define RAC_DIRECT_OFFESET_L0_G1 0x3800 +#define RAC_DIRECT_OFFESET_L1_G1 0x3900 +#define RAC_DIRECT_OFFESET_L0_G2 0x3A00 +#define RAC_DIRECT_OFFESET_L1_G2 0x3B00 + #define RTW89_PCI_WR_RETRY_CNT 20 /* Interrupts */ @@ -296,6 +303,10 @@ #define B_BE_PCIE_EN_AUX_CLK BIT(0) #define R_BE_PCIE_PS_CTRL 0x3008 +#define B_BE_ASPM_L11_EN BIT(19) +#define B_BE_ASPM_L12_EN BIT(18) +#define B_BE_PCIPM_L11_EN BIT(17) +#define B_BE_PCIPM_L12_EN BIT(16) #define B_BE_RSM_L0S_EN BIT(8) #define B_BE_CMAC_EXIT_L1_EN BIT(7) #define B_BE_DMAC0_EXIT_L1_EN BIT(6) @@ -767,31 +778,6 @@ #define R_AX_WP_ADDR_H_SEL8_11 0x133C #define R_AX_WP_ADDR_H_SEL12_15 0x1340 -#define R_BE_HAXI_DMA_STOP1 0xB010 -#define B_BE_STOP_WPDMA BIT(31) -#define B_BE_STOP_CH14 BIT(14) -#define B_BE_STOP_CH13 BIT(13) -#define B_BE_STOP_CH12 BIT(12) -#define B_BE_STOP_CH11 BIT(11) -#define B_BE_STOP_CH10 BIT(10) -#define B_BE_STOP_CH9 BIT(9) -#define B_BE_STOP_CH8 BIT(8) -#define B_BE_STOP_CH7 BIT(7) -#define B_BE_STOP_CH6 BIT(6) -#define B_BE_STOP_CH5 BIT(5) -#define B_BE_STOP_CH4 BIT(4) -#define B_BE_STOP_CH3 BIT(3) -#define B_BE_STOP_CH2 BIT(2) -#define B_BE_STOP_CH1 BIT(1) -#define B_BE_STOP_CH0 BIT(0) -#define B_BE_TX_STOP1_MASK (B_BE_STOP_CH0 | B_BE_STOP_CH1 | \ - B_BE_STOP_CH2 | B_BE_STOP_CH3 | \ - B_BE_STOP_CH4 | B_BE_STOP_CH5 | \ - B_BE_STOP_CH6 | B_BE_STOP_CH7 | \ - B_BE_STOP_CH8 | B_BE_STOP_CH9 | \ - B_BE_STOP_CH10 | B_BE_STOP_CH11 | \ - B_BE_STOP_CH12) - #define R_BE_CH0_TXBD_NUM_V1 0xB030 #define R_BE_CH1_TXBD_NUM_V1 0xB032 #define R_BE_CH2_TXBD_NUM_V1 0xB034 @@ -974,6 +960,12 @@ #define R_BE_PCIE_CRPWM 0x30C4 #define R_BE_L1_2_CTRL_HCILDO 0x3110 +#define B_BE_PM_CLKREQ_EXT_RB BIT(11) +#define B_BE_PCIE_DIS_RTK_PRST_N_L1_2 BIT(10) +#define B_BE_PCIE_PRST_IN_L1_2_RB BIT(9) +#define B_BE_PCIE_PRST_SEL_RB_V1 BIT(8) +#define B_BE_PCIE_DIS_L2_CTRL_APHY_SUSB BIT(7) +#define B_BE_PCIE_DIS_L1_2_CTRL_APHY_SUSB BIT(6) #define B_BE_PCIE_DIS_L1_2_CTRL_HCILDO BIT(0) #define R_BE_PL1_DBG_INFO 0x3120 @@ -1023,9 +1015,11 @@ #define B_BE_PL1_SER_PL1_EN BIT(31) #define B_BE_PL1_IGNORE_HOT_RST BIT(30) #define B_BE_PL1_TIMER_UNIT_MASK GENMASK(19, 17) +#define PCIE_SER_TIMER_UNIT 0x2 #define B_BE_PL1_TIMER_CLEAR BIT(0) #define R_BE_REG_PL1_MASK 0x34B0 +#define B_BE_SER_LTSSM_UNSTABLE_MASK BIT(6) #define B_BE_SER_PCLKREQ_ACK_MASK BIT(5) #define B_BE_SER_PM_CLK_MASK BIT(4) #define B_BE_SER_LTSSM_IMR BIT(3) @@ -1055,6 +1049,18 @@ #define B_BE_CLR_CH2_IDX BIT(2) #define B_BE_CLR_CH1_IDX BIT(1) #define B_BE_CLR_CH0_IDX BIT(0) +#define B_BE_CLR_ALL_IDX_MASK (B_BE_CLR_CH0_IDX | B_BE_CLR_CH1_IDX | \ + B_BE_CLR_CH2_IDX | B_BE_CLR_CH3_IDX | \ + B_BE_CLR_CH4_IDX | B_BE_CLR_CH5_IDX | \ + B_BE_CLR_CH6_IDX | B_BE_CLR_CH7_IDX | \ + B_BE_CLR_CH8_IDX | B_BE_CLR_CH9_IDX | \ + B_BE_CLR_CH10_IDX | B_BE_CLR_CH11_IDX | \ + B_BE_CLR_CH12_IDX | B_BE_CLR_CH13_IDX | \ + B_BE_CLR_CH14_IDX) +#define B_BE_CLR_ALL_IDX_MASK_V1 (B_BE_CLR_CH0_IDX | B_BE_CLR_CH2_IDX | \ + B_BE_CLR_CH4_IDX | B_BE_CLR_CH6_IDX | \ + B_BE_CLR_CH8_IDX | B_BE_CLR_CH10_IDX | \ + B_BE_CLR_CH12_IDX) #define R_BE_RXBD_RWPTR_CLR1_V1 0xB018 #define B_BE_CLR_ROQ1_IDX_V1 BIT(5) diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index e4590879b800..33bdd3e66bf6 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -46,6 +46,14 @@ static void rtw89_pci_aspm_set_be(struct rtw89_dev *rtwdev, bool enable) static void rtw89_pci_l1ss_set_be(struct rtw89_dev *rtwdev, bool enable) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + struct rtw89_hal *hal = &rtwdev->hal; + + if (enable && chip_id == RTL8922D && hal->cid == RTL8922D_CID7090) + rtw89_write32_set(rtwdev, R_BE_PCIE_PS_CTRL, + B_BE_ASPM_L11_EN | B_BE_ASPM_L12_EN | + B_BE_PCIPM_L11_EN | B_BE_PCIPM_L12_EN); + if (enable) rtw89_write32_set(rtwdev, R_BE_PCIE_MIX_CFG, B_BE_L1SUB_ENABLE); @@ -154,7 +162,7 @@ static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev, rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val); - if (io_en == MAC_AX_PCIE_ENABLE) + if (io_en == MAC_AX_PCIE_ENABLE && rtwdev->chip->chip_id == RTL8922A) rtw89_write32_mask(rtwdev, R_BE_HAXI_MST_WDT_TIMEOUT_SEL_V1, B_BE_HAXI_MST_WDT_TIMEOUT_SEL_MASK, 4); } @@ -162,14 +170,15 @@ static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev, static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_pci_rx_ring *rx_ring; u32 val; - val = B_BE_CLR_CH0_IDX | B_BE_CLR_CH1_IDX | B_BE_CLR_CH2_IDX | - B_BE_CLR_CH3_IDX | B_BE_CLR_CH4_IDX | B_BE_CLR_CH5_IDX | - B_BE_CLR_CH6_IDX | B_BE_CLR_CH7_IDX | B_BE_CLR_CH8_IDX | - B_BE_CLR_CH9_IDX | B_BE_CLR_CH10_IDX | B_BE_CLR_CH11_IDX | - B_BE_CLR_CH12_IDX | B_BE_CLR_CH13_IDX | B_BE_CLR_CH14_IDX; + if (chip->chip_id == RTL8922A) + val = B_BE_CLR_ALL_IDX_MASK; + else + val = B_BE_CLR_ALL_IDX_MASK_V1; + rtw89_write32(rtwdev, R_BE_TXBD_RWPTR_CLR1, val); rtw89_write32(rtwdev, R_BE_RXBD_RWPTR_CLR1_V1, @@ -184,10 +193,13 @@ static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) static int rtw89_pci_poll_txdma_ch_idle_be(struct rtw89_dev *rtwdev) { + const struct rtw89_pci_info *info = rtwdev->pci_info; + u32 dma_busy1 = info->dma_busy1.addr; + u32 check = info->dma_busy1.mask; u32 val; - return read_poll_timeout(rtw89_read32, val, (val & DMA_BUSY1_CHECK_BE) == 0, - 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1); + return read_poll_timeout(rtw89_read32, val, (val & check) == 0, + 10, 1000, false, rtwdev, dma_busy1); } static int rtw89_pci_poll_rxdma_ch_idle_be(struct rtw89_dev *rtwdev) @@ -223,20 +235,24 @@ static int rtw89_pci_poll_dma_all_idle_be(struct rtw89_dev *rtwdev) static void rtw89_pci_mode_op_be(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_chip_info *chip = rtwdev->chip; u32 val32_init1, val32_rxapp, val32_exp; val32_init1 = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1); - val32_rxapp = rtw89_read32(rtwdev, R_BE_RX_APPEND_MODE); + if (chip->chip_id == RTL8922A) + val32_rxapp = rtw89_read32(rtwdev, R_BE_RX_APPEND_MODE); val32_exp = rtw89_read32(rtwdev, R_BE_HAXI_EXP_CTRL_V1); - if (info->rxbd_mode == MAC_AX_RXBD_PKT) { - val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_NORM, - B_BE_RXQ_RXBD_MODE_MASK); - } else if (info->rxbd_mode == MAC_AX_RXBD_SEP) { - val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_SEP, - B_BE_RXQ_RXBD_MODE_MASK); - val32_rxapp = u32_replace_bits(val32_rxapp, 0, - B_BE_APPEND_LEN_MASK); + if (chip->chip_id == RTL8922A) { + if (info->rxbd_mode == MAC_AX_RXBD_PKT) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_NORM, + B_BE_RXQ_RXBD_MODE_MASK); + } else if (info->rxbd_mode == MAC_AX_RXBD_SEP) { + val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_SEP, + B_BE_RXQ_RXBD_MODE_MASK); + val32_rxapp = u32_replace_bits(val32_rxapp, 0, + B_BE_APPEND_LEN_MASK); + } } val32_init1 = u32_replace_bits(val32_init1, info->tx_burst, @@ -251,7 +267,8 @@ static void rtw89_pci_mode_op_be(struct rtw89_dev *rtwdev) B_BE_CFG_WD_PERIOD_ACTIVE_MASK); rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val32_init1); - rtw89_write32(rtwdev, R_BE_RX_APPEND_MODE, val32_rxapp); + if (chip->chip_id == RTL8922A) + rtw89_write32(rtwdev, R_BE_RX_APPEND_MODE, val32_rxapp); rtw89_write32(rtwdev, R_BE_HAXI_EXP_CTRL_V1, val32_exp); } @@ -277,6 +294,10 @@ static void rtw89_pci_debounce_be(struct rtw89_dev *rtwdev) static void rtw89_pci_ldo_low_pwr_be(struct rtw89_dev *rtwdev) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + struct rtw89_hal *hal = &rtwdev->hal; + u32 clr; + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_PSUS_OFF_CAPC_EN); rtw89_write32_set(rtwdev, R_BE_SYS_PAGE_CLK_GATED, B_BE_SOP_OFFPOOBS_PC | B_BE_CPHY_AUXCLK_OP | @@ -284,7 +305,16 @@ static void rtw89_pci_ldo_low_pwr_be(struct rtw89_dev *rtwdev) rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN | B_BE_PCIE_DIS_L2_RTK_PERST | B_BE_PCIE_DIS_L2__CTRL_LDO_HCI); - rtw89_write32_clr(rtwdev, R_BE_L1_2_CTRL_HCILDO, B_BE_PCIE_DIS_L1_2_CTRL_HCILDO); + + if (chip_id == RTL8922D && hal->cid == RTL8922D_CID7090) + clr = B_BE_PCIE_DIS_L1_2_CTRL_HCILDO | + B_BE_PCIE_DIS_L1_2_CTRL_APHY_SUSB | + B_BE_PCIE_DIS_RTK_PRST_N_L1_2 | + B_BE_PCIE_DIS_L2_CTRL_APHY_SUSB; + else + clr = B_BE_PCIE_DIS_L1_2_CTRL_HCILDO; + + rtw89_write32_clr(rtwdev, R_BE_L1_2_CTRL_HCILDO, clr); } static void rtw89_pci_pcie_setting_be(struct rtw89_dev *rtwdev) @@ -300,11 +330,25 @@ static void rtw89_pci_pcie_setting_be(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL); rtw89_write32_set(rtwdev, R_BE_PCIE_LAT_CTRL, B_BE_SYM_AUX_CLK_SEL); + + if (chip->chip_id != RTL8922D) + return; + + rtw89_write32_set(rtwdev, R_BE_RSV_CTRL, B_BE_R_SYM_PRST_CPHY_RST); + rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_USUS_OFFCAPC_EN); } static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) { + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + struct rtw89_hal *hal = &rtwdev->hal; u32 val32; + int ret; + + if (chip_id == RTL8922D) + goto be2_chips; + else if (chip_id != RTL8922A) + return; rtw89_write32(rtwdev, R_BE_PL1_DBG_INFO, 0x0); rtw89_write32_set(rtwdev, R_BE_FWS1IMR, B_BE_PCIE_SER_TIMEOUT_INDIC_EN); @@ -315,10 +359,48 @@ static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev) val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR | B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK | B_BE_SER_PCLKREQ_ACK_MASK; rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32); + + return; + +be2_chips: + rtw89_write32_clr(rtwdev, R_BE_PCIE_SER_DBG, B_BE_PCIE_SER_FLUSH_RSTB); + rtw89_write32_set(rtwdev, R_BE_PCIE_SER_DBG, B_BE_PCIE_SER_FLUSH_RSTB); + + rtw89_write16_clr(rtwdev, RAC_DIRECT_OFFESET_L0_G1 + + RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN); + rtw89_write16_clr(rtwdev, RAC_DIRECT_OFFESET_L0_G2 + + RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN); + rtw89_write16_set(rtwdev, RAC_DIRECT_OFFESET_L0_G1 + + RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN); + rtw89_write16_set(rtwdev, RAC_DIRECT_OFFESET_L0_G2 + + RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN); + + val32 = rtw89_read32(rtwdev, R_BE_SER_PL1_CTRL); + val32 &= ~B_BE_PL1_SER_PL1_EN; + rtw89_write32(rtwdev, R_BE_SER_PL1_CTRL, val32); + + ret = read_poll_timeout_atomic(rtw89_read32, val32, !val32, + 1, 1000, false, rtwdev, R_BE_REG_PL1_ISR); + if (ret) + rtw89_warn(rtwdev, "[ERR] PCIE SER clear poll fail\n"); + + val32 = rtw89_read32(rtwdev, R_BE_REG_PL1_MASK); + val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR | + B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK | B_BE_SER_PCLKREQ_ACK_MASK | + B_BE_SER_LTSSM_UNSTABLE_MASK; + rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32); + + rtw89_write32_mask(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_TIMER_UNIT_MASK, + PCIE_SER_TIMER_UNIT); + rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); + + if (hal->cid == RTL8922D_CID7090) + rtw89_write32_set(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_SER_DETECT_EN); } static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool enable) { + const struct rtw89_pci_info *info = rtwdev->pci_info; u32 mask_all; u32 val; @@ -327,6 +409,9 @@ static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool enable) B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 | B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11; + /* mask out unsupported channels for certains chips */ + mask_all &= info->dma_stop1.mask; + val = rtw89_read32(rtwdev, R_BE_HAXI_DMA_STOP1); val |= B_BE_STOP_CH13 | B_BE_STOP_CH14; @@ -409,6 +494,7 @@ static int rtw89_pci_ops_mac_pre_deinit_be(struct rtw89_dev *rtwdev) int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) { u32 ctrl0, cfg0, cfg1, dec_ctrl, idle_ltcy, act_ltcy, dis_ltcy; + u32 ltr_idle_lat_ctrl, ltr_act_lat_ctrl; ctrl0 = rtw89_read32(rtwdev, R_BE_LTR_CTRL_0); if (rtw89_pci_ltr_is_err_reg_val(ctrl0)) @@ -451,8 +537,16 @@ int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en) cfg0 = u32_replace_bits(cfg0, 3, B_BE_LTR_IDX_IDLE_MASK); dec_ctrl = u32_replace_bits(dec_ctrl, 0, B_BE_LTR_IDX_DISABLE_V1_MASK); - rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1, 0x90039003); - rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1, 0x880b880b); + if (rtwdev->chip->chip_id == RTL8922A) { + ltr_idle_lat_ctrl = 0x90039003; + ltr_act_lat_ctrl = 0x880b880b; + } else { + ltr_idle_lat_ctrl = 0x90019001; + ltr_act_lat_ctrl = 0x88018801; + } + + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1, ltr_idle_lat_ctrl); + rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1, ltr_act_lat_ctrl); rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1, 0); rtw89_write32(rtwdev, R_BE_LTR_DECISION_CTRL_V1, dec_ctrl); rtw89_write32(rtwdev, R_BE_LTR_CFG_0, cfg0); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 9f418b1fb7ed..0b72d3dcf666 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -281,8 +281,7 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev, 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_ltf = mask->control[nl_band].he_ltf; - u8 he_gi = mask->control[nl_band].he_gi; + u8 ltf, gi; *fix_giltf_en = true; @@ -293,22 +292,31 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev, else *fix_giltf = RTW89_GILTF_2XHE08; - if (!(rtwsta_link->use_cfg_mask && link_sta->he_cap.has_he)) + if (!rtwsta_link->use_cfg_mask) return; - if (he_ltf == 2 && he_gi == 2) { + if (link_sta->eht_cap.has_eht) { + ltf = mask->control[nl_band].eht_ltf; + gi = mask->control[nl_band].eht_gi; + } else if (link_sta->he_cap.has_he) { + ltf = mask->control[nl_band].he_ltf; + gi = mask->control[nl_band].he_gi; + } else { + return; + } + + if (ltf == 2 && gi == 2) *fix_giltf = RTW89_GILTF_LGI_4XHE32; - } else if (he_ltf == 2 && he_gi == 0) { + else if (ltf == 2 && gi == 0) *fix_giltf = RTW89_GILTF_SGI_4XHE08; - } else if (he_ltf == 1 && he_gi == 1) { + else if (ltf == 1 && gi == 1) *fix_giltf = RTW89_GILTF_2XHE16; - } else if (he_ltf == 1 && he_gi == 0) { + else if (ltf == 1 && gi == 0) *fix_giltf = RTW89_GILTF_2XHE08; - } else if (he_ltf == 0 && he_gi == 1) { + else if (ltf == 0 && gi == 1) *fix_giltf = RTW89_GILTF_1XHE16; - } else if (he_ltf == 0 && he_gi == 0) { + else if (ltf == 0 && gi == 0) *fix_giltf = RTW89_GILTF_1XHE08; - } } static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, @@ -3808,13 +3816,22 @@ int rtw89_phy_rfk_pre_ntfy_and_wait(struct rtw89_dev *rtwdev, { int ret; - rtw89_phy_rfk_report_prep(rtwdev); + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY, &rtwdev->fw)) { + rtw89_phy_rfk_report_prep(rtwdev); + rtw89_fw_h2c_rf_pre_ntfy(rtwdev, phy_idx); + ret = rtw89_phy_rfk_report_wait(rtwdev, "PRE_NTFY", ms); + if (ret) + return ret; + } - ret = rtw89_fw_h2c_rf_pre_ntfy(rtwdev, phy_idx); - if (ret) - return ret; + if (RTW89_CHK_FW_FEATURE_GROUP(WITH_RFK_PRE_NOTIFY_MCC, &rtwdev->fw)) { + ret = rtw89_fw_h2c_rf_pre_ntfy_mcc(rtwdev, phy_idx); + if (ret) + return ret; + } + + return 0; - return rtw89_phy_rfk_report_wait(rtwdev, "PRE_NTFY", ms); } EXPORT_SYMBOL(rtw89_phy_rfk_pre_ntfy_and_wait); diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 3f69dd4361c3..abd8aee02b47 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -16,7 +16,7 @@ static int rtw89_fw_receive_lps_h2c_check(struct rtw89_dev *rtwdev, u8 macid) { - struct rtw89_mac_c2h_info c2h_info = {}; + struct rtw89_mac_c2h_info c2h_info = {.timeout = 5000}; u16 c2hreg_macid; u32 c2hreg_ret; int ret; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 5b4a459cf29c..efeb4507b1a9 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -149,6 +149,7 @@ #define R_AX_WLLPS_CTRL 0x0090 #define B_AX_LPSOP_ASWRM BIT(17) #define B_AX_LPSOP_DSWRM BIT(9) +#define B_AX_FORCE_LEAVE_LPS BIT(3) #define B_AX_DIS_WLBT_LPSEN_LOPC BIT(1) #define SW_LPS_OPTION 0x0001A0B2 @@ -313,13 +314,18 @@ #define R_AX_IC_PWR_STATE 0x03F0 #define B_AX_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16) #define B_AX_WLMAC_PWR_STE_MASK GENMASK(9, 8) +#define MAC_AX_MAC_OFF 0 +#define MAC_AX_MAC_ON 1 +#define MAC_AX_MAC_LPS 2 #define B_AX_UART_HCISYS_PWR_STE_MASK GENMASK(7, 6) #define B_AX_SDIO_HCISYS_PWR_STE_MASK GENMASK(5, 4) #define B_AX_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2) #define B_AX_PCIE_HCISYS_PWR_STE_MASK GENMASK(1, 0) #define R_AX_SPS_DIG_OFF_CTRL0 0x0400 +#define B_AX_R1_L1_MASK GENMASK(7, 6) #define B_AX_C3_L1_MASK GENMASK(5, 4) +#define B_AX_C2_L1_MASK GENMASK(3, 2) #define B_AX_C1_L1_MASK GENMASK(1, 0) #define R_AX_AFE_OFF_CTRL1 0x0444 @@ -603,6 +609,9 @@ #define R_AX_SER_DBG_INFO 0x8424 #define B_AX_L0_TO_L1_EVENT_MASK GENMASK(31, 28) +#define B_AX_SER_L1_COUNTER_MASK GENMASK(27, 24) +#define B_AX_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16) +#define B_AX_SER_L0_COUNTER_MASK GENMASK(7, 0) #define R_AX_DLE_EMPTY0 0x8430 #define B_AX_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) @@ -1958,7 +1967,9 @@ #define B_AX_B0_PRELD_FEN BIT(31) #define B_AX_B0_PRELD_USEMAXSZ_MASK GENMASK(25, 16) #define PRELD_B0_ENT_NUM 10 +#define PRELD_B01_ENT_NUM_8922D 2 #define PRELD_AMSDU_SIZE 52 +#define PRELD_NEXT_MIN_SIZE 255 #define B_AX_B0_PRELD_CAM_G1ENTNUM_MASK GENMASK(12, 8) #define B_AX_B0_PRELD_CAM_G0ENTNUM_MASK GENMASK(4, 0) @@ -2094,6 +2105,7 @@ #define B_AX_B1_ISR_ERR_USRCTL_REINIT BIT(0) #define R_AX_AFE_CTRL1 0x0024 +#define B_AX_CMAC_CLK_SEL BIT(21) #define B_AX_R_SYM_WLCMAC1_P4_PC_EN BIT(4) #define B_AX_R_SYM_WLCMAC1_P3_PC_EN BIT(3) @@ -2107,6 +2119,12 @@ #define B_AX_R_SYM_FEN_WLBBFUN_1 BIT(16) #define B_AX_R_SYM_ISO_CMAC12PP BIT(5) +#define R_AX_SYSON_FSM_MON 0x00A0 +#define B_AX_FSM_MON_SEL_MASK GENMASK(26, 24) +#define B_AX_DOP_ELDO BIT(23) +#define B_AX_FSM_MON_UPD BIT(15) +#define B_AX_FSM_PAR_MASK GENMASK(14, 0) + #define R_AX_CMAC_REG_START 0xC000 #define R_AX_CMAC_FUNC_EN 0xC000 @@ -3813,6 +3831,7 @@ #define B_BE_EN_WLON BIT(16) #define B_BE_APDM_HPDN BIT(15) #define B_BE_PSUS_OFF_CAPC_EN BIT(14) +#define B_BE_USUS_OFFCAPC_EN BIT(13) #define B_BE_AFSM_PCIE_SUS_EN BIT(12) #define B_BE_AFSM_WLSUS_EN BIT(11) #define B_BE_APFM_SWLPS BIT(10) @@ -3881,6 +3900,8 @@ #define B_BE_SYM_PADPDN_WL_RFC0_1P3 BIT(5) #define R_BE_RSV_CTRL 0x001C +#define B_BE_R_SYM_PRST_CPHY_RST BIT(25) +#define B_BE_R_SYM_PRST_PDN_EN BIT(24) #define B_BE_HR_BE_DBG GENMASK(23, 12) #define B_BE_R_SYM_DIS_PCIE_FLR BIT(9) #define B_BE_R_EN_HRST_PWRON BIT(8) @@ -3927,6 +3948,11 @@ #define B_BE_R_SYM_WLCMAC0_P2_PC_EN BIT(26) #define B_BE_R_SYM_WLCMAC0_P1_PC_EN BIT(25) #define B_BE_R_SYM_WLCMAC0_PC_EN BIT(24) +#define B_BE_R_SYM_WLCMAC0_ALL_EN (B_BE_R_SYM_WLCMAC0_PC_EN | \ + B_BE_R_SYM_WLCMAC0_P1_PC_EN | \ + B_BE_R_SYM_WLCMAC0_P2_PC_EN | \ + B_BE_R_SYM_WLCMAC0_P3_PC_EN | \ + B_BE_R_SYM_WLCMAC0_P4_PC_EN) #define B_BE_DATAMEM_PC3_EN BIT(23) #define B_BE_DATAMEM_PC2_EN BIT(22) #define B_BE_DATAMEM_PC1_EN BIT(21) @@ -3948,11 +3974,11 @@ #define B_BE_R_SYM_WLCMAC1_P2_PC_EN BIT(2) #define B_BE_R_SYM_WLCMAC1_P1_PC_EN BIT(1) #define B_BE_R_SYM_WLCMAC1_PC_EN BIT(0) -#define B_BE_AFE_CTRL1_SET (B_BE_R_SYM_WLCMAC1_PC_EN | \ - B_BE_R_SYM_WLCMAC1_P1_PC_EN | \ - B_BE_R_SYM_WLCMAC1_P2_PC_EN | \ - B_BE_R_SYM_WLCMAC1_P3_PC_EN | \ - B_BE_R_SYM_WLCMAC1_P4_PC_EN) +#define B_BE_R_SYM_WLCMAC1_ALL_EN (B_BE_R_SYM_WLCMAC1_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P1_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P2_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P3_PC_EN | \ + B_BE_R_SYM_WLCMAC1_P4_PC_EN) #define R_BE_EFUSE_CTRL 0x0030 #define B_BE_EF_MODE_SEL_MASK GENMASK(31, 30) @@ -4015,6 +4041,7 @@ #define R_BE_SYS_SDIO_CTRL 0x0070 #define B_BE_MCM_FLASH_EN BIT(28) +#define B_BE_SER_DETECT_EN BIT(26) #define B_BE_PCIE_SEC_LOAD BIT(26) #define B_BE_PCIE_SER_RSTB BIT(25) #define B_BE_PCIE_SEC_LOAD_CLR BIT(24) @@ -4172,6 +4199,22 @@ #define B_BE_LPSROP_LOWPWRPLL BIT(7) #define B_BE_LPSROP_DSWRSD_SEL_MASK GENMASK(5, 4) +#define R_BE_SYSON_FSM_MON 0x00A0 +#define B_BE_FSM_MON_SEL_MASK GENMASK(26, 24) +#define B_BE_DOP_ELDO BIT(23) +#define B_BE_AFE_PLL_BYPASS BIT(22) +#define B_BE_PON_SWR_BYPASS BIT(21) +#define B_BE_PON_ADIE_BYPASS BIT(20) +#define B_BE_AFE_LS_BYPASS BIT(19) +#define B_BE_BTPMC_XTAL_SI_BYPASS BIT(17) +#define B_BE_WLPMC_XTAL_SI_BYPASS BIT(16) +#define B_BE_FSM_MON_UPD BIT(15) +#define B_BE_FSM_PAR_MASK GENMASK(14, 0) +#define WLAN_FSM_MASK 0xFFFFFF +#define WLAN_FSM_SET 0x4000000 +#define WLAN_FSM_STATE_MASK 0x1FF +#define WLAN_FSM_IDLE 0 + #define R_BE_EFUSE_CTRL_2_V1 0x00A4 #define B_BE_EF_ENT BIT(31) #define B_BE_EF_TCOLUMN_EN BIT(29) @@ -4188,6 +4231,10 @@ #define B_BE_EF_DSB_EN BIT(11) #define B_BE_EF_DLY_SEL_MASK GENMASK(3, 0) +#define R_BE_SCOREBOARD 0x00AC +#define B_BE_TOGGLE BIT(31) +#define B_BE_DATA_LINE_MASK GENMASK(30, 0) + #define R_BE_PMC_DBG_CTRL2 0x00CC #define B_BE_EFUSE_BURN_GNT_MASK GENMASK(31, 24) #define B_BE_DIS_IOWRAP_TIMEOUT BIT(16) @@ -4237,6 +4284,13 @@ #define R_BE_PCIE_MIO_INTD 0x00E8 #define B_BE_PCIE_MIO_DATA_MASK GENMASK(31, 0) +#define R_BE_SYS_CHIPINFO 0x00FC +#define B_BE_USB2_SEL BIT(31) +#define B_BE_U3PHY_RST_V1 BIT(30) +#define B_BE_U3_TERM_DETECT BIT(29) +#define B_BE_VERIFY_ENV_MASK GENMASK(9, 8) +#define B_BE_HW_ID_MASK GENMASK(7, 0) + #define R_BE_HALT_H2C_CTRL 0x0160 #define B_BE_HALT_H2C_TRIGGER BIT(0) @@ -4447,6 +4501,16 @@ #define B_BE_WL_XTAL_SI_DATA_MASK GENMASK(15, 8) #define B_BE_WL_XTAL_SI_ADDR_MASK GENMASK(7, 0) +#define R_BE_PCIE_SER_DBG 0x02FC +#define B_BE_PCIE_SER_DBG_MASK GENMASK(31, 10) +#define B_BE_PCIE_SER_PHY_PROTECT BIT(9) +#define B_BE_PCIE_SER_MAC_PROTECT BIT(8) +#define B_BE_PCIE_SER_FLUSH_RSTB BIT(4) +#define B_BE_PCIE_AXI_BRG_FLUSH_EN BIT(3) +#define B_BE_PCIE_SER_AUXCLK_RDY BIT(2) +#define B_BE_PCIE_SER_FRZ_REG_RST BIT(1) +#define B_BE_PCIE_SER_FRZ_CFG_SPC_RST BIT(0) + #define R_BE_IC_PWR_STATE 0x03F0 #define B_BE_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16) #define MAC_AX_SYS_ACT 0x220 @@ -4599,6 +4663,10 @@ #define R_BE_LTR_LATENCY_IDX2_V1 0x361C #define R_BE_LTR_LATENCY_IDX3_V1 0x3620 +#define R_BE_HCI_BUF_IMR 0x6018 +#define B_BE_HCI_BUF_IMR_CLR 0xC0000303 +#define B_BE_HCI_BUF_IMR_SET 0xC0000301 + #define R_BE_H2CREG_DATA0 0x7140 #define R_BE_H2CREG_DATA1 0x7144 #define R_BE_H2CREG_DATA2 0x7148 @@ -4693,6 +4761,9 @@ #define B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK GENMASK(27, 16) #define B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK GENMASK(11, 0) +#define R_BE_NO_RX_ERR_CFG 0x841C +#define B_BE_NO_RX_ERR_TO_MASK GENMASK(31, 29) + #define R_BE_DMAC_TABLE_CTRL 0x8420 #define B_BE_HWAMSDU_PADDING_MODE BIT(31) #define B_BE_MACID_MPDU_PROCESSOR_OFFSET_MASK GENMASK(26, 16) @@ -4704,7 +4775,7 @@ #define B_BE_SER_L0_PROMOTE_L1_EVENT_MASK GENMASK(31, 28) #define B_BE_SER_L1_COUNTER_MASK GENMASK(27, 24) #define B_BE_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16) -#define B_BE_SER_L0_COUNTER_MASK GENMASK(8, 0) +#define B_BE_SER_L0_COUNTER_MASK GENMASK(7, 0) #define R_BE_DMAC_SYS_CR32B 0x842C #define B_BE_DMAC_BB_PHY1_MASK GENMASK(31, 16) @@ -5026,6 +5097,8 @@ B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN | \ B_BE_STF_OQT_OVERFLOW_ERR_INT_EN | \ B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN) +#define B_BE_DISP_OTHER_IMR_CLR_V1 0xFFFFFFFF +#define B_BE_DISP_OTHER_IMR_SET_V1 0x3F002000 #define R_BE_DISP_HOST_IMR 0x8874 #define B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN BIT(31) @@ -5103,6 +5176,8 @@ B_BE_HR_DMA_PROCESS_ERR_INT_EN | \ B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN | \ B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN) +#define B_BE_DISP_HOST_IMR_CLR_V1 0xFBFFFFFF +#define B_BE_DISP_HOST_IMR_SET_V1 0xC8B3E579 #define R_BE_DISP_CPU_IMR 0x8878 #define B_BE_CR_PLD_LEN_ERR_INT_EN BIT(30) @@ -5177,6 +5252,8 @@ B_BE_CR_DMA_PROCESS_ERR_INT_EN | \ B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \ B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN) +#define B_BE_DISP_CPU_IMR_CLR_V1 0x7DFFFFFD +#define B_BE_DISP_CPU_IMR_SET_V1 0x34F938FD #define R_BE_RX_STOP 0x8914 #define B_BE_CPU_RX_STOP BIT(17) @@ -5471,6 +5548,10 @@ #define B_BE_PLE_Q12_MAX_SIZE_MASK GENMASK(27, 16) #define B_BE_PLE_Q12_MIN_SIZE_MASK GENMASK(11, 0) +#define R_BE_PLE_QTA13_CFG 0x9074 +#define B_BE_PLE_Q13_MAX_SIZE_MASK GENMASK(27, 16) +#define B_BE_PLE_Q13_MIN_SIZE_MASK GENMASK(11, 0) + #define R_BE_PLE_ERRFLAG1_IMR 0x90C0 #define B_BE_PLE_SRCHPG_PGOFST_IMR BIT(26) #define B_BE_PLE_SRCHPG_STRPG_IMR BIT(25) @@ -5528,7 +5609,21 @@ B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN | \ B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN) +#define R_BE_RLSRPT0_CFG0 0x9440 +#define B_BE_RLSRPT0_FWRLS BIT(31) +#define B_BE_RLSRPT0_FWD_TRGT_MASK GENMASK(23, 16) +#define B_BE_RLSRPT0_PID_MASK GENMASK(10, 8) +#define B_BE_RLSRPT0_QID_MASK GENMASK(5, 0) +#define WDRLS_DEST_QID_POH 1 +#define WDRLS_DEST_QID_STF 0 + #define R_BE_RLSRPT0_CFG1 0x9444 +#define B_BE_RLSRPT0_FLTR_MAP_V1_MASK GENMASK(28, 24) +#define S_BE_WDRLS_FLTR_TXOK_V1 BIT(0) +#define S_BE_WDRLS_FLTR_RTYLMT_V1 BIT(1) +#define S_BE_WDRLS_FLTR_LIFTIM_V1 BIT(2) +#define S_BE_WDRLS_FLTR_MACID_V1 BIT(3) +#define S_BE_WDRLS_FLTR_RELINK_V1 BIT(4) #define B_BE_RLSRPT0_FLTR_MAP_MASK GENMASK(27, 24) #define S_BE_WDRLS_FLTR_TXOK 1 #define S_BE_WDRLS_FLTR_RTYLMT 2 @@ -5822,12 +5917,18 @@ #define B_BE_MPDUINFO_PKTID_MASK GENMASK(27, 16) #define B_BE_MPDUINFO_B1_BADDR_MASK GENMASK(5, 0) #define MPDU_INFO_B1_OFST 18 +#define MPDU_INFO_TBL_FACTOR 3 #define R_BE_TXPKTCTL_B0_PRELD_CFG0 0x9F48 #define B_BE_B0_PRELD_FEN BIT(31) #define B_BE_B0_PRELD_USEMAXSZ_MASK GENMASK(25, 16) #define B_BE_B0_PRELD_CAM_G1ENTNUM_MASK GENMASK(12, 8) +#define PRELD_MISCQ_ENT_NUM_8922A 2 +#define PRELD_MISCQ_ENT_NUM_8922D 1 #define B_BE_B0_PRELD_CAM_G0ENTNUM_MASK GENMASK(4, 0) +#define PRELD_B0_ACQ_ENT_NUM_8922A 8 +#define PRELD_B1_ACQ_ENT_NUM_8922A 2 +#define PRELD_ACQ_ENT_NUM_8922D 1 #define R_BE_TXPKTCTL_B0_PRELD_CFG1 0x9F4C #define B_BE_B0_PRELD_NXT_TXENDWIN_MASK GENMASK(11, 8) @@ -5939,6 +6040,7 @@ #define B_BE_PLRLS_CTL_FRZTO_ISR BIT(0) #define R_BE_SS_CTRL 0xA310 +#define R_BE_SS_CTRL_V1 0xA610 #define B_BE_SS_INIT_DONE BIT(31) #define B_BE_WDE_STA_DIS BIT(30) #define B_BE_WARM_INIT BIT(29) @@ -5978,6 +6080,24 @@ #define B_BE_RPT_TIMEOUT_ISR BIT(1) #define B_BE_SEARCH_TIMEOUT_ISR BIT(0) +#define R_BE_PLRLS_ERR_IMR_V1 0xA518 +#define B_BE_PLRLS_DUMMY_ISR6 BIT(7) +#define B_BE_PLRLS_DUMMY_ISR5 BIT(6) +#define B_BE_PLRLS_DUMMY_ISR4 BIT(5) +#define B_BE_PLRLS_DUMMY_ISR3 BIT(4) +#define B_BE_PLRLS_DUMMY_ISR2 BIT(3) +#define B_BE_PLRLS_DUMMY_ISR1 BIT(2) +#define B_BE_PLRLS_DUMMY_ISR0 BIT(1) +#define B_BE_PLRLS_ERR_IMR_V1_CLR 0x1 +#define B_BE_PLRLS_ERR_IMR_V1_SET 0x1 + +#define R_BE_SS_LITE_TXL_MACID 0xA790 +#define B_BE_RPT_OTHER_BAND_EN BIT(31) +#define B_BE_TXL_CMD_EN BIT(30) +#define B_BE_TXL_READ_MACID_MASK GENMASK(29, 20) +#define B_BE_TXL_MACID_1_MASK GENMASK(19, 10) +#define B_BE_TXL_MACID_0_MASK GENMASK(9, 0) + #define R_BE_HAXI_INIT_CFG1 0xB000 #define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28) #define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24) @@ -6017,6 +6137,18 @@ #define B_BE_STOP_CH2 BIT(2) #define B_BE_STOP_CH1 BIT(1) #define B_BE_STOP_CH0 BIT(0) +#define B_BE_TX_STOP1_MASK (B_BE_STOP_CH0 | B_BE_STOP_CH1 | \ + B_BE_STOP_CH2 | B_BE_STOP_CH3 | \ + B_BE_STOP_CH4 | B_BE_STOP_CH5 | \ + B_BE_STOP_CH6 | B_BE_STOP_CH7 | \ + B_BE_STOP_CH8 | B_BE_STOP_CH9 | \ + B_BE_STOP_CH10 | B_BE_STOP_CH11 | \ + B_BE_STOP_CH12 | B_BE_STOP_CH13 | \ + B_BE_STOP_CH14) +#define B_BE_TX_STOP1_MASK_V1 (B_BE_STOP_CH0 | B_BE_STOP_CH2 | \ + B_BE_STOP_CH4 | B_BE_STOP_CH6 | \ + B_BE_STOP_CH8 | B_BE_STOP_CH10 | \ + B_BE_STOP_CH12) #define R_BE_HAXI_MST_WDT_TIMEOUT_SEL_V1 0xB02C #define B_BE_HAXI_MST_WDT_TIMEOUT_SEL_MASK GENMASK(4, 0) @@ -6069,6 +6201,7 @@ #define R_BE_CH_PAGE_CTRL 0xB704 #define B_BE_PREC_PAGE_CH12_V1_MASK GENMASK(21, 16) +#define B_BE_FULL_WD_PG_MASK GENMASK(15, 8) #define B_BE_PREC_PAGE_CH011_V1_MASK GENMASK(5, 0) #define R_BE_CH0_PAGE_CTRL 0xB718 @@ -6101,6 +6234,10 @@ #define R_BE_WP_PAGE_CTRL1 0xB7A4 #define B_BE_PREC_PAGE_WP_CH811_MASK GENMASK(24, 16) #define B_BE_PREC_PAGE_WP_CH07_MASK GENMASK(8, 0) +#define B_BE_FULL_PAGE_WP_CH811_MASK GENMASK(31, 24) +#define B_BE_PREC_PAGE_WP_CH811_V1_MASK GENMASK(23, 16) +#define B_BE_FULL_PAGE_WP_CH07_MASK GENMASK(15, 8) +#define B_BE_PREC_PAGE_WP_CH07_V1_MASK GENMASK(7, 0) #define R_BE_WP_PAGE_CTRL2 0xB7A8 #define B_BE_WP_THRD_MASK GENMASK(12, 0) @@ -6159,6 +6296,75 @@ #define B_BE_GNT_WL_BB_PWR_VAL BIT(1) #define B_BE_GNT_WL_BB_PWR_SWCTRL BIT(0) +#define R_BE_PTA_GNT_SW_CTRL 0x0E348 +#define B_BE_PTA_WL_ACT0_VAL BIT(19) +#define B_BE_PTA_WL_ACT0_SWCTRL BIT(18) +#define B_BE_PTA_GNT_BT0_RX_BB1_VAL BIT(17) +#define B_BE_PTA_GNT_BT0_RX_BB1_SWCTRL BIT(16) +#define B_BE_PTA_GNT_BT0_TX_BB1_VAL BIT(15) +#define B_BE_PTA_GNT_BT0_TX_BB1_SWCTRL BIT(14) +#define B_BE_PTA_GNT_BT0_RX_BB0_VAL BIT(13) +#define B_BE_PTA_GNT_BT0_RX_BB0_SWCTRL BIT(12) +#define B_BE_PTA_GNT_BT0_TX_BB0_VAL BIT(11) +#define B_BE_PTA_GNT_BT0_TX_BB0_SWCTRL BIT(10) +#define B_BE_PTA_GNT_BT0_BB_VAL BIT(9) +#define B_BE_PTA_GNT_BT0_BB_SWCTRL BIT(8) +#define B_BE_PTA_WL_ACT_RX_BT0_VAL BIT(7) +#define B_BE_PTA_WL_ACT_RX_BT0_SWCTRL BIT(6) +#define B_BE_PTA_WL_ACT_TX_BT0_VAL BIT(5) +#define B_BE_PTA_WL_ACT_TX_BT0_SWCTRL BIT(4) +#define B_BE_PTA_GNT_WL_BB1_VAL BIT(3) +#define B_BE_PTA_GNT_WL_BB1_SWCTRL BIT(2) +#define B_BE_PTA_GNT_WL_BB0_VAL BIT(1) +#define B_BE_PTA_GNT_WL_BB0_SWCTRL BIT(0) + +#define R_BE_PTA_GNT_VAL 0x0E34C +#define B_BE_PTA_WL_ACT2 BIT(20) +#define B_BE_PTA_GNT_ZB_TX_BB1 BIT(19) +#define B_BE_PTA_GNT_ZB_TX_BB0 BIT(18) +#define B_BE_PTA_WL_ACT1 BIT(17) +#define B_BE_PTA_GNT_BT1_RX_BB1 BIT(16) +#define B_BE_PTA_GNT_BT1_RX_BB0 BIT(15) +#define B_BE_PTA_GNT_BT1_TX_BB1 BIT(14) +#define B_BE_PTA_GNT_BT1_TX_BB0 BIT(13) +#define B_BE_PTA_WL_ACT_RX_BT1 BIT(12) +#define B_BE_PTA_WL_ACT_TX_BT1 BIT(11) +#define B_BE_PTA_GNT_BT1_BB BIT(10) +#define B_BE_PTA_WL_ACT0 BIT(9) +#define B_BE_PTA_GNT_BT0_RX_BB1 BIT(8) +#define B_BE_PTA_GNT_BT0_TX_BB1 BIT(7) +#define B_BE_PTA_GNT_BT0_RX_BB0 BIT(6) +#define B_BE_PTA_GNT_BT0_TX_BB0 BIT(5) +#define B_BE_PTA_GNT_BT0_BB BIT(4) +#define B_BE_PTA_WL_ACT_RX_BT0 BIT(3) +#define B_BE_PTA_WL_ACT_TX_BT0 BIT(2) +#define B_BE_PTA_GNT_WL_BB1 BIT(1) +#define B_BE_PTA_GNT_WL_BB0 BIT(0) + +#define R_BE_PTA_GNT_ZL_SW_CTRL 0x0E350 +#define B_BE_PTA_WL_ACT2_VAL BIT(21) +#define B_BE_PTA_WL_ACT2_SWCTRL BIT(20) +#define B_BE_PTA_GNT_ZB_TX_BB1_VAL BIT(19) +#define B_BE_PTA_GNT_ZB_TX_BB1_SWCTRL BIT(18) +#define B_BE_PTA_GNT_ZB_TX_BB0_VAL BIT(17) +#define B_BE_PTA_GNT_ZB_TX_BB0_SWCTRL BIT(16) +#define B_BE_PTA_WL_ACT1_VAL BIT(15) +#define B_BE_PTA_WL_ACT1_SWCTRL BIT(14) +#define B_BE_PTA_GNT_BT1_RX_BB1_VAL BIT(13) +#define B_BE_PTA_GNT_BT1_RX_BB1_SWCTRL BIT(12) +#define B_BE_PTA_GNT_BT1_RX_BB0_VAL BIT(11) +#define B_BE_PTA_GNT_BT1_RX_BB0_SWCTRL BIT(10) +#define B_BE_PTA_GNT_BT1_TX_BB1_VAL BIT(9) +#define B_BE_PTA_GNT_BT1_TX_BB1_SWCTRL BIT(8) +#define B_BE_PTA_GNT_BT1_TX_BB0_VAL BIT(7) +#define B_BE_PTA_GNT_BT1_TX_BB0_SWCTRL BIT(6) +#define B_BE_PTA_WL_ACT_RX_BT1_VAL BIT(5) +#define B_BE_PTA_WL_ACT_RX_BT1_SWCTRL BIT(4) +#define B_BE_PTA_WL_ACT_TX_BT1_VAL BIT(3) +#define B_BE_PTA_WL_ACT_TX_BT1_SWCTRL BIT(2) +#define B_BE_PTA_GNT_BT1_BB_VAL BIT(1) +#define B_BE_PTA_GNT_BT1_BB_SWCTRL BIT(0) + #define R_BE_PWR_MACID_PATH_BASE 0x0E500 #define R_BE_PWR_MACID_LMT_BASE 0x0ED00 @@ -6257,6 +6463,21 @@ #define B_BE_RSC_MASK GENMASK(7, 6) #define B_BE_RRSR_CCK_MASK GENMASK(3, 0) +#define R_BE_COMMON_PHYINTF_CTRL_0 0x100B8 +#define R_BE_COMMON_PHYINTF_CTRL_0_C1 0x140B8 +#define B_BE_SEQ_EN_GUARD_CYE_MASK GENMASK(23, 20) +#define B_BE_PARA_FIFO_CRC_EN BIT(18) +#define B_BE_SEQ_FIFO_TO_EN BIT(17) +#define B_BE_PARA_FIFO_TO_EN BIT(16) +#define B_BE_SEQ_FIFO_CLR_EN BIT(6) +#define B_BE_PARA_FIFO_CLR_EN_V1 BIT(5) +#define B_BE_CSI_FIFO_CLR_EN_V1 BIT(4) +#define B_BE_FTM_FIFO_CLR_EN_V1 BIT(3) +#define B_BE_RXD_FIFO_CLR_EN_V1 BIT(2) +#define B_BE_TXD_FIFO_CLR_EN_V1 BIT(1) +#define B_BE_TXUID_FIFO_CLR_EN_V1 BIT(0) +#define CLEAR_DTOP_DIS (BIT(1) | BIT(5) | BIT(6)) + #define R_BE_CMAC_ERR_IMR 0x10160 #define R_BE_CMAC_ERR_IMR_C1 0x14160 #define B_BE_CMAC_FW_ERR_IDCT_EN BIT(16) @@ -6349,6 +6570,25 @@ #define B_BE_P0_SYNC_PORT_SRC_SEL_MASK GENMASK(26, 24) #define B_BE_P0_TSFTR_SYNC_OFFSET_MASK GENMASK(18, 0) +#define R_BE_SCH_EDCA_RST_CFG 0x102E4 +#define R_BE_SCH_EDCA_RST_CFG_C1 0x142E4 +#define B_BE_EDCCA_S160_RST_EDCA_EN BIT(23) +#define B_BE_EDCCA_S80_RST_EDCA_EN BIT(22) +#define B_BE_EDCCA_S40_RST_EDCA_EN BIT(21) +#define B_BE_EDCCA_S20_RST_EDCA_EN BIT(20) +#define B_BE_OFDM_CCA_S160_RST_EDCA_EN BIT(19) +#define B_BE_CCA_PEB_BE_BITMAP_RST_EDCA_EN BIT(18) +#define B_BE_RX_INTRA_NAV_RST_EDCA_EN BIT(15) +#define B_BE_RX_BASIC_NAV_RST_EDCA_EN BIT(14) +#define B_BE_EDCCA_PER20_BITMAP_SIFS_RST_EDCA_EN BIT(10) +#define B_BE_TX_NAV_RST_EDCA_EN BIT(7) +#define B_BE_NO_GNT_WL_RST_EDCA_EN BIT(5) +#define B_BE_EDCCA_P20_RST_EDCA_EN BIT(4) +#define B_BE_OFDM_CCA_S80_RST_EDCA_EN BIT(3) +#define B_BE_OFDM_CCA_S40_RST_EDCA_EN BIT(2) +#define B_BE_OFDM_CCA_S20_RST_EDCA_EN BIT(1) +#define B_BE_CCA_P20_RST_EDCA_EN BIT(0) + #define R_BE_EDCA_BCNQ_PARAM 0x10324 #define R_BE_EDCA_BCNQ_PARAM_C1 0x14324 #define B_BE_BCNQ_CW_MASK GENMASK(31, 24) @@ -6639,6 +6879,34 @@ #define B_BE_CMAC_TX_MODE_1 BIT(1) #define B_BE_CMAC_TX_MODE_0 BIT(0) +#define R_BE_AGG_BK_0 0x10804 +#define R_BE_AGG_BK_0_C1 0x14804 +#define B_BE_DIS_SAMPDU_TXIME_SR_CHECK BIT(24) +#define B_BE_TX_PAIR_MACID_LEN_EN BIT(23) +#define B_BE_DIS_SND_STS_CHECK_SU BIT(22) +#define B_BE_MAX_AGG_NUM_FIX_MODE_EN_V1 BIT(21) +#define B_BE_DIS_SIFS_BK_AGG_AMPDU BIT(20) +#define B_BE_EN_MU2SU_CHK_PROTECT_PPDU BIT(19) +#define B_BE_RPT_TXOP_START_PROTECT BIT(18) +#define B_BE_RANDOM_GEN_CMD_ABORT_EN BIT(17) +#define B_BE_PHYTXON_ENDPS_RESP_CHK BIT(16) +#define B_BE_CTN_CHK_SEQ_REQ_EN BIT(15) +#define B_BE_PTCL_RLS_ALLFAIL_EN BIT(14) +#define B_BE_DIS_MURU_PRI_Q_EMPTY_CHK BIT(13) +#define B_BE_DIS_MURU_SEC_Q_EMPTY_CHK BIT(12) +#define B_BE_EN_SAMPDU_TXIME_TWT_CHECK BIT(11) +#define B_BE_DIS_SAMPDU_TXIME_P2P_CHECK BIT(10) +#define B_BE_DIS_SAMPDU_TXIME_BCN_CHECK BIT(9) +#define B_BE_DIS_UL_SEQ_ABORT_CHECK BIT(8) +#define B_BE_DIS_SND_STS_CHECK BIT(7) +#define B_BE_NAV_PAUS_PHB_EN BIT(6) +#define B_BE_TXOP_SHT_PHB_EN BIT(5) +#define B_BE_AGG_BRK_PHB_EN BIT(4) +#define B_BE_DIS_SSN_CHK BIT(3) +#define B_BE_WDBK_CFG BIT(2) +#define B_BE_EN_RTY_BK BIT(1) +#define B_BE_EN_RTY_BK_COD BIT(0) + #define R_BE_TB_PPDU_CTRL 0x1080C #define R_BE_TB_PPDU_CTRL_C1 0x1480C #define B_BE_TB_PPDU_BK_DIS BIT(15) @@ -6653,9 +6921,11 @@ #define R_BE_AMPDU_AGG_LIMIT_C1 0x14810 #define B_BE_AMPDU_MAX_TIME_MASK GENMASK(31, 24) #define AMPDU_MAX_TIME 0x9E +#define AMPDU_MAX_TIME_V1 0xA4 #define B_BE_RA_TRY_RATE_AGG_LMT_MASK GENMASK(23, 16) #define B_BE_RTS_MAX_AGG_NUM_MASK GENMASK(15, 8) #define B_BE_MAX_AGG_NUM_MASK GENMASK(7, 0) +#define MAX_TX_AMPDU_NUM_V1 128 #define R_BE_AGG_LEN_HT_0 0x10814 #define R_BE_AGG_LEN_HT_0_C1 0x14814 @@ -6663,6 +6933,20 @@ #define B_BE_RTS_TXTIME_TH_MASK GENMASK(15, 8) #define B_BE_RTS_LEN_TH_MASK GENMASK(7, 0) +#define R_BE_SPECIAL_TX_SETTING 0x10820 +#define R_BE_SPECIAL_TX_SETTING_C1 0x14820 +#define B_BE_TRI_PADDING_EXTEND BIT(31) +#define B_BE_TX_SN_BYPASS_EN BIT(30) +#define B_BE_USE_DATA_BW BIT(29) +#define B_BE_BW_SIGTA_MASK GENMASK(28, 27) +#define B_BE_BMC_NAV_PROTECT BIT(26) +#define B_BE_F2P_KEEP_NON_SR_CMD BIT(25) +#define B_BE_F2P_SU_FIXRATE_OVER_WD BIT(24) +#define B_BE_BAR_TXRATE_FOR_NULL_WD_MASK GENMASK(23, 20) +#define B_BE_STBC_CFEND_MASK GENMASK(19, 18) +#define B_BE_STBC_CFEND_RATE_MASK GENMASK(17, 9) +#define B_BE_BASIC_CFEND_RATE_MASK GENMASK(8, 0) + #define R_BE_SIFS_SETTING 0x10824 #define R_BE_SIFS_SETTING_C1 0x14824 #define B_BE_HW_CTS2SELF_PKT_LEN_TH_MASK GENMASK(31, 24) @@ -6696,6 +6980,44 @@ #define B_BE_PORT_DROP_4_0_MASK GENMASK(20, 16) #define B_BE_MBSSID_DROP_15_0_MASK GENMASK(15, 0) +#define R_BE_PTCL_PRELD_CTRL 0x10868 +#define R_BE_PTCL_PRELD_CTRL_C1 0x14868 +#define B_BE_PRELD_MGQ2_EN BIT(22) +#define B_BE_PRELD_MGQ1_EN BIT(21) +#define B_BE_PRELD_MGQ0_EN BIT(20) +#define B_BE_PRELD_HIQ_P4_EN BIT(19) +#define B_BE_PRELD_HIQ_P3_EN BIT(18) +#define B_BE_PRELD_HIQ_P2_EN BIT(17) +#define B_BE_PRELD_HIQ_P1_EN BIT(16) +#define B_BE_PRELD_HIQ_P0MB15_EN BIT(15) +#define B_BE_PRELD_HIQ_P0MB14_EN BIT(14) +#define B_BE_PRELD_HIQ_P0MB13_EN BIT(13) +#define B_BE_PRELD_HIQ_P0MB12_EN BIT(12) +#define B_BE_PRELD_HIQ_P0MB11_EN BIT(11) +#define B_BE_PRELD_HIQ_P0MB10_EN BIT(10) +#define B_BE_PRELD_HIQ_P0MB9_EN BIT(9) +#define B_BE_PRELD_HIQ_P0MB8_EN BIT(8) +#define B_BE_PRELD_HIQ_P0MB7_EN BIT(7) +#define B_BE_PRELD_HIQ_P0MB6_EN BIT(6) +#define B_BE_PRELD_HIQ_P0MB5_EN BIT(5) +#define B_BE_PRELD_HIQ_P0MB4_EN BIT(4) +#define B_BE_PRELD_HIQ_P0MB3_EN BIT(3) +#define B_BE_PRELD_HIQ_P0MB2_EN BIT(2) +#define B_BE_PRELD_HIQ_P0MB1_EN BIT(1) +#define B_BE_PRELD_HIQ_P0_EN BIT(0) +#define B_BE_PRELD_HIQ_ALL_EN (B_BE_PRELD_HIQ_P0_EN | B_BE_PRELD_HIQ_P1_EN | \ + B_BE_PRELD_HIQ_P2_EN | B_BE_PRELD_HIQ_P3_EN | \ + B_BE_PRELD_HIQ_P4_EN) +#define B_BE_PRELD_HIQ_P0MB_ALL_EN \ + (B_BE_PRELD_HIQ_P0_EN | B_BE_PRELD_HIQ_P0MB1_EN | \ + B_BE_PRELD_HIQ_P0MB2_EN | B_BE_PRELD_HIQ_P0MB3_EN | \ + B_BE_PRELD_HIQ_P0MB4_EN | B_BE_PRELD_HIQ_P0MB5_EN | \ + B_BE_PRELD_HIQ_P0MB6_EN | B_BE_PRELD_HIQ_P0MB7_EN | \ + B_BE_PRELD_HIQ_P0MB8_EN | B_BE_PRELD_HIQ_P0MB9_EN | \ + B_BE_PRELD_HIQ_P0MB10_EN | B_BE_PRELD_HIQ_P0MB11_EN | \ + B_BE_PRELD_HIQ_P0MB12_EN | B_BE_PRELD_HIQ_P0MB13_EN | \ + B_BE_PRELD_HIQ_P0MB14_EN | B_BE_PRELD_HIQ_P0MB15_EN) + #define R_BE_BT_PLT 0x1087C #define R_BE_BT_PLT_C1 0x1487C #define B_BE_BT_PLT_PKT_CNT_MASK GENMASK(31, 16) @@ -6936,6 +7258,8 @@ B_BE_RX_RU1_FSM_HANG_ERROR_IMR | \ B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \ B_BE_RX_GET_NULL_PKT_ERROR_IMR) +#define B_BE_RX_ERROR_FLAG_IMR_CLR_V1 0x7FFFFFF8 +#define B_BE_RX_ERROR_FLAG_IMR_SET_V1 0x7FFFFF38 #define R_BE_RX_CTRL_1 0x10C0C #define R_BE_RX_CTRL_1_C1 0x14C0C @@ -7349,6 +7673,8 @@ #define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) #define B_BE_ACK_BA_RESP_LEGACY_CHK_EDCCA BIT(1) #define B_BE_ACK_BA_RESP_LEGACY_CHK_CCA BIT(0) +#define RESP_ACK_CFG_BE (B_BE_ACK_BA_RESP_LEGACY_CHK_BTCCA | \ + B_BE_ACK_BA_RESP_LEGACY_CHK_TX_NAV) #define R_BE_WMAC_ACK_BA_RESP_HE 0x11204 #define R_BE_WMAC_ACK_BA_RESP_HE_C1 0x15204 @@ -7390,6 +7716,188 @@ #define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_EDCCA BIT(1) #define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_CCA BIT(0) +#define R_BE_WMAC_RX_RTS_RESP_LEGACY 0x1120C +#define R_BE_WMAC_RX_RTS_RESP_LEGACY_C1 0x1520C +#define B_BE_RX_RTS_RESP_LEGACY_CHK_NSTR BIT(16) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV BIT(15) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_INTRA_NAV BIT(14) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV BIT(13) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA BIT(12) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA160 BIT(5) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA80 BIT(4) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA40 BIT(3) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA BIT(1) +#define B_BE_RX_RTS_RESP_LEGACY_CHK_CCA BIT(0) +#define RESP_RTS_CFG_BE (B_BE_RX_RTS_RESP_LEGACY_CHK_CCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA20 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA40 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA80 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA160 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA20 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA40 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA80 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA160 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_INTRA_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV) +#define RESP_RTS_PUNC_CFG_BE (B_BE_RX_RTS_RESP_LEGACY_CHK_CCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_CCA_PER20_BMP | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA_PER20_BMP | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_INTRA_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV) +#define RESP_NORMAL_CFG_BE (B_BE_RX_RTS_RESP_LEGACY_CHK_CCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA20 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA40 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA80 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_CCA160 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA20 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA40 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA80 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_SEC_EDCCA160 | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV) +#define RESP_NORMAL_PUNC_CFG_BE (B_BE_RX_RTS_RESP_LEGACY_CHK_CCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_CCA_PER20_BMP | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_EDCCA_PER20_BMP | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BTCCA | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_BASIC_NAV | \ + B_BE_RX_RTS_RESP_LEGACY_CHK_TX_NAV) + +#define R_BE_WMAC_RX_RTS_RESP_LEGACY_PUNC 0x11210 +#define R_BE_WMAC_RX_RTS_RESP_LEGACY_PUNC_C1 0x15210 +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_NSTR BIT(16) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_TX_NAV BIT(15) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_INTRA_NAV BIT(14) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_BASIC_NAV BIT(13) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_BTCCA BIT(12) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_CCA160 BIT(5) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_CCA80 BIT(4) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_CCA40 BIT(3) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_SEC_CCA20 BIT(2) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_EDCCA BIT(1) +#define B_BE_RX_RTS_RESP_LEGACY_PUNC_CHK_CCA BIT(0) + +#define R_BE_WMAC_RX_MURTS_RESP_LEGACY 0x11214 +#define R_BE_WMAC_RX_MURTS_RESP_LEGACY_C1 0x15214 +#define B_BE_MURTS_RESP_LEGACY_CHK_NSTR BIT(16) +#define B_BE_MURTS_RESP_LEGACY_CHK_TX_NAV BIT(15) +#define B_BE_MURTS_RESP_LEGACY_CHK_INTRA_NAV BIT(14) +#define B_BE_MURTS_RESP_LEGACY_CHK_BASIC_NAV BIT(13) +#define B_BE_MURTS_RESP_LEGACY_CHK_BTCCA BIT(12) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_MURTS_RESP_LEGACY_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_MURTS_RESP_LEGACY_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_CCA160 BIT(5) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_CCA80 BIT(4) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_CCA40 BIT(3) +#define B_BE_MURTS_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) +#define B_BE_MURTS_RESP_LEGACY_CHK_EDCCA BIT(1) +#define B_BE_MURTS_RESP_LEGACY_CHK_CCA BIT(0) + +#define R_BE_WMAC_RX_MURTS_RESP_LEGACY_PUNC 0x11218 +#define R_BE_WMAC_RX_MURTS_RESP_LEGACY_PUNC_C1 0x15218 +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_NSTR BIT(16) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_TX_NAV BIT(15) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_INTRA_NAV BIT(14) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_BASIC_NAV BIT(13) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_BTCCA BIT(12) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_CCA160 BIT(5) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_CCA80 BIT(4) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_CCA40 BIT(3) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_SEC_CCA20 BIT(2) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_EDCCA BIT(1) +#define B_BE_MURTS_RESP_LEGACY_PUNC_CHK_CCA BIT(0) + +#define R_BE_WMAC_OTHERS_RESP_LEGACY 0x1121C +#define R_BE_WMAC_OTHERS_RESP_LEGACY_C1 0x1521C +#define B_BE_OTHERS_RESP_LEGACY_CHK_NSTR BIT(16) +#define B_BE_OTHERS_RESP_LEGACY_CHK_TX_NAV BIT(15) +#define B_BE_OTHERS_RESP_LEGACY_CHK_INTRA_NAV BIT(14) +#define B_BE_OTHERS_RESP_LEGACY_CHK_BASIC_NAV BIT(13) +#define B_BE_OTHERS_RESP_LEGACY_CHK_BTCCA BIT(12) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_OTHERS_RESP_LEGACY_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_OTHERS_RESP_LEGACY_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_CCA160 BIT(5) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_CCA80 BIT(4) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_CCA40 BIT(3) +#define B_BE_OTHERS_RESP_LEGACY_CHK_SEC_CCA20 BIT(2) +#define B_BE_OTHERS_RESP_LEGACY_CHK_EDCCA BIT(1) +#define B_BE_OTHERS_RESP_LEGACY_CHK_CCA BIT(0) + +#define R_BE_WMAC_OTHERS_RESP_HE 0x11220 +#define R_BE_WMAC_OTHERS_RESP_HE_C1 0x15220 +#define B_BE_OTHERS_RESP_HE_CHK_NSTR BIT(16) +#define B_BE_OTHERS_RESP_HE_CHK_TX_NAV BIT(15) +#define B_BE_OTHERS_RESP_HE_CHK_INTRA_NAV BIT(14) +#define B_BE_OTHERS_RESP_HE_CHK_BASIC_NAV BIT(13) +#define B_BE_OTHERS_RESP_HE_CHK_BTCCA BIT(12) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_OTHERS_RESP_HE_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_OTHERS_RESP_HE_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_CCA160 BIT(5) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_CCA80 BIT(4) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_CCA40 BIT(3) +#define B_BE_OTHERS_RESP_HE_CHK_SEC_CCA20 BIT(2) +#define B_BE_OTHERS_RESP_HE_CHK_EDCCA BIT(1) +#define B_BE_OTHERS_RESP_HE_CHK_CCA BIT(0) + +#define R_BE_WMAC_OTHERS_RESP_EHT_LEG_PUNC 0x11224 +#define R_BE_WMAC_OTHERS_RESP_EHT_LEG_PUNC_C1 0x15224 +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_NSTR BIT(16) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_TX_NAV BIT(15) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_INTRA_NAV BIT(14) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_BASIC_NAV BIT(13) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_BTCCA BIT(12) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_EDCCA160 BIT(11) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_EDCCA80 BIT(10) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_EDCCA40 BIT(9) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_EDCCA20 BIT(8) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_EDCCA_PER20_BMP BIT(7) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_CCA_PER20_BMP BIT(6) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_CCA160 BIT(5) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_CCA80 BIT(4) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_CCA40 BIT(3) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_SEC_CCA20 BIT(2) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_EDCCA BIT(1) +#define B_BE_OTHERS_RESP_EHT_LEG_PUNC_CHK_CCA BIT(0) + #define R_BE_RCR 0x11400 #define R_BE_RCR_C1 0x15400 #define B_BE_BUSY_CHKSN BIT(15) @@ -7427,6 +7935,17 @@ #define B_BE_CCK_SIG_CHK BIT(1) #define B_BE_CCK_CRC_CHK BIT(0) +#define R_BE_RXGCK_CTRL 0x11406 +#define R_BE_RXGCK_CTRL_C1 0x15406 +#define B_BE_RXGCK_BCNPRS_DISGCLK BIT(12) +#define B_BE_RXGCK_GCK_RATE_LIMIT_MASK GENMASK(9, 8) +#define RX_GCK_LEGACY 2 +#define B_BE_RXGCK_DISREG_GCLK BIT(7) +#define B_BE_RXGCK_ENTRY_DELAY_MASK GENMASK(6, 4) +#define B_BE_RXGCK_GCK_CYCLE_MASK GENMASK(3, 2) +#define B_BE_RXGCK_CCA_EN BIT(1) +#define B_BE_DISGCLK BIT(0) + #define R_BE_RX_FLTR_OPT 0x11420 #define R_BE_RX_FLTR_OPT_C1 0x15420 #define B_BE_UID_FILTER_MASK GENMASK(31, 24) @@ -7521,6 +8040,11 @@ #define B_BE_CSIPRT_HESU_AID_EN BIT(25) #define B_BE_CSIPRT_VHTSU_AID_EN BIT(24) +#define R_BE_BSR_UPD_CTRL 0x11468 +#define R_BE_BSR_UPD_CTRL_C1 0x15468 +#define B_BE_QSIZE_RULE BIT(1) +#define B_BE_QSIZE_UPD BIT(0) + #define R_BE_DRV_INFO_OPTION 0x11470 #define R_BE_DRV_INFO_OPTION_C1 0x15470 #define B_BE_DRV_INFO_PHYRPT_EN BIT(0) @@ -7586,11 +8110,35 @@ #define B_BE_PLCP_CH20_WIDATA_SRC BIT(1) #define B_BE_PLCP_PPDU_TYPE_SRC BIT(0) +#define R_BE_RX_PLCP_EXT_OPTION_2 0x11518 +#define R_BE_RX_PLCP_EXT_OPTION_2_C1 0x15518 +#define B_BE_PLCP_PHASE_B_CRC_CHK_EN BIT(17) +#define B_BE_PLCP_PHASE_A_CRC_CHK_EN BIT(16) +#define B_BE_EHTTB_EHTSIG_CRC_CHK_EN BIT(3) +#define B_BE_EHTTB_USIG_CRC_CHK_EN BIT(2) +#define B_BE_EHTMU_EHTSIG_CRC_CHK_EN BIT(1) +#define B_BE_EHTMU_USIG_CRC_CHK_EN BIT(0) + #define R_BE_RESP_CSI_RESERVED_PAGE 0x11810 #define R_BE_RESP_CSI_RESERVED_PAGE_C1 0x15810 #define B_BE_CSI_RESERVED_PAGE_NUM_MASK GENMASK(27, 16) #define B_BE_CSI_RESERVED_START_PAGE_MASK GENMASK(11, 0) +#define R_BE_RESP_IMR1 0x11878 +#define R_BE_RESP_IMR1_C1 0x15878 +#define B_BE_RESP_IMR_1_MASK GENMASK(31, 9) +#define B_BE_FSM_TIMEOUT_ERR_IMR BIT(8) +#define B_BE_SEC_DOUBLE_HIT_ERR_IMR BIT(7) +#define B_BE_WRPTR_ERR_IMR BIT(6) +#define B_BE_SMR_TOO_MANY_PLD_ERR_IMR BIT(5) +#define B_BE_LMR_TOO_MANY_PLD_ERR_IMR BIT(4) +#define B_BE_CSI_TOO_MANY_PLD_ERR_IMR BIT(3) +#define B_BE_FTM_LMR_PLDID_READY_ERR_IMR BIT(2) +#define B_BE_SMR_PLDID_READY_ERR_IMR BIT(1) +#define B_BE_CSI_PLDID_READY_ERR_IMR BIT(0) +#define B_BE_RESP_IMR1_CLR 0x1FF +#define B_BE_RESP_IMR1_SET 0xFF + #define R_BE_RESP_IMR 0x11884 #define R_BE_RESP_IMR_C1 0x15884 #define B_BE_RESP_TBL_FLAG_ERR_ISR_EN BIT(17) @@ -7635,6 +8183,8 @@ B_BE_RESP_PLDID_RDY_ERR_ISR_EN | \ B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN | \ B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN) +#define B_BE_RESP_IMR_CLR_V1 0xFFFFFFFF +#define B_BE_RESP_IMR_SET_V1 0xFFFFFFFF #define R_BE_PWR_MODULE 0x11900 #define R_BE_PWR_MODULE_C1 0x15900 @@ -7713,6 +8263,10 @@ #define R_BE_TXPWR_ERR_FLAG_C1 0x158E4 #define R_BE_TXPWR_ERR_IMR_C1 0x158E0 +#define R_BE_SCH_EXT_CTRL 0x103FC +#define R_BE_SCH_EXT_CTRL_C1 0x143FC +#define B_BE_CWCNT_PLUS_MODE BIT(31) + #define CMAC1_START_ADDR_BE 0x14000 #define CMAC1_END_ADDR_BE 0x17FFF diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 209d84909f88..c3425ed44732 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -1142,6 +1142,7 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, } } else { rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + dflt = true; } rcu_read_unlock(); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 84b628d23882..0383d3b5c7bc 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -633,8 +633,6 @@ static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, efuse->rfe_type = map->rfe_type; efuse->xtal_cap = map->xtal_k; - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } @@ -2553,6 +2551,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8851b_btc_set_rfe, .btc_init_cfg = rtw8851b_btc_init_cfg, @@ -2590,6 +2589,10 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .small_fifo_size = true, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 3500, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, @@ -2704,6 +2707,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .rfkill_init = &rtw8851b_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), @@ -2712,6 +2716,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8851b, #endif .xtal_info = &rtw8851b_xtal_info, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8851b_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 8677723e3561..329fc0a7b07b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -678,8 +678,6 @@ static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, efuse->rfe_type = map->rfe_type; efuse->xtal_cap = map->xtal_k; - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } @@ -2247,6 +2245,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8852a_btc_set_rfe, .btc_init_cfg = rtw8852a_btc_init_cfg, @@ -2275,6 +2274,10 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .small_fifo_size = false, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 3500, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = {rtw8852a_hfc_param_ini_pcie, @@ -2391,12 +2394,14 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP, .rfkill_init = &rtw8852a_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = 0, .edcca_regs = &rtw8852a_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852a, #endif .xtal_info = &rtw8852a_xtal_info, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8852a_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c index ca782469c455..ccdbcc178c2a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c @@ -52,6 +52,8 @@ static const struct usb_device_id rtw_8852au_id_table[] = { .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3321, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3323, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x332c, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x013f, 0xff, 0xff, 0xff), @@ -60,6 +62,8 @@ static const struct usb_device_id rtw_8852au_id_table[] = { .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0141, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3625, 0x010d, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x3625, 0x010f, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852au_info }, {}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 70fb05bc5e98..f44674a39e30 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -313,6 +313,27 @@ static void rtw8852b_pwr_sps_ana(struct rtw89_dev *rtwdev) rtw89_write16(rtwdev, R_AX_SPS_ANA_ON_CTRL2, RTL8852B_RFE_05_SPS_ANA); } +static void rtw8852b_pwr_sps_dig_off(struct rtw89_dev *rtwdev) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + + if (efuse->rfe_type == 0x5) { + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C1_L1_MASK, 0x1); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C2_L1_MASK, 0x1); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C3_L1_MASK, 0x2); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_R1_L1_MASK, 0x1); + } else { + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C1_L1_MASK, 0x1); + rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, + B_AX_C3_L1_MASK, 0x3); + } +} + static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; @@ -338,8 +359,7 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) if (ret) return ret; - rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, B_AX_C1_L1_MASK, 0x1); - rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, B_AX_C3_L1_MASK, 0x3); + rtw8852b_pwr_sps_dig_off(rtwdev); rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_EN_WLON); rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFN_ONMAC); @@ -858,6 +878,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8852b_btc_set_rfe, .btc_init_cfg = rtw8852bx_btc_init_cfg, @@ -899,6 +920,10 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .small_fifo_size = true, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 5000, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, @@ -1016,6 +1041,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .rfkill_init = &rtw8852b_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), @@ -1024,6 +1050,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8852b, #endif .xtal_info = NULL, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8852b_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index 4e72f4961837..65b839323e3e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -265,8 +265,6 @@ static int __rtw8852bx_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, efuse->rfe_type = map->rfe_type; efuse->xtal_cap = map->xtal_k; - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index f956474c3b72..ab60ed389ff7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -724,6 +724,7 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8852bt_btc_set_rfe, .btc_init_cfg = rtw8852bx_btc_init_cfg, @@ -765,6 +766,10 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .small_fifo_size = true, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 5000, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = {rtw8852bt_hfc_param_ini_pcie, NULL, NULL}, @@ -873,6 +878,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .rfkill_init = &rtw8852bt_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), @@ -881,6 +887,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .wowlan_stub = &rtw_wowlan_stub_8852bt, #endif .xtal_info = NULL, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8852bt_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c index 980d17ef68d0..84cd3ec971f9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c @@ -54,6 +54,8 @@ static const struct usb_device_id rtw_8852bu_id_table[] = { .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x0db0, 0x6931, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0db0, 0xf0c8, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3327, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, { USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6121, 0xff, 0xff, 0xff), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index db99450e9158..d2138be3640d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -600,8 +600,6 @@ static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, efuse->rfe_type = map->rfe_type; efuse->xtal_cap = map->xtal_k; - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } @@ -3088,6 +3086,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8852c_btc_set_rfe, .btc_init_cfg = rtw8852c_btc_init_cfg, @@ -3116,6 +3115,10 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .small_fifo_size = false, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 8000, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = 0, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x6f800, .hfc_param_ini = {rtw8852c_hfc_param_ini_pcie, @@ -3236,12 +3239,14 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP, .rfkill_init = &rtw8852c_rfkill_regs, .rfkill_get = {R_AX_GPIO_EXT_CTRL, B_AX_GPIO_IN_9}, + .btc_sb = {{{R_AX_SCOREBOARD, R_AX_SCOREBOARD},}}, .dma_ch_mask = 0, .edcca_regs = &rtw8852c_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852c, #endif .xtal_info = NULL, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8852c_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 4437279c554b..6d2cd914e16e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -628,24 +628,36 @@ static int rtw8922a_read_efuse_rf(struct rtw89_dev *rtwdev, u8 *log_map) rtw8922a_efuse_parsing_tssi(rtwdev, map); rtw8922a_efuse_parsing_gain_offset(rtwdev, map); - rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); - return 0; } static int rtw8922a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, enum rtw89_efuse_block block) { + struct rtw89_efuse *efuse = &rtwdev->efuse; + int ret; + switch (block) { case RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO: - return rtw8922a_read_efuse_pci_sdio(rtwdev, log_map); + ret = rtw8922a_read_efuse_pci_sdio(rtwdev, log_map); + break; case RTW89_EFUSE_BLOCK_HCI_DIG_USB: - return rtw8922a_read_efuse_usb(rtwdev, log_map); + ret = rtw8922a_read_efuse_usb(rtwdev, log_map); + break; case RTW89_EFUSE_BLOCK_RF: - return rtw8922a_read_efuse_rf(rtwdev, log_map); + ret = rtw8922a_read_efuse_rf(rtwdev, log_map); + break; default: - return 0; + ret = 0; + break; + } + + if (!ret && is_zero_ether_addr(efuse->addr)) { + rtw89_info(rtwdev, "efuse mac address is zero, using random mac\n"); + eth_random_addr(efuse->addr); } + + return ret; } #define THM_TRIM_POSITIVE_MASK BIT(6) @@ -2847,6 +2859,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v2, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, + .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update, .btc_set_rfe = rtw8922a_btc_set_rfe, .btc_init_cfg = rtw8922a_btc_init_cfg, @@ -2875,6 +2888,10 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .small_fifo_size = false, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 8000, + .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + .max_eht_mpdu_cap = IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991, + .max_tx_agg_num = 128, + .max_rx_agg_num = 64, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x8f800, .hfc_param_ini = {rtw8922a_hfc_param_ini_pcie, NULL, NULL}, @@ -2988,12 +3005,14 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .bss_clr_map_reg = R_BSS_CLR_MAP_V2, .rfkill_init = &rtw8922a_rfkill_regs, .rfkill_get = {R_BE_GPIO_EXT_CTRL, B_BE_GPIO_IN_9}, + .btc_sb = {{{R_BE_SCOREBOARD, R_BE_SCOREBOARD},}}, .dma_ch_mask = 0, .edcca_regs = &rtw8922a_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8922a, #endif .xtal_info = NULL, + .default_quirks = 0, }; EXPORT_SYMBOL(rtw8922a_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index fce094c7ce93..98f14b31cf52 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -205,11 +205,11 @@ static void rtw8922a_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx) } } -static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, - const struct rtw89_chan *chan, u8 path) +static u8 rtw8922a_chlk_reload_sel_tbl_v0(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] = {}; + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; u8 tbl_sel; for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) { @@ -229,11 +229,53 @@ static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, 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].rf18[tbl_sel] = rtw89_chip_chan_to_rf18_val(rtwdev, chan); rfk_mcc->data[path].table_idx = tbl_sel; return tbl_sel; } +static u8 rtw8922a_chlk_reload_sel_tbl_v1(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 path) +{ + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {}; + u8 tbl_sel; + + 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->has_band = true; + p->band = rfk_mcc->band[tbl_sel]; + + p->has_bw = true; + p->bw = rfk_mcc->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->rf18[tbl_sel] = rtw89_chip_chan_to_rf18_val(rtwdev, chan); + + /* shared table array, but tbl_sel can be independent by path */ + rfk_mcc[path].table_idx = tbl_sel; + + return tbl_sel; +} + +static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 path) +{ + if (RTW89_CHK_FW_FEATURE(RFK_PRE_NOTIFY_MCC_V1, &rtwdev->fw)) + return rtw8922a_chlk_reload_sel_tbl_v1(rtwdev, chan, path); + else + return rtw8922a_chlk_reload_sel_tbl_v0(rtwdev, chan, path); +} + static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) { const struct rtw89_chan *chan0, *chan1; diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index f99e179f7ff9..7fdc69578da3 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -431,6 +431,14 @@ static void hal_send_m4_event(struct rtw89_ser *ser) rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RCVY_EN); } +static void hal_enable_err_imr(struct rtw89_ser *ser) +{ + struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + mac->err_imr_ctrl(rtwdev, true); +} + /* state handler */ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) { @@ -552,6 +560,8 @@ static void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt) break; case SER_EV_MAC_RESET_DONE: + hal_enable_err_imr(ser); + ser_state_goto(ser, SER_IDLE_ST); break; diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index fa324b4a1dde..b69a2529aefc 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -188,12 +188,16 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_BODY2_QSEL GENMASK(22, 17) #define BE_TXD_BODY2_TID_IND BIT(23) #define BE_TXD_BODY2_MACID GENMASK(31, 24) +#define BE_TXD_BODY2_QSEL_V1 GENMASK(20, 15) +#define BE_TXD_BODY2_TID_IND_V1 BIT(21) +#define BE_TXD_BODY2_MACID_V1 GENMASK(31, 22) /* TX WD BODY DWORD 3 */ #define BE_TXD_BODY3_WIFI_SEQ GENMASK(11, 0) #define BE_TXD_BODY3_MLO_FLAG BIT(12) #define BE_TXD_BODY3_IS_MLD_SW_EN BIT(13) #define BE_TXD_BODY3_TRY_RATE BIT(14) +#define BE_TXD_BODY3_BK_V1 BIT(14) #define BE_TXD_BODY3_RELINK_FLAG_V1 BIT(15) #define BE_TXD_BODY3_BAND0_SU_TC_V1 GENMASK(21, 16) #define BE_TXD_BODY3_TOTAL_TC GENMASK(27, 22) @@ -201,6 +205,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_BODY3_MU_PRI_RTY BIT(29) #define BE_TXD_BODY3_MU_2ND_RTY BIT(30) #define BE_TXD_BODY3_BAND1_SU_RTY_V1 BIT(31) +#define BE_TXD_BODY3_DRIVER_QUEUE_TIME GENMASK(31, 16) /* TX WD BODY DWORD 4 */ #define BE_TXD_BODY4_TXDESC_CHECKSUM GENMASK(15, 0) @@ -224,6 +229,10 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_BODY6_EOSP_BIT BIT(15) #define BE_TXD_BODY6_S_IDX GENMASK(23, 16) #define BE_TXD_BODY6_RU_POS GENMASK(31, 24) +#define BE_TXD_BODY6_MU_TC_V1 GENMASK(3, 0) +#define BE_TXD_BODY6_RU_TC_V1 GENMASK(8, 5) +#define BE_TXD_BODY6_RELINK_EN BIT(9) +#define BE_TXD_BODY6_RELINK_LAST BIT(10) /* TX WD BODY DWORD 7 */ #define BE_TXD_BODY7_RTS_TC GENMASK(5, 0) @@ -262,6 +271,8 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) /* TX WD INFO DWORD 2 */ #define BE_TXD_INFO2_SEC_CAM_IDX GENMASK(7, 0) #define BE_TXD_INFO2_FORCE_KEY_EN BIT(8) +#define BE_TXD_INFO2_SEC_CAM_IDX_V1 GENMASK(9, 0) +#define BE_TXD_INFO2_FORCE_KEY_EN_V1 BIT(10) #define BE_TXD_INFO2_LIFETIME_SEL GENMASK(15, 13) #define BE_TXD_INFO2_FORCE_TXOP BIT(17) #define BE_TXD_INFO2_AMPDU_DENSITY GENMASK(20, 18) @@ -277,6 +288,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_INFO3_RTT_EN BIT(9) #define BE_TXD_INFO3_HT_DATA_SND_V1 BIT(10) #define BE_TXD_INFO3_BT_NULL BIT(11) +#define BE_TXD_INFO3_DISABLE_TXBF BIT(11) #define BE_TXD_INFO3_TRI_FRAME BIT(12) #define BE_TXD_INFO3_NULL_0 BIT(13) #define BE_TXD_INFO3_NULL_1 BIT(14) @@ -292,6 +304,8 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_INFO4_PUNC_MODE GENMASK(17, 16) #define BE_TXD_INFO4_SW_TX_OK_0 BIT(18) #define BE_TXD_INFO4_SW_TX_OK_1 BIT(19) +#define BE_TXD_INFO4_SW_EHT_NLTF_SWITCH BIT(20) +#define BE_TXD_INFO4_SW_EHT_NLTF GENMASK(22, 21) #define BE_TXD_INFO4_SW_TX_PWR_DBM GENMASK(26, 23) #define BE_TXD_INFO4_RTS_EN BIT(27) #define BE_TXD_INFO4_CTS2SELF BIT(28) @@ -308,6 +322,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_INFO6_UL_GI_LTF GENMASK(14, 12) #define BE_TXD_INFO6_UL_DOPPLER BIT(15) #define BE_TXD_INFO6_UL_STBC BIT(16) +#define BE_TXD_INFO6_UL_MU_MIMO_EN BIT(17) #define BE_TXD_INFO6_UL_LENGTH_REF GENMASK(21, 18) #define BE_TXD_INFO6_UL_RF_GAIN_IDX GENMASK(31, 22) @@ -322,6 +337,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define BE_TXD_INFO7_UL_HELTF_SYMBOL_NUM GENMASK(19, 17) #define BE_TXD_INFO7_ULBW GENMASK(21, 20) #define BE_TXD_INFO7_ULBW_EXT GENMASK(23, 22) +#define BE_TXD_INFO7_UL_TRI_PAD_TSF BIT(24) #define BE_TXD_INFO7_USE_WD_UL GENMASK(25, 24) #define BE_TXD_INFO7_EXTEND_MODE_SEL GENMASK(31, 28) @@ -488,6 +504,7 @@ struct rtw89_phy_sts_iehdr { /* BE RXD dword2 */ #define BE_RXD_MAC_ID_MASK GENMASK(7, 0) +#define BE_RXD_MAC_ID_V1 GENMASK(9, 0) #define BE_RXD_TYPE_MASK GENMASK(11, 10) #define BE_RXD_LAST_MSDU BIT(12) #define BE_RXD_AMSDU_CUT BIT(13) @@ -519,6 +536,7 @@ struct rtw89_phy_sts_iehdr { #define BE_RXD_QNULL BIT(22) #define BE_RXD_A4_FRAME BIT(23) #define BE_RXD_FRAG_MASK GENMASK(27, 24) +#define BE_RXD_GET_CH_INFO_V2 GENMASK(31, 29) #define BE_RXD_GET_CH_INFO_V1_MASK GENMASK(31, 30) /* BE RXD dword4 */ @@ -534,10 +552,14 @@ struct rtw89_phy_sts_iehdr { /* BE RXD dword6 */ #define BE_RXD_ADDR_CAM_MASK GENMASK(7, 0) +#define BE_RXD_ADDR_CAM_V1 GENMASK(9, 0) +#define BE_RXD_RX_STATISTICS_V1 BIT(11) +#define BE_RXD_SMART_ANT_V1 BIT(12) #define BE_RXD_SR_EN BIT(13) #define BE_RXD_NON_SRG_PPDU BIT(14) #define BE_RXD_INTER_PPDU BIT(15) #define BE_RXD_USER_ID_MASK GENMASK(21, 16) +#define BE_RXD_SEC_CAM_IDX_V1 GENMASK(31, 22) #define BE_RXD_RX_STATISTICS BIT(22) #define BE_RXD_SMART_ANT BIT(23) #define BE_RXD_SEC_CAM_IDX_MASK GENMASK(31, 24) diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c index d7d968207a39..e77561a4d971 100644 --- a/drivers/net/wireless/realtek/rtw89/usb.c +++ b/drivers/net/wireless/realtek/rtw89/usb.c @@ -620,7 +620,7 @@ static int rtw89_usb_init_rx(struct rtw89_dev *rtwdev) struct sk_buff *rx_skb; int i; - rtwusb->rxwq = alloc_workqueue("rtw89_usb: rx wq", WQ_BH, 0); + rtwusb->rxwq = alloc_workqueue("rtw89_usb: rx wq", WQ_BH | WQ_PERCPU, 0); if (!rtwusb->rxwq) { rtw89_err(rtwdev, "failed to create RX work queue\n"); return -ENOMEM; diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 46aba4cb2ee9..5d3227e2b3e4 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -809,6 +809,10 @@ static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) reason = rtw89_read8(rtwdev, wow_reason_reg); switch (reason) { + case RTW89_WOW_RSN_RX_DISASSOC: + wakeup.disconnect = true; + rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx disassoc\n"); + break; case RTW89_WOW_RSN_RX_DEAUTH: wakeup.disconnect = true; rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx deauth\n"); @@ -1070,7 +1074,7 @@ static void rtw89_wow_pattern_clear_cam(struct rtw89_dev *rtwdev) for (i = 0; i < rtw_wow->pattern_cnt; i++) { rtw_pattern = &rtw_wow->patterns[i]; rtw_pattern->valid = false; - rtw89_fw_wow_cam_update(rtwdev, rtw_pattern); + rtw89_chip_h2c_wow_cam_update(rtwdev, rtw_pattern); } } @@ -1081,7 +1085,7 @@ static void rtw89_wow_pattern_write(struct rtw89_dev *rtwdev) int i; for (i = 0; i < rtw_wow->pattern_cnt; i++) - rtw89_fw_wow_cam_update(rtwdev, rtw_pattern + i); + rtw89_chip_h2c_wow_cam_update(rtwdev, rtw_pattern + i); } static void rtw89_wow_pattern_clear(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index d2ba6cebc2a6..71e07f482174 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -33,6 +33,7 @@ enum rtw89_wake_reason { RTW89_WOW_RSN_RX_PTK_REKEY = 0x1, RTW89_WOW_RSN_RX_GTK_REKEY = 0x2, + RTW89_WOW_RSN_RX_DISASSOC = 0x4, RTW89_WOW_RSN_RX_DEAUTH = 0x8, RTW89_WOW_RSN_DISCONNECT = 0x10, RTW89_WOW_RSN_RX_MAGIC_PKT = 0x21, diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 1e578533e473..ee7ad81c858d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1443,9 +1443,8 @@ static int rsi_thaw(struct device *dev) return 0; } -static void rsi_shutdown(struct device *dev) +static void rsi_shutdown(struct sdio_func *pfunction) { - struct sdio_func *pfunction = dev_to_sdio_func(dev); struct rsi_hw *adapter = sdio_get_drvdata(pfunction); struct rsi_91x_sdiodev *sdev = adapter->rsi_dev; struct ieee80211_hw *hw = adapter->hw; @@ -1513,9 +1512,9 @@ static struct sdio_driver rsi_driver = { .remove = rsi_disconnect, .id_table = rsi_dev_table, #ifdef CONFIG_PM + .shutdown = rsi_shutdown, .drv = { .pm = &rsi_pm_ops, - .shutdown = rsi_shutdown, } #endif }; diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index d16afb35f9ee..f8160f372bc7 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -455,6 +455,7 @@ enum wl1271_cmd_key_type { KEY_TKIP = 2, KEY_AES = 3, KEY_GEM = 4, + KEY_IGTK = 5, }; struct wl1271_cmd_set_keys { diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 12f0167d7380..dce79bce2e3f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -2419,6 +2419,11 @@ power_off: strscpy(wiphy->fw_version, wl->chip.fw_ver_str, sizeof(wiphy->fw_version)); + /* WLAN_CIPHER_SUITE_AES_CMAC must be last in cipher_suites; + support only with firmware 8.9.1 and newer */ + if (wl->chip.fw_ver[FW_VER_MAJOR] < 1) + wl->hw->wiphy->n_cipher_suites--; + /* * Now we know if 11a is supported (info from the NVS), so disable * 11a channels if not supported @@ -3585,6 +3590,9 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, case WL1271_CIPHER_SUITE_GEM: key_type = KEY_GEM; break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key_type = KEY_IGTK; + break; default: wl1271_error("Unknown key algo 0x%x", key_conf->cipher); @@ -6196,6 +6204,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, WL1271_CIPHER_SUITE_GEM, + WLAN_CIPHER_SUITE_AES_CMAC, }; /* The tx descriptor buffer */ diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 96439de55f07..fbde215c25aa 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1351,6 +1351,7 @@ struct ieee80211_tdls_data { #define WLAN_AUTH_FILS_SK 4 #define WLAN_AUTH_FILS_SK_PFS 5 #define WLAN_AUTH_FILS_PK 6 +#define WLAN_AUTH_EPPKE 9 #define WLAN_AUTH_LEAP 128 #define WLAN_AUTH_CHALLENGE_LEN 128 diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index fed1f5f4a8d3..4534bf462aac 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -78,6 +78,7 @@ struct sdio_driver { int (*probe)(struct sdio_func *, const struct sdio_device_id *); void (*remove)(struct sdio_func *); + void (*shutdown)(struct sdio_func *); struct device_driver drv; }; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 6c11aa0e103b..7911ed58abbb 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1785,6 +1785,7 @@ struct cfg80211_ttlm_params { * present/updated * @eml_cap: EML capabilities of this station * @link_sta_params: link related params. + * @epp_peer: EPP peer indication */ struct station_parameters { struct net_device *vlan; @@ -1811,6 +1812,7 @@ struct station_parameters { bool eml_cap_present; u16 eml_cap; struct link_station_parameters link_sta_params; + bool epp_peer; }; /** @@ -4187,6 +4189,7 @@ struct cfg80211_ftm_responder_stats { * @num_bursts_exp: actual number of bursts exponent negotiated * @burst_duration: actual burst duration negotiated * @ftms_per_burst: actual FTMs per burst negotiated + * @burst_period: actual burst period negotiated in units of 100ms * @lci_len: length of LCI information (if present) * @civicloc_len: length of civic location information (if present) * @lci: LCI data (may be %NULL) @@ -4228,6 +4231,7 @@ struct cfg80211_pmsr_ftm_result { u8 num_bursts_exp; u8 burst_duration; u8 ftms_per_burst; + u16 burst_period; s32 rssi_avg; s32 rssi_spread; struct rate_info tx_rate, rx_rate; @@ -4290,7 +4294,9 @@ struct cfg80211_pmsr_result { * @burst_period: burst period to use * @asap: indicates to use ASAP mode * @num_bursts_exp: number of bursts exponent - * @burst_duration: burst duration + * @burst_duration: burst duration. If @trigger_based or @non_trigger_based is + * set, this is the burst duration in milliseconds, and zero means the + * device should pick an appropriate value based on @ftms_per_burst. * @ftms_per_burst: number of FTMs per burst * @ftmr_retries: number of retries for FTM request * @request_lci: request LCI information @@ -4303,6 +4309,8 @@ struct cfg80211_pmsr_result { * EDCA based ranging will be used. * @lmr_feedback: negotiate for I2R LMR feedback. Only valid if either * @trigger_based or @non_trigger_based is set. + * @rsta: Operate as the RSTA in the measurement. Only valid if @lmr_feedback + * and either @trigger_based or @non_trigger_based is set. * @bss_color: the bss color of the responder. Optional. Set to zero to * indicate the driver should set the BSS color. Only valid if * @non_trigger_based or @trigger_based is set. @@ -4318,7 +4326,8 @@ struct cfg80211_pmsr_ftm_request_peer { request_civicloc:1, trigger_based:1, non_trigger_based:1, - lmr_feedback:1; + lmr_feedback:1, + rsta:1; u8 num_bursts_exp; u8 burst_duration; u8 ftms_per_burst; @@ -5638,6 +5647,18 @@ cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type); * not limited) * @ftm.trigger_based: trigger based ranging measurement is supported * @ftm.non_trigger_based: non trigger based ranging measurement is supported + * @ftm.support_6ghz: supports ranging in 6 GHz band + * @ftm.max_tx_ltf_rep: maximum number of TX LTF repetitions supported (0 means + * only one LTF, no repetitions) + * @ftm.max_rx_ltf_rep: maximum number of RX LTF repetitions supported (0 means + * only one LTF, no repetitions) + * @ftm.max_tx_sts: maximum number of TX STS supported (zero based) + * @ftm.max_rx_sts: maximum number of RX STS supported (zero based) + * @ftm.max_total_ltf_tx: maximum total number of LTFs that can be transmitted + * (0 means unknown) + * @ftm.max_total_ltf_rx: maximum total number of LTFs that can be received + * (0 means unknown) + * @ftm.support_rsta: supports operating as RSTA in PMSR FTM request */ struct cfg80211_pmsr_capabilities { unsigned int max_peers; @@ -5655,7 +5676,15 @@ struct cfg80211_pmsr_capabilities { request_lci:1, request_civicloc:1, trigger_based:1, - non_trigger_based:1; + non_trigger_based:1, + support_6ghz:1; + u8 max_tx_ltf_rep; + u8 max_rx_ltf_rep; + u8 max_tx_sts; + u8 max_rx_sts; + u8 max_total_ltf_tx; + u8 max_total_ltf_rx; + u8 support_rsta:1; } ftm; }; @@ -10165,9 +10194,9 @@ cfg80211_6ghz_power_type(u8 control, u32 client_flags) case IEEE80211_6GHZ_CTRL_REG_LPI_AP: case IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP: case IEEE80211_6GHZ_CTRL_REG_AP_ROLE_NOT_RELEVANT: + case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD: return IEEE80211_REG_LPI_AP; case IEEE80211_6GHZ_CTRL_REG_SP_AP: - case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP_OLD: return IEEE80211_REG_SP_AP; case IEEE80211_6GHZ_CTRL_REG_VLP_AP: return IEEE80211_REG_VLP_AP; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 36daccef6554..36ae7fe9ddf3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -2520,6 +2520,7 @@ struct ieee80211_link_sta { * by the AP. * @valid_links: bitmap of valid links, or 0 for non-MLO * @spp_amsdu: indicates whether the STA uses SPP A-MSDU or not. + * @epp_peer: indicates that the peer is an EPP peer. */ struct ieee80211_sta { u8 addr[ETH_ALEN] __aligned(2); @@ -2544,6 +2545,7 @@ struct ieee80211_sta { struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1]; u16 valid_links; + bool epp_peer; struct ieee80211_link_sta deflink; struct ieee80211_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 7c12badf85dc..706a98686068 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -11,7 +11,7 @@ * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> * Copyright 2008 Colin McCabe <colin@cozybit.com> * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2025 Intel Corporation + * Copyright (C) 2018-2026 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -2974,6 +2974,9 @@ enum nl80211_commands { * primary channel is 2 MHz wide, and the control channel designates * the 1 MHz primary subchannel within that 2 MHz primary. * + * @NL80211_ATTR_EPP_PEER: A flag attribute to indicate if the peer is an EPP + * STA. Used with %NL80211_CMD_NEW_STA and %NL80211_CMD_ADD_LINK_STA + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3542,6 +3545,8 @@ enum nl80211_attrs { NL80211_ATTR_S1G_PRIMARY_2MHZ, + NL80211_ATTR_EPP_PEER, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -5430,6 +5435,7 @@ enum nl80211_bss_status { * @NL80211_AUTHTYPE_FILS_SK: Fast Initial Link Setup shared key * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key + * @NL80211_AUTHTYPE_EPPKE: Enhanced Privacy Protection Key Exchange * @__NL80211_AUTHTYPE_NUM: internal * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by @@ -5445,6 +5451,7 @@ enum nl80211_auth_type { NL80211_AUTHTYPE_FILS_SK, NL80211_AUTHTYPE_FILS_SK_PFS, NL80211_AUTHTYPE_FILS_PK, + NL80211_AUTHTYPE_EPPKE, /* keep last */ __NL80211_AUTHTYPE_NUM, @@ -6749,6 +6756,15 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_BEACON_RATE_EHT: Driver supports beacon rate * configuration (AP/mesh) with EHT rates. * + * @NL80211_EXT_FEATURE_EPPKE: Driver supports Enhanced Privacy Protection + * Key Exchange (EPPKE) with user space SME (NL80211_CMD_AUTHENTICATE) + * in non-AP STA mode. + * + * @NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION: This specifies that the + * driver supports encryption of (Re)Association Request and Response + * frames in both non‑AP STA and AP mode as specified in + * "IEEE P802.11bi/D3.0, 12.16.6". + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -6825,6 +6841,8 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_DFS_CONCURRENT, NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT, NL80211_EXT_FEATURE_BEACON_RATE_EHT, + NL80211_EXT_FEATURE_EPPKE, + NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -7437,6 +7455,8 @@ enum nl80211_nan_band_conf_attributes { * address that can take values from 50-6F-9A-01-00-00 to * 50-6F-9A-01-FF-FF. This attribute is optional. If not present, * a random Cluster ID will be chosen. + * This attribute will be ignored in NL80211_CMD_CHANGE_NAN_CONFIG + * since after NAN was started, the cluster ID can no longer change. * @NL80211_NAN_CONF_EXTRA_ATTRS: Additional NAN attributes to be * published in the beacons. This is an optional byte array. * @NL80211_NAN_CONF_VENDOR_ELEMS: Vendor-specific elements that will @@ -7771,6 +7791,30 @@ enum nl80211_peer_measurement_attrs { * trigger based ranging measurement is supported * @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating * if non-trigger-based ranging measurement is supported + * @NL80211_PMSR_FTM_CAPA_ATTR_6GHZ_SUPPORT: flag attribute indicating if + * ranging on the 6 GHz band is supported + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_LTF_REP: u32 attribute indicating + * the maximum number of LTF repetitions the device can transmit in the + * preamble of the ranging NDP (zero means only one LTF, no repetitions) + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_LTF_REP: u32 attribute indicating + * the maximum number of LTF repetitions the device can receive in the + * preamble of the ranging NDP (zero means only one LTF, no repetitions) + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_STS: u32 attribute indicating + * the maximum number of space-time streams supported for ranging NDP TX + * (zero-based) + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_STS: u32 attribute indicating + * the maximum number of space-time streams supported for ranging NDP RX + * (zero-based) + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_TX: u32 attribute indicating the + * maximum total number of LTFs the device can transmit. The total number + * of LTFs is (number of LTF repetitions) * (number of space-time streams). + * This limits the allowed combinations of LTF repetitions and STS. + * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_RX: u32 attribute indicating the + * maximum total number of LTFs the device can receive. The total number + * of LTFs is (number of LTF repetitions) * (number of space-time streams). + * This limits the allowed combinations of LTF repetitions and STS. + * @NL80211_PMSR_FTM_CAPA_ATTR_RSTA_SUPPORT: flag attribute indicating the + * device supports operating as the RSTA in PMSR FTM request * * @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal * @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number @@ -7788,6 +7832,14 @@ enum nl80211_peer_measurement_ftm_capa { NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST, NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED, NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED, + NL80211_PMSR_FTM_CAPA_ATTR_6GHZ_SUPPORT, + NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_LTF_REP, + NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_LTF_REP, + NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_STS, + NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_STS, + NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_TX, + NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_RX, + NL80211_PMSR_FTM_CAPA_ATTR_RSTA_SUPPORT, /* keep last */ NUM_NL80211_PMSR_FTM_CAPA_ATTR, @@ -7803,12 +7855,15 @@ enum nl80211_peer_measurement_ftm_capa { * &enum nl80211_preamble), optional for DMG (u32) * @NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP: number of bursts exponent as in * 802.11-2016 9.4.2.168 "Fine Timing Measurement Parameters element" - * (u8, 0-15, optional with default 15 i.e. "no preference") + * (u8, 0-15, optional with default 15 i.e. "no preference". No limit for + * non-EDCA ranging) * @NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD: interval between bursts in units * of 100ms (u16, optional with default 0) * @NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION: burst duration, as in 802.11-2016 * Table 9-257 "Burst Duration field encoding" (u8, 0-15, optional with - * default 15 i.e. "no preference") + * default 15 i.e. "no preference"). For non-EDCA ranging, this is the + * burst duration in milliseconds (optional with default 0, i.e. let the + * device decide). * @NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST: number of successful FTM frames * requested per burst * (u8, 0-31, optional with default 0 i.e. "no preference") @@ -7837,6 +7892,14 @@ enum nl80211_peer_measurement_ftm_capa { * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set. + * @NL80211_PMSR_FTM_REQ_ATTR_RSTA: optional. Request to perform the measurement + * as the RSTA (flag). When set, the device is expected to dwell on the + * channel specified in %NL80211_PMSR_PEER_ATTR_CHAN until it receives the + * FTM request from the peer or the timeout specified by + * %NL80211_ATTR_TIMEOUT has expired. + * Only valid if %NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK is set (so the + * RSTA will have the measurement results to report back in the FTM + * response). * * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number @@ -7857,6 +7920,7 @@ enum nl80211_peer_measurement_ftm_req { NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, + NL80211_PMSR_FTM_REQ_ATTR_RSTA, /* keep last */ NUM_NL80211_PMSR_FTM_REQ_ATTR, @@ -7941,6 +8005,8 @@ enum nl80211_peer_measurement_ftm_failure_reasons { * 9.4.2.22.1) starting with the Measurement Token, with Measurement * Type 11. * @NL80211_PMSR_FTM_RESP_ATTR_PAD: ignore, for u64/s64 padding only + * @NL80211_PMSR_FTM_RESP_ATTR_BURST_PERIOD: actual burst period used by + * the responder (similar to request, u16) * * @NUM_NL80211_PMSR_FTM_RESP_ATTR: internal * @NL80211_PMSR_FTM_RESP_ATTR_MAX: highest attribute number @@ -7969,6 +8035,7 @@ enum nl80211_peer_measurement_ftm_resp { NL80211_PMSR_FTM_RESP_ATTR_LCI, NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC, NL80211_PMSR_FTM_RESP_ATTR_PAD, + NL80211_PMSR_FTM_RESP_ATTR_BURST_PERIOD, /* keep last */ NUM_NL80211_PMSR_FTM_RESP_ATTR, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fe6be11a7f44..964f440e31cd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -680,10 +680,18 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, * association has completed, this rejects that attempt * so it will set the key again after association. * + * With (re)association frame encryption enabled, cfg80211 + * may deliver keys to mac80211 before the station has + * associated. In that case, accept the key if the station + * is an Enhanced Privacy Protection (EPP) peer. + * If (re)association frame encryption support is not present, + * cfg80211 will not allow key installation in non‑AP STA mode. + * * TODO: accept the key if we have a station entry and - * add it to the device after the station. + * add it to the device after the station associates. */ - if (!sta || !test_sta_flag(sta, WLAN_STA_ASSOC)) { + if (!sta || (!sta->sta.epp_peer && + !test_sta_flag(sta, WLAN_STA_ASSOC))) { ieee80211_key_free_unused(key); return -ENOENT; } @@ -2198,6 +2206,9 @@ static int sta_apply_parameters(struct ieee80211_local *local, mask = params->sta_flags_mask; set = params->sta_flags_set; + if (params->epp_peer) + sta->sta.epp_peer = true; + if (ieee80211_vif_is_mesh(&sdata->vif)) { /* * In mesh mode, ASSOCIATED isn't part of the nl80211 diff --git a/net/mac80211/drop.h b/net/mac80211/drop.h index eb9ab310f91c..f06a8aa905c5 100644 --- a/net/mac80211/drop.h +++ b/net/mac80211/drop.h @@ -2,7 +2,7 @@ /* * mac80211 drop reason list * - * Copyright (C) 2023-2024 Intel Corporation + * Copyright (C) 2023-2024, 2026 Intel Corporation */ #ifndef MAC80211_DROP_H @@ -65,6 +65,49 @@ typedef unsigned int __bitwise ieee80211_rx_result; /* 0x30 */ \ R(RX_DROP_U_BAD_MGMT_KEYIDX) \ R(RX_DROP_U_UNKNOWN_ACTION_REJECTED) \ + R(RX_DROP_U_MESH_DS_BITS) \ + R(RX_DROP_U_MESH_A3_MISMATCH) \ + R(RX_DROP_U_MESH_NO_A4) \ + R(RX_DROP_U_MESH_A4_MISMATCH) \ + R(RX_DROP_U_MESH_UNEXP_DATA) \ + R(RX_DROP_U_MESH_WRONG_ACTION) \ + R(RX_DROP_U_MESH_UNEXP_MGMT) \ + R(RX_DROP_U_SPURIOUS_NOTIF) \ + R(RX_DROP_U_RUNT_DATA) \ + R(RX_DROP_U_KEY_TAINTED) \ + R(RX_DROP_U_UNPROTECTED) \ + R(RX_DROP_U_MCAST_FRAGMENT) \ + R(RX_DROP_U_DEFRAG_MISMATCH) \ + R(RX_DROP_U_RUNT_MESH_DATA) \ + /* 0x40 */ \ + R(RX_DROP_U_MESH_NO_TTL) \ + R(RX_DROP_U_MESH_RMC) \ + R(RX_DROP_U_MESH_BAD_AE) \ + R(RX_DROP_U_MESH_TTL_EXPIRED) \ + R(RX_DROP_U_MESH_NOT_FORWARDING) \ + R(RX_DROP_U_AMSDU_WITHOUT_DATA) \ + R(RX_DROP_U_NULL_DATA) \ + R(RX_DROP_U_UNEXPECTED_4ADDR) \ + R(RX_DROP_U_PORT_CONTROL) \ + R(RX_DROP_U_UNKNOWN_STA) \ + R(RX_DROP_U_RUNT_BAR) \ + R(RX_DROP_U_BAR_OUTSIDE_SESSION) \ + R(RX_DROP_U_CTRL_FRAME) \ + R(RX_DROP_U_RUNT_MGMT) \ + R(RX_DROP_U_EXPECTED_MGMT) \ + R(RX_DROP_U_NONBCAST_BEACON) \ + /* 0x50 */ \ + R(RX_DROP_U_MALFORMED_ACTION) \ + R(RX_DROP_U_UNKNOWN_MCAST_ACTION) \ + R(RX_DROP_U_UNEXPECTED_EXT_FRAME) \ + R(RX_DROP_U_UNHANDLED_MGMT) \ + R(RX_DROP_U_MCAST_DEAUTH) \ + R(RX_DROP_U_UNHANDLED_DEAUTH) \ + R(RX_DROP_U_MCAST_DISASSOC) \ + R(RX_DROP_U_UNHANDLED_DISASSOC) \ + R(RX_DROP_U_UNHANDLED_PREQ) \ + R(RX_DROP_U_UNHANDLED_MGMT_STYPE) \ + R(RX_DROP_U_NO_LINK) \ /* this line for the trailing \ - add before this */ /* having two enums allows for checking ieee80211_rx_result use with sparse */ @@ -85,7 +128,6 @@ enum ___mac80211_drop_reason { enum mac80211_drop_reason { RX_CONTINUE = (__force ieee80211_rx_result)___RX_CONTINUE, RX_QUEUED = (__force ieee80211_rx_result)___RX_QUEUED, - RX_DROP = (__force ieee80211_rx_result)___RX_DROP_UNUSABLE, #define DEF(x) x = (__force ieee80211_rx_result)___ ## x, MAC80211_DROP_REASONS_UNUSABLE(DEF) #undef DEF diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5bc7eb2342bb..ea4c9293d299 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -430,7 +430,7 @@ struct ieee80211_mgd_auth_data { u8 ap_addr[ETH_ALEN] __aligned(2); - u16 sae_trans, sae_status; + u16 trans, status; size_t data_len; u8 data[]; }; @@ -2391,6 +2391,14 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int tid, int link_id, enum nl80211_band band); +static inline bool ieee80211_require_encrypted_assoc(__le16 fc, + struct sta_info *sta) +{ + return (sta && sta->sta.epp_peer && + (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc) || + ieee80211_is_assoc_resp(fc) || ieee80211_is_reassoc_resp(fc))); +} + /* sta_out needs to be checked for ERR_PTR() before using */ int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 515384ca2f8f..463b78093d3e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -8,7 +8,7 @@ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2025 Intel Corporation + * Copyright (C) 2018-2026 Intel Corporation */ #include <linux/slab.h> #include <linux/kernel.h> @@ -1793,7 +1793,7 @@ static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work) else ieee80211_iface_process_skb(local, sdata, skb); - kfree_skb(skb); + consume_skb(skb); kcov_remote_stop(); } @@ -1802,7 +1802,7 @@ static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work) kcov_remote_start_common(skb_get_kcov_handle(skb)); ieee80211_iface_process_status(sdata, skb); - kfree_skb(skb); + consume_skb(skb); kcov_remote_stop(); } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 94ebffbdf394..7461f4fa6e08 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2155,6 +2155,8 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) struct ieee80211_prep_tx_info info = {}; unsigned int link_id, n_links = 0; u16 present_elems[PRESENT_ELEMS_MAX] = {}; + struct sta_info *sta; + bool assoc_encrypt; void *capab_pos; size_t size; int ret; @@ -2335,7 +2337,15 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) info.link_id = assoc_data->assoc_link_id; drv_mgd_prepare_tx(local, sdata, &info); - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + sta = sta_info_get_bss(sdata, sdata->vif.cfg.ap_addr); + + assoc_encrypt = sta && sta->sta.epp_peer && + wiphy_dereference(sdata->local->hw.wiphy, + sta->ptk[sta->ptk_idx]); + + if (!assoc_encrypt) + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | IEEE80211_TX_INTFL_MLME_CONN_TX; @@ -4911,6 +4921,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, case WLAN_AUTH_FILS_SK: case WLAN_AUTH_FILS_SK_PFS: case WLAN_AUTH_FILS_PK: + case WLAN_AUTH_EPPKE: break; case WLAN_AUTH_SHARED_KEY: if (ifmgd->auth_data->expected_transaction != 4) { @@ -8307,6 +8318,12 @@ static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) if (WARN_ON_ONCE(!auth_data)) return -EINVAL; + if (auth_data->algorithm == WLAN_AUTH_EPPKE && + ieee80211_vif_is_mld(&sdata->vif) && + !cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK, + auth_data->data, auth_data->data_len)) + return -EINVAL; + auth_data->tries++; if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { @@ -8335,9 +8352,12 @@ static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) auth_data->expected_transaction = 2; if (auth_data->algorithm == WLAN_AUTH_SAE) { - trans = auth_data->sae_trans; - status = auth_data->sae_status; + trans = auth_data->trans; + status = auth_data->status; auth_data->expected_transaction = trans; + } else if (auth_data->algorithm == WLAN_AUTH_EPPKE) { + trans = auth_data->trans; + status = auth_data->status; } if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) @@ -8994,6 +9014,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, goto out_err; } + if (ifmgd->auth_data && + ifmgd->auth_data->algorithm == WLAN_AUTH_EPPKE) + new_sta->sta.epp_peer = true; + new_sta->sta.mlo = mlo; } @@ -9248,6 +9272,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, case NL80211_AUTHTYPE_FILS_PK: auth_alg = WLAN_AUTH_FILS_PK; break; + case NL80211_AUTHTYPE_EPPKE: + auth_alg = WLAN_AUTH_EPPKE; + break; default: return -EOPNOTSUPP; } @@ -9272,12 +9299,14 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, auth_data->link_id = req->link_id; if (req->auth_data_len >= 4) { - if (req->auth_type == NL80211_AUTHTYPE_SAE) { + if (req->auth_type == NL80211_AUTHTYPE_SAE || + req->auth_type == NL80211_AUTHTYPE_EPPKE) { __le16 *pos = (__le16 *) req->auth_data; - auth_data->sae_trans = le16_to_cpu(pos[0]); - auth_data->sae_status = le16_to_cpu(pos[1]); + auth_data->trans = le16_to_cpu(pos[0]); + auth_data->status = le16_to_cpu(pos[1]); } + memcpy(auth_data->data, req->auth_data + 4, req->auth_data_len - 4); auth_data->data_len += req->auth_data_len - 4; @@ -9328,7 +9357,11 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, * out SAE Confirm. */ if (cont_auth && req->auth_type == NL80211_AUTHTYPE_SAE && - auth_data->peer_confirmed && auth_data->sae_trans == 2) + auth_data->peer_confirmed && auth_data->trans == 2) + ieee80211_mark_sta_auth(sdata); + + if (cont_auth && req->auth_type == NL80211_AUTHTYPE_EPPKE && + auth_data->trans == 3) ieee80211_mark_sta_auth(sdata); if (ifmgd->associated) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e0ccd9749853..30b9b4d76357 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -6,7 +6,7 @@ * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2025 Intel Corporation + * Copyright (C) 2018-2026 Intel Corporation */ #include <linux/jiffies.h> @@ -1137,14 +1137,14 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (is_multicast_ether_addr(hdr->addr1)) { if (ieee80211_has_tods(hdr->frame_control) || !ieee80211_has_fromds(hdr->frame_control)) - return RX_DROP; + return RX_DROP_U_MESH_DS_BITS; if (ether_addr_equal(hdr->addr3, dev_addr)) - return RX_DROP; + return RX_DROP_U_MESH_A3_MISMATCH; } else { if (!ieee80211_has_a4(hdr->frame_control)) - return RX_DROP; + return RX_DROP_U_MESH_NO_A4; if (ether_addr_equal(hdr->addr4, dev_addr)) - return RX_DROP; + return RX_DROP_U_MESH_A4_MISMATCH; } } @@ -1156,20 +1156,20 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) struct ieee80211_mgmt *mgmt; if (!ieee80211_is_mgmt(hdr->frame_control)) - return RX_DROP; + return RX_DROP_U_MESH_UNEXP_DATA; if (ieee80211_is_action(hdr->frame_control)) { u8 category; /* make sure category field is present */ if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) - return RX_DROP; + return RX_DROP_U_RUNT_ACTION; mgmt = (struct ieee80211_mgmt *)hdr; category = mgmt->u.action.category; if (category != WLAN_CATEGORY_MESH_ACTION && category != WLAN_CATEGORY_SELF_PROTECTED) - return RX_DROP; + return RX_DROP_U_MESH_WRONG_ACTION; return RX_CONTINUE; } @@ -1179,7 +1179,7 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) ieee80211_is_auth(hdr->frame_control)) return RX_CONTINUE; - return RX_DROP; + return RX_DROP_U_MESH_UNEXP_MGMT; } return RX_CONTINUE; @@ -1605,7 +1605,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) hdrlen = ieee80211_hdrlen(hdr->frame_control); if (rx->skb->len < hdrlen + 8) - return RX_DROP; + return RX_DROP_U_RUNT_DATA; skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2); if (ethertype == rx->sdata->control_port_protocol) @@ -1615,9 +1615,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) if (rx->sdata->vif.type == NL80211_IFTYPE_AP && cfg80211_rx_spurious_frame(rx->sdata->dev, hdr->addr2, rx->link_id, GFP_ATOMIC)) - return RX_DROP_U_SPURIOUS; + return RX_DROP_U_SPURIOUS_NOTIF; - return RX_DROP; + return RX_DROP_U_SPURIOUS; } return RX_CONTINUE; @@ -1880,7 +1880,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) link_sta->rx_stats.fragments++; u64_stats_update_begin(&link_sta->rx_stats.syncp); - link_sta->rx_stats.bytes += rx->skb->len; + u64_stats_add(&link_sta->rx_stats.bytes, rx->skb->len); u64_stats_update_end(&link_sta->rx_stats.syncp); if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { @@ -2106,7 +2106,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (rx->link_sta) { if (ieee80211_is_group_privacy_action(skb) && test_sta_flag(rx->sta, WLAN_STA_MFP)) - return RX_DROP; + return RX_DROP_U_UNPROTECTED; rx->key = rcu_dereference(rx->link_sta->gtk[mmie_keyidx]); } @@ -2191,11 +2191,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (rx->key) { if (unlikely(rx->key->flags & KEY_FLAG_TAINTED)) - return RX_DROP; + return RX_DROP_U_KEY_TAINTED; /* TODO: add threshold stuff again */ } else { - return RX_DROP; + return RX_DROP_U_UNPROTECTED; } switch (rx->key->conf.cipher) { @@ -2371,7 +2371,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) goto out; if (is_multicast_ether_addr(hdr->addr1)) - return RX_DROP; + return RX_DROP_U_MCAST_FRAGMENT; I802_DEBUG_INC(rx->local->rx_handlers_fragments); @@ -2426,7 +2426,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) rx->seqno_idx, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - return RX_DROP; + return RX_DROP_U_DEFRAG_MISMATCH; } /* "The receiver shall discard MSDUs and MMPDUs whose constituent @@ -2609,6 +2609,14 @@ ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC))) return RX_DROP_U_UNPROT_ROBUST_ACTION; + /* + * Drop unprotected (Re)Association Request/Response frame received from + * an EPP Peer. + */ + if (!ieee80211_has_protected(fc) && + ieee80211_require_encrypted_assoc(fc, rx->sta)) + return RX_DROP_U_UNPROT_UCAST_MGMT; + return RX_CONTINUE; } EXPORT_SYMBOL_IF_MAC80211_KUNIT(ieee80211_drop_unencrypted_mgmt); @@ -2777,7 +2785,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) * frame, so count MSDUs. */ u64_stats_update_begin(&rx->link_sta->rx_stats.syncp); - rx->link_sta->rx_stats.msdu[rx->seqno_idx]++; + u64_stats_inc(&rx->link_sta->rx_stats.msdu[rx->seqno_idx]); u64_stats_update_end(&rx->link_sta->rx_stats.syncp); } @@ -2948,25 +2956,25 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta return RX_CONTINUE; if (!pskb_may_pull(skb, sizeof(*eth) + 6)) - return RX_DROP; + return RX_DROP_U_RUNT_MESH_DATA; mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth)); mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr); if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen)) - return RX_DROP; + return RX_DROP_U_RUNT_MESH_DATA; eth = (struct ethhdr *)skb->data; multicast = is_multicast_ether_addr(eth->h_dest); mesh_hdr = (struct ieee80211s_hdr *)(eth + 1); if (!mesh_hdr->ttl) - return RX_DROP; + return RX_DROP_U_MESH_NO_TTL; /* frame is in RMC, don't forward */ if (is_multicast_ether_addr(eth->h_dest) && mesh_rmc_check(sdata, eth->h_source, mesh_hdr)) - return RX_DROP; + return RX_DROP_U_MESH_RMC; /* forward packet */ if (sdata->crypto_tx_tailroom_needed_cnt) @@ -2983,7 +2991,7 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta /* has_a4 already checked in ieee80211_rx_mesh_check */ proxied_addr = mesh_hdr->eaddr2; else - return RX_DROP; + return RX_DROP_U_MESH_BAD_AE; rcu_read_lock(); mppath = mpp_path_lookup(sdata, proxied_addr); @@ -3015,14 +3023,14 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta goto rx_accept; IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); - return RX_DROP; + return RX_DROP_U_MESH_TTL_EXPIRED; } if (!ifmsh->mshcfg.dot11MeshForwarding) { if (is_multicast_ether_addr(eth->h_dest)) goto rx_accept; - return RX_DROP; + return RX_DROP_U_MESH_NOT_FORWARDING; } skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]); @@ -3208,7 +3216,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (unlikely(!ieee80211_is_data_present(fc))) - return RX_DROP; + return RX_DROP_U_AMSDU_WITHOUT_DATA; if (unlikely(ieee80211_has_a4(hdr->frame_control))) { switch (rx->sdata->vif.type) { @@ -3265,7 +3273,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) - return RX_DROP; + return RX_DROP_U_NULL_DATA; /* Send unexpected-4addr-frame event to hostapd */ if (ieee80211_has_a4(hdr->frame_control) && @@ -3275,7 +3283,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) cfg80211_rx_unexpected_4addr_frame( rx->sdata->dev, rx->sta->sta.addr, rx->link_id, GFP_ATOMIC); - return RX_DROP; + return RX_DROP_U_UNEXPECTED_4ADDR; } res = __ieee80211_data_to_8023(rx, &port_control); @@ -3287,7 +3295,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) return res; if (!ieee80211_frame_allowed(rx, fc)) - return RX_DROP; + return RX_DROP_U_PORT_CONTROL; /* directly handle TDLS channel switch requests/responses */ if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto == @@ -3352,11 +3360,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) }; if (!rx->sta) - return RX_DROP; + return RX_DROP_U_UNKNOWN_STA; if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control), &bar_data, sizeof(bar_data))) - return RX_DROP; + return RX_DROP_U_RUNT_BAR; tid = le16_to_cpu(bar_data.control) >> 12; @@ -3368,7 +3376,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); if (!tid_agg_rx) - return RX_DROP; + return RX_DROP_U_BAR_OUTSIDE_SESSION; start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4; event.u.ba.tid = tid; @@ -3392,7 +3400,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) return RX_QUEUED; } - return RX_DROP; + return RX_DROP_U_CTRL_FRAME; } static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, @@ -3501,10 +3509,10 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) * and unknown (reserved) frames are useless. */ if (rx->skb->len < 24) - return RX_DROP; + return RX_DROP_U_RUNT_MGMT; if (!ieee80211_is_mgmt(mgmt->frame_control)) - return RX_DROP; + return RX_DROP_U_EXPECTED_MGMT; /* drop too small action frames */ if (ieee80211_is_action(mgmt->frame_control) && @@ -3514,7 +3522,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) /* Drop non-broadcast Beacon frames */ if (ieee80211_is_beacon(mgmt->frame_control) && !is_broadcast_ether_addr(mgmt->da)) - return RX_DROP; + return RX_DROP_U_NONBCAST_BEACON; if (rx->sdata->vif.type == NL80211_IFTYPE_AP && ieee80211_is_beacon(mgmt->frame_control) && @@ -4046,10 +4054,10 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) && (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) - return RX_DROP; + return RX_DROP_U_MALFORMED_ACTION; if (is_multicast_ether_addr(mgmt->da)) - return RX_DROP; + return RX_DROP_U_UNKNOWN_MCAST_ACTION; /* do not return rejected action frames */ if (mgmt->u.action.category & 0x80) @@ -4094,7 +4102,7 @@ ieee80211_rx_h_ext(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP; + return RX_DROP_U_UNEXPECTED_EXT_FRAME; /* for now only beacons are ext, so queue them */ ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb); @@ -4115,7 +4123,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) sdata->vif.type != NL80211_IFTYPE_ADHOC && sdata->vif.type != NL80211_IFTYPE_OCB && sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP; + return RX_DROP_U_UNHANDLED_MGMT; switch (stype) { case cpu_to_le16(IEEE80211_STYPE_AUTH): @@ -4126,32 +4134,32 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) case cpu_to_le16(IEEE80211_STYPE_DEAUTH): if (is_multicast_ether_addr(mgmt->da) && !is_broadcast_ether_addr(mgmt->da)) - return RX_DROP; + return RX_DROP_U_MCAST_DEAUTH; /* process only for station/IBSS */ if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_ADHOC) - return RX_DROP; + return RX_DROP_U_UNHANDLED_DEAUTH; break; case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): case cpu_to_le16(IEEE80211_STYPE_DISASSOC): if (is_multicast_ether_addr(mgmt->da) && !is_broadcast_ether_addr(mgmt->da)) - return RX_DROP; + return RX_DROP_U_MCAST_DISASSOC; /* process only for station */ if (sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP; + return RX_DROP_U_UNHANDLED_DISASSOC; break; case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): /* process only for ibss and mesh */ if (sdata->vif.type != NL80211_IFTYPE_ADHOC && sdata->vif.type != NL80211_IFTYPE_MESH_POINT) - return RX_DROP; + return RX_DROP_U_UNHANDLED_PREQ; break; default: - return RX_DROP; + return RX_DROP_U_UNHANDLED_MGMT_STYPE; } ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb); @@ -4179,7 +4187,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) { - ieee80211_rx_result res = RX_DROP; + ieee80211_rx_result res; struct sk_buff *skb; #define CALL_RXH(rxh) \ @@ -4205,8 +4213,10 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, */ rx->skb = skb; - if (WARN_ON_ONCE(!rx->link)) + if (WARN_ON_ONCE(!rx->link)) { + res = RX_DROP_U_NO_LINK; goto rxh_next; + } CALL_RXH(ieee80211_rx_h_check_more_data); CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll); @@ -4243,7 +4253,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) { struct sk_buff_head reorder_release; - ieee80211_rx_result res = RX_DROP; + ieee80211_rx_result res; __skb_queue_head_init(&reorder_release); @@ -4868,8 +4878,8 @@ static void ieee80211_rx_8023(struct ieee80211_rx_data *rx, * frame, so count MSDUs. */ u64_stats_update_begin(&stats->syncp); - stats->msdu[rx->seqno_idx]++; - stats->bytes += orig_len; + u64_stats_inc(&stats->msdu[rx->seqno_idx]); + u64_stats_add(&stats->bytes, orig_len); u64_stats_update_end(&stats->syncp); if (fast_rx->internal_forward) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1a995bc301b1..22e8561ad6fc 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -360,7 +360,9 @@ static void sta_accumulate_removed_link_stats(struct sta_info *sta, int link_id) struct link_sta_info *link_sta = wiphy_dereference(sta->local->hw.wiphy, sta->link[link_id]); struct ieee80211_link_data *link; + unsigned int start; int ac, tid; + u64 value; u32 thr; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { @@ -369,8 +371,13 @@ static void sta_accumulate_removed_link_stats(struct sta_info *sta, int link_id) sta->rem_link_stats.tx_bytes += link_sta->tx_stats.bytes[ac]; } + do { + start = u64_stats_fetch_begin(&link_sta->rx_stats.syncp); + value = u64_stats_read(&link_sta->rx_stats.bytes); + } while (u64_stats_fetch_retry(&link_sta->rx_stats.syncp, start)); + sta->rem_link_stats.rx_packets += link_sta->rx_stats.packets; - sta->rem_link_stats.rx_bytes += link_sta->rx_stats.bytes; + sta->rem_link_stats.rx_bytes += value; sta->rem_link_stats.tx_retries += link_sta->status_stats.retry_count; sta->rem_link_stats.tx_failed += link_sta->status_stats.retry_failed; sta->rem_link_stats.rx_dropped_misc += link_sta->rx_stats.dropped; @@ -380,8 +387,13 @@ static void sta_accumulate_removed_link_stats(struct sta_info *sta, int link_id) sta->rem_link_stats.expected_throughput += thr; for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { - sta->rem_link_stats.pertid_stats.rx_msdu += - link_sta->rx_stats.msdu[tid]; + do { + start = u64_stats_fetch_begin(&link_sta->rx_stats.syncp); + value = u64_stats_read(&link_sta->rx_stats.msdu[tid]); + } while (u64_stats_fetch_retry(&link_sta->rx_stats.syncp, + start)); + + sta->rem_link_stats.pertid_stats.rx_msdu += value; sta->rem_link_stats.pertid_stats.tx_msdu += link_sta->tx_stats.msdu[tid]; sta->rem_link_stats.pertid_stats.tx_msdu_retries += @@ -2578,7 +2590,7 @@ static inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats, do { start = u64_stats_fetch_begin(&rxstats->syncp); - value = rxstats->msdu[tid]; + value = u64_stats_read(&rxstats->msdu[tid]); } while (u64_stats_fetch_retry(&rxstats->syncp, start)); return value; @@ -2654,7 +2666,7 @@ static inline u64 sta_get_stats_bytes(struct ieee80211_sta_rx_stats *rxstats) do { start = u64_stats_fetch_begin(&rxstats->syncp); - value = rxstats->bytes; + value = u64_stats_read(&rxstats->bytes); } while (u64_stats_fetch_retry(&rxstats->syncp, start)); return value; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5288d5286651..b1edf8ed102f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -434,8 +434,8 @@ struct ieee80211_sta_rx_stats { s8 chain_signal_last[IEEE80211_MAX_CHAINS]; u32 last_rate; struct u64_stats_sync syncp; - u64 bytes; - u64 msdu[IEEE80211_NUM_TIDS + 1]; + u64_stats_t bytes; + u64_stats_t msdu[IEEE80211_NUM_TIDS + 1]; }; /* diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1b55e8340413..007f5a368d41 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -640,7 +640,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) if (!ieee80211_is_data_present(hdr->frame_control) && !ieee80211_use_mfp(hdr->frame_control, tx->sta, tx->skb) && - !ieee80211_is_group_privacy_action(tx->skb)) + !ieee80211_is_group_privacy_action(tx->skb) && + !ieee80211_require_encrypted_assoc(hdr->frame_control, + tx->sta)) tx->key = NULL; else skip_hw = (tx->key->conf.flags & diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7d7650c91f4f..4d5680da7aa0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1142,14 +1142,17 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, .ml.control = cpu_to_le16(IEEE80211_ML_CONTROL_TYPE_BASIC), .basic.len = sizeof(mle.basic), }; + bool add_mle; int err; - memcpy(mle.basic.mld_mac_addr, sdata->vif.addr, ETH_ALEN); + add_mle = (multi_link && + !cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK, + extra, extra_len)); /* 24 + 6 = header + auth_algo + auth_transaction + status_code */ skb = dev_alloc_skb(local->hw.extra_tx_headroom + IEEE80211_WEP_IV_LEN + 24 + 6 + extra_len + IEEE80211_WEP_ICV_LEN + - multi_link * sizeof(mle)); + add_mle * sizeof(mle)); if (!skb) return; @@ -1166,8 +1169,11 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, mgmt->u.auth.status_code = cpu_to_le16(status); if (extra) skb_put_data(skb, extra, extra_len); - if (multi_link) + + if (add_mle) { + memcpy(mle.basic.mld_mac_addr, sdata->vif.addr, ETH_ALEN); skb_put_data(skb, &mle, sizeof(mle)); + } if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 4a858112e4ef..fdf98c21d32c 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -527,7 +527,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, hdrlen = ieee80211_hdrlen(hdr->frame_control); if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_robust_mgmt_frame(skb)) + !ieee80211_is_robust_mgmt_frame(skb) && + !ieee80211_require_encrypted_assoc(hdr->frame_control, rx->sta)) return RX_CONTINUE; if (status->flag & RX_FLAG_DECRYPTED) { @@ -723,7 +724,8 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) hdrlen = ieee80211_hdrlen(hdr->frame_control); if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_robust_mgmt_frame(skb)) + !ieee80211_is_robust_mgmt_frame(skb) && + !ieee80211_require_encrypted_assoc(hdr->frame_control, rx->sta)) return RX_CONTINUE; if (status->flag & RX_FLAG_DECRYPTED) { diff --git a/net/wireless/core.c b/net/wireless/core.c index d0c7d9ff03b3..9af85d655027 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -265,6 +265,8 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, rdev_stop_nan(rdev, wdev); wdev->is_running = false; + eth_zero_addr(wdev->u.nan.cluster_id); + rdev->opencount--; } @@ -661,12 +663,8 @@ int wiphy_verify_iface_combinations(struct wiphy *wiphy, c->limits[j].max > 1)) return -EINVAL; - /* Only a single NAN can be allowed, avoid this - * check for multi-radio global combination, since it - * hold the capabilities of all radio combinations. - */ - if (!combined_radio && - WARN_ON(types & BIT(NL80211_IFTYPE_NAN) && + /* Only a single NAN can be allowed */ + if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) && c->limits[j].max > 1)) return -EINVAL; @@ -1416,8 +1414,10 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, cfg80211_leave_ocb(rdev, dev); break; case NL80211_IFTYPE_P2P_DEVICE: + cfg80211_stop_p2p_device(rdev, wdev); + break; case NL80211_IFTYPE_NAN: - /* cannot happen, has no netdev */ + cfg80211_stop_nan(rdev, wdev); break; case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MONITOR: diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bf3a1a617cc0..9aa83a6943a2 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5,7 +5,7 @@ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2025 Intel Corporation + * Copyright (C) 2018-2026 Intel Corporation */ #include <linux/if.h> @@ -361,6 +361,7 @@ nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = { [NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG }, [NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK] = { .type = NLA_FLAG }, [NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR] = { .type = NLA_U8 }, + [NL80211_PMSR_FTM_REQ_ATTR_RSTA] = { .type = NLA_FLAG }, }; static const struct nla_policy @@ -932,6 +933,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { NLA_POLICY_NESTED(nl80211_s1g_short_beacon), [NL80211_ATTR_BSS_PARAM] = { .type = NLA_FLAG }, [NL80211_ATTR_S1G_PRIMARY_2MHZ] = { .type = NLA_FLAG }, + [NL80211_ATTR_EPP_PEER] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -1678,7 +1680,9 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) return -ENOLINK; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - if (wdev->connected) + if (wdev->connected || + (wiphy_ext_feature_isset(wdev->wiphy, + NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION))) return 0; return -ENOLINK; case NL80211_IFTYPE_NAN: @@ -2310,6 +2314,32 @@ nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap, if (cap->ftm.non_trigger_based && nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED)) return -ENOBUFS; + if (cap->ftm.support_6ghz && + nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_6GHZ_SUPPORT)) + return -ENOBUFS; + if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_LTF_REP, + cap->ftm.max_tx_ltf_rep)) + return -ENOBUFS; + if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_LTF_REP, + cap->ftm.max_rx_ltf_rep)) + return -ENOBUFS; + if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_STS, + cap->ftm.max_tx_sts)) + return -ENOBUFS; + if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_STS, + cap->ftm.max_rx_sts)) + return -ENOBUFS; + if (cap->ftm.max_total_ltf_tx > 0 && + nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_TX, + cap->ftm.max_total_ltf_tx)) + return -ENOBUFS; + if (cap->ftm.max_total_ltf_rx > 0 && + nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_RX, + cap->ftm.max_total_ltf_rx)) + return -ENOBUFS; + if (cap->ftm.support_rsta && + nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_RSTA_SUPPORT)) + return -ENOBUFS; nla_nest_end(msg, ftm); return 0; @@ -6473,6 +6503,10 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, auth_type == NL80211_AUTHTYPE_FILS_SK_PFS || auth_type == NL80211_AUTHTYPE_FILS_PK)) return false; + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_EPPKE) && + auth_type == NL80211_AUTHTYPE_EPPKE) + return false; return true; case NL80211_CMD_CONNECT: if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) && @@ -6490,6 +6524,10 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) && auth_type == NL80211_AUTHTYPE_FILS_SK) return false; + if (!wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_EPPKE) && + auth_type == NL80211_AUTHTYPE_EPPKE) + return false; return true; case NL80211_CMD_START_AP: if (!wiphy_ext_feature_isset(&rdev->wiphy, @@ -8782,6 +8820,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) goto out; } } + + params.epp_peer = + nla_get_flag(info->attrs[NL80211_ATTR_EPP_PEER]); + err = rdev_add_station(rdev, dev, mac_addr, ¶ms); out: dev_put(params.vlan); @@ -11956,7 +11998,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) if ((auth_type == NL80211_AUTHTYPE_SAE || auth_type == NL80211_AUTHTYPE_FILS_SK || auth_type == NL80211_AUTHTYPE_FILS_SK_PFS || - auth_type == NL80211_AUTHTYPE_FILS_PK) && + auth_type == NL80211_AUTHTYPE_FILS_PK || + auth_type == NL80211_AUTHTYPE_EPPKE) && !info->attrs[NL80211_ATTR_AUTH_DATA]) return -EINVAL; @@ -11964,7 +12007,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) if (auth_type != NL80211_AUTHTYPE_SAE && auth_type != NL80211_AUTHTYPE_FILS_SK && auth_type != NL80211_AUTHTYPE_FILS_SK_PFS && - auth_type != NL80211_AUTHTYPE_FILS_PK) + auth_type != NL80211_AUTHTYPE_FILS_PK && + auth_type != NL80211_AUTHTYPE_EPPKE) return -EINVAL; req.auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]); req.auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]); @@ -15556,7 +15600,8 @@ static int nl80211_parse_nan_band_config(struct wiphy *wiphy, static int nl80211_parse_nan_conf(struct wiphy *wiphy, struct genl_info *info, struct cfg80211_nan_conf *conf, - u32 *changed_flags) + u32 *changed_flags, + bool start) { struct nlattr *attrs[NL80211_NAN_CONF_ATTR_MAX + 1]; int err, rem; @@ -15603,7 +15648,7 @@ static int nl80211_parse_nan_conf(struct wiphy *wiphy, return err; changed |= CFG80211_NAN_CONF_CHANGED_CONFIG; - if (attrs[NL80211_NAN_CONF_CLUSTER_ID]) + if (attrs[NL80211_NAN_CONF_CLUSTER_ID] && start) conf->cluster_id = nla_data(attrs[NL80211_NAN_CONF_CLUSTER_ID]); @@ -15714,7 +15759,7 @@ static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) return -EINVAL; - err = nl80211_parse_nan_conf(&rdev->wiphy, info, &conf, NULL); + err = nl80211_parse_nan_conf(&rdev->wiphy, info, &conf, NULL, true); if (err) return err; @@ -16080,7 +16125,7 @@ static int nl80211_nan_change_config(struct sk_buff *skb, if (!wdev_running(wdev)) return -ENOTCONN; - err = nl80211_parse_nan_conf(&rdev->wiphy, info, &conf, &changed); + err = nl80211_parse_nan_conf(&rdev->wiphy, info, &conf, &changed, false); if (err) return err; @@ -16099,6 +16144,9 @@ void cfg80211_nan_match(struct wireless_dev *wdev, struct sk_buff *msg; void *hdr; + if (WARN_ON(wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE)) + return; + if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr)) return; @@ -16181,6 +16229,9 @@ void cfg80211_nan_func_terminated(struct wireless_dev *wdev, struct nlattr *func_attr; void *hdr; + if (WARN_ON(wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE)) + return; + if (WARN_ON(!inst_id)) return; diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c index a117f5093ca2..60e1e31c2185 100644 --- a/net/wireless/pmsr.c +++ b/net/wireless/pmsr.c @@ -85,11 +85,6 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, return -EINVAL; } - out->ftm.burst_duration = 15; - if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]) - out->ftm.burst_duration = - nla_get_u8(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]); - out->ftm.ftms_per_burst = 0; if (tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]) out->ftm.ftms_per_burst = @@ -164,6 +159,12 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, return -EINVAL; } + if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]) + out->ftm.burst_duration = + nla_get_u8(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]); + else if (!out->ftm.non_trigger_based && !out->ftm.trigger_based) + out->ftm.burst_duration = 15; + out->ftm.lmr_feedback = !!tb[NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK]; if (!out->ftm.trigger_based && !out->ftm.non_trigger_based && @@ -186,6 +187,21 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, nla_get_u8(tb[NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR]); } + out->ftm.rsta = !!tb[NL80211_PMSR_FTM_REQ_ATTR_RSTA]; + if (out->ftm.rsta && !capa->ftm.support_rsta) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[NL80211_PMSR_FTM_REQ_ATTR_RSTA], + "FTM: RSTA not supported by device"); + return -EOPNOTSUPP; + } + + if (out->ftm.rsta && !out->ftm.lmr_feedback) { + NL_SET_ERR_MSG_ATTR(info->extack, + tb[NL80211_PMSR_FTM_REQ_ATTR_RSTA], + "FTM: RSTA set without LMR feedback"); + return -EINVAL; + } + return 0; } @@ -453,6 +469,7 @@ static int nl80211_pmsr_send_ftm_res(struct sk_buff *msg, PUT(u8, NUM_BURSTS_EXP, num_bursts_exp); PUT(u8, BURST_DURATION, burst_duration); PUT(u8, FTMS_PER_BURST, ftms_per_burst); + PUT(u16, BURST_PERIOD, burst_period); PUTOPT(s32, RSSI_AVG, rssi_avg); PUTOPT(s32, RSSI_SPREAD, rssi_spread); if (res->ftm.tx_rate_valid && diff --git a/net/wireless/reg.c b/net/wireless/reg.c index a8ab0ab22d90..6cbfa3b78311 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2332,8 +2332,17 @@ static void reg_process_ht_flags(struct wiphy *wiphy) if (!wiphy) return; - for (band = 0; band < NUM_NL80211_BANDS; band++) + for (band = 0; band < NUM_NL80211_BANDS; band++) { + /* + * Don't apply HT flags to channels within the S1G band. + * Each bonded channel will instead be validated individually + * within cfg80211_s1g_usable(). + */ + if (band == NL80211_BAND_S1GHZ) + continue; + reg_process_ht_flags_band(wiphy, wiphy->bands[band]); + } } static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) |
