summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-01-30 06:17:42 +0300
committerJakub Kicinski <kuba@kernel.org>2026-01-30 06:17:43 +0300
commit303c1a66a22068517793284524dd1d24b7316d1b (patch)
tree6610d11e4b386449668edb50dff882d63d08ac02
parent6f1769ec5892ac41d82e820d94dcdc68e904aa99 (diff)
parentc30e188bd2a886258be5facb970a804d8ef549b5 (diff)
downloadlinux-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>
-rw-r--r--Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml9
-rw-r--r--drivers/mmc/core/sdio_bus.c25
-rw-r--r--drivers/net/wireless/ath/ath11k/Kconfig11
-rw-r--r--drivers/net/wireless/ath/ath11k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath11k/cfr.c1023
-rw-r--r--drivers/net/wireless/ath/ath11k/cfr.h308
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c81
-rw-r--r--drivers/net/wireless/ath/ath11k/core.h19
-rw-r--r--drivers/net/wireless/ath/ath11k/dbring.c50
-rw-r--r--drivers/net/wireless/ath/ath11k/dbring.h8
-rw-r--r--drivers/net/wireless/ath/ath11k/debug.h8
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_sta.c142
-rw-r--r--drivers/net/wireless/ath/ath11k/dp.c12
-rw-r--r--drivers/net/wireless/ath/ath11k/dp.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_tx.c9
-rw-r--r--drivers/net/wireless/ath/ath11k/hal.c3
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.c19
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.h8
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c23
-rw-r--r--drivers/net/wireless/ath/ath11k/reg.c9
-rw-r--r--drivers/net/wireless/ath/ath11k/wmi.c147
-rw-r--r--drivers/net/wireless/ath/ath11k/wmi.h97
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/fw.c10
-rw-r--r--drivers/net/wireless/ath/ath12k/fw.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/hal.c46
-rw-r--r--drivers/net/wireless/ath/ath12k/hal.h34
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/pci.c18
-rw-r--r--drivers/net/wireless/ath/ath12k/pci.h7
-rw-r--r--drivers/net/wireless/ath/ath12k/qmi.c180
-rw-r--r--drivers/net/wireless/ath/ath12k/qmi.h16
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/Makefile3
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c62
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/dp_rx.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal.c8
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_desc.h33
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.c503
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_qcc2072.h13
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c8
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_rx.c97
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_rx.h30
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_rx_desc.h17
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.c8
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_wcn7850.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hw.c101
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/pci.c26
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/wmi.c5
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c54
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.h7
-rw-r--r--drivers/net/wireless/ath/ath12k/wow.c16
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath9k/common-debug.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h15
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h33
-rw-r--r--drivers/net/wireless/intel/iwlegacy/3945-mac.c2
-rw-r--r--drivers/net/wireless/intel/iwlegacy/4965-mac.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/bz.c12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c117
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h159
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h34
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/power.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/rs.h41
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/rx.h95
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/regulatory.c206
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/regulatory.h9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/runtime.h17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/smem.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/uefi.c72
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/uefi.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-config.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/Makefile2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/d3.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/debugfs.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/iface.c21
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/iface.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mac80211.c114
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mld.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mld.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mlo.c59
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mlo.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/nan.c299
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/nan.h28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/notif.c13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/notif.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/power.c37
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/regulatory.c66
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/rx.c142
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/scan.c12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/sta.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/tlc.c85
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/tx.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c51
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c202
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/link.c22
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c68
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c29
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c193
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h60
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c18
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tdls.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c39
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c51
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c4
-rw-r--r--drivers/net/wireless/intersil/p54/main.c4
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/core.c1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/regd.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c54
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h2
-rw-r--r--drivers/net/wireless/realtek/rtw88/phy.c20
-rw-r--r--drivers/net/wireless/realtek/rtw88/phy.h2
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8723cs.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8723ds.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821cs.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821cu.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822b.c3
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822bs.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822cs.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/sdio.c3
-rw-r--r--drivers/net/wireless/realtek/rtw88/sdio.h2
-rw-r--r--drivers/net/wireless/realtek/rtw89/cam.c134
-rw-r--r--drivers/net/wireless/realtek/rtw89/cam.h129
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.c38
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.h2
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.c237
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.h158
-rw-r--r--drivers/net/wireless/realtek/rtw89/debug.c79
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse.h6
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse_be.c26
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c866
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.h333
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.c176
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.h79
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c40
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac_be.c675
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci.c7
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci.h56
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci_be.c136
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.c47
-rw-r--r--drivers/net/wireless/realtek/rtw89/ps.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/reg.h566
-rw-r--r--drivers/net/wireless/realtek/rtw89/regd.c1
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8851b.c9
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852a.c9
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852au.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852b.c31
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852b_common.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852bt.c7
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852bu.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852c.c9
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922a.c31
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c48
-rw-r--r--drivers/net/wireless/realtek/rtw89/ser.c10
-rw-r--r--drivers/net/wireless/realtek/rtw89/txrx.h22
-rw-r--r--drivers/net/wireless/realtek/rtw89/usb.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/wow.c8
-rw-r--r--drivers/net/wireless/realtek/rtw89/wow.h1
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio.c5
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.h1
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c9
-rw-r--r--include/linux/ieee80211.h1
-rw-r--r--include/linux/mmc/sdio_func.h1
-rw-r--r--include/net/cfg80211.h37
-rw-r--r--include/net/mac80211.h2
-rw-r--r--include/uapi/linux/nl80211.h73
-rw-r--r--net/mac80211/cfg.c15
-rw-r--r--net/mac80211/drop.h46
-rw-r--r--net/mac80211/ieee80211_i.h10
-rw-r--r--net/mac80211/iface.c6
-rw-r--r--net/mac80211/mlme.c47
-rw-r--r--net/mac80211/rx.c114
-rw-r--r--net/mac80211/sta_info.c22
-rw-r--r--net/mac80211/sta_info.h4
-rw-r--r--net/mac80211/tx.c4
-rw-r--r--net/mac80211/util.c12
-rw-r--r--net/mac80211/wpa.c6
-rw-r--r--net/wireless/core.c14
-rw-r--r--net/wireless/nl80211.c67
-rw-r--r--net/wireless/pmsr.c27
-rw-r--r--net/wireless/reg.c11
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, &param);
- 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, &param);
+ 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, &param);
+ 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,
+ &params);
+ if (ret) {
+ ath11k_warn(ab, "failed to parse cfr capture event tlv %d\n",
+ ret);
+ return;
+ }
+
+ ret = ath11k_process_cfr_capture_event(ab, &params);
+ 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(&params, 0, sizeof(params));
+
+ entry_size = ath12k_hal_srng_get_entrysize(ab, HAL_REO_CMD);
+ ath12k_hal_srng_get_params(ab, srng, &params);
+ 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, &params, 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, &params);
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 = &param->prec_cfg;
struct rtw89_hfc_pub_cfg *pub_cfg = &param->pub_cfg;
struct rtw89_hfc_pub_info *info = &param->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 = &param->prec_cfg;
const struct rtw89_hfc_pub_cfg *pub_cfg = &param->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, &ethertype, 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, &params);
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)