summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-04-12 09:17:42 -0700
committerJakub Kicinski <kuba@kernel.org>2026-04-12 09:17:42 -0700
commit118cbd428e434bc1b8aac92a74b4992c7683f0fe (patch)
tree7cf20aa1d8f39ab70241a91cace924e5eadacefb
parent29703d7813f991e4ef80741ee15fe30e529a2192 (diff)
parentfa489a77e3267e05df95db96ba98e141ec07cbd9 (diff)
Merge tag 'wireless-next-2026-04-10' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Johannes Berg says: ==================== Final updates, notably: - crypto: move Michael MIC code into wireless (only) - mac80211: - multi-link 4-addr support - NAN data support (but no drivers yet) - ath10k: DT quirk to make it work on some devices - ath12k: IPQ5424 support - rtw89: USB improvements for performance * tag 'wireless-next-2026-04-10' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (124 commits) wifi: cfg80211: Explicitly include <linux/export.h> in michael-mic.c wifi: ath10k: Add device-tree quirk to skip host cap QMI requests dt-bindings: wireless: ath10k: Add quirk to skip host cap QMI requests crypto: Remove michael_mic from crypto_shash API wifi: ipw2x00: Use michael_mic() from cfg80211 wifi: ath12k: Use michael_mic() from cfg80211 wifi: ath11k: Use michael_mic() from cfg80211 wifi: mac80211, cfg80211: Export michael_mic() and move it to cfg80211 wifi: ipw2x00: Rename michael_mic() to libipw_michael_mic() wifi: libertas_tf: refactor endpoint lookup wifi: libertas: refactor endpoint lookup wifi: at76c50x: refactor endpoint lookup wifi: ath12k: Enable IPQ5424 WiFi device support wifi: ath12k: Add CE remap hardware parameters for IPQ5424 wifi: ath12k: add ath12k_hw_regs for IPQ5424 wifi: ath12k: add ath12k_hw_version_map entry for IPQ5424 wifi: ath12k: Add ath12k_hw_params for IPQ5424 dt-bindings: net: wireless: add ath12k wifi device IPQ5424 wifi: ath10k: fix station lookup failure during disconnect wifi: ath12k: Create symlink for each radio in a wiphy ... ==================== Link: https://patch.msgid.link/20260410064703.735099-3-johannes@sipsolutions.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml1
-rw-r--r--Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml11
-rw-r--r--Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml1
-rw-r--r--arch/arm/configs/omap2plus_defconfig1
-rw-r--r--arch/arm/configs/spitz_defconfig1
-rw-r--r--arch/arm64/configs/defconfig1
-rw-r--r--arch/m68k/configs/amiga_defconfig1
-rw-r--r--arch/m68k/configs/apollo_defconfig1
-rw-r--r--arch/m68k/configs/atari_defconfig1
-rw-r--r--arch/m68k/configs/bvme6000_defconfig1
-rw-r--r--arch/m68k/configs/hp300_defconfig1
-rw-r--r--arch/m68k/configs/mac_defconfig1
-rw-r--r--arch/m68k/configs/multi_defconfig1
-rw-r--r--arch/m68k/configs/mvme147_defconfig1
-rw-r--r--arch/m68k/configs/mvme16x_defconfig1
-rw-r--r--arch/m68k/configs/q40_defconfig1
-rw-r--r--arch/m68k/configs/sun3_defconfig1
-rw-r--r--arch/m68k/configs/sun3x_defconfig1
-rw-r--r--arch/mips/configs/bigsur_defconfig1
-rw-r--r--arch/mips/configs/decstation_64_defconfig1
-rw-r--r--arch/mips/configs/decstation_defconfig1
-rw-r--r--arch/mips/configs/decstation_r4k_defconfig1
-rw-r--r--arch/mips/configs/gpr_defconfig1
-rw-r--r--arch/mips/configs/ip32_defconfig1
-rw-r--r--arch/mips/configs/lemote2f_defconfig1
-rw-r--r--arch/mips/configs/malta_qemu_32r6_defconfig1
-rw-r--r--arch/mips/configs/maltaaprp_defconfig1
-rw-r--r--arch/mips/configs/maltasmvp_defconfig1
-rw-r--r--arch/mips/configs/maltasmvp_eva_defconfig1
-rw-r--r--arch/mips/configs/maltaup_defconfig1
-rw-r--r--arch/mips/configs/mtx1_defconfig1
-rw-r--r--arch/mips/configs/rm200_defconfig1
-rw-r--r--arch/mips/configs/sb1250_swarm_defconfig1
-rw-r--r--arch/parisc/configs/generic-32bit_defconfig1
-rw-r--r--arch/parisc/configs/generic-64bit_defconfig1
-rw-r--r--arch/powerpc/configs/g5_defconfig1
-rw-r--r--arch/powerpc/configs/linkstation_defconfig1
-rw-r--r--arch/powerpc/configs/mvme5100_defconfig1
-rw-r--r--arch/powerpc/configs/powernv_defconfig1
-rw-r--r--arch/powerpc/configs/ppc64_defconfig1
-rw-r--r--arch/powerpc/configs/ppc64e_defconfig1
-rw-r--r--arch/powerpc/configs/ppc6xx_defconfig1
-rw-r--r--arch/powerpc/configs/ps3_defconfig1
-rw-r--r--arch/s390/configs/debug_defconfig1
-rw-r--r--arch/s390/configs/defconfig1
-rw-r--r--arch/sh/configs/sh2007_defconfig1
-rw-r--r--arch/sh/configs/titan_defconfig1
-rw-r--r--arch/sh/configs/ul2_defconfig1
-rw-r--r--arch/sparc/configs/sparc32_defconfig1
-rw-r--r--arch/sparc/configs/sparc64_defconfig1
-rw-r--r--crypto/Kconfig12
-rw-r--r--crypto/Makefile1
-rw-r--r--crypto/michael_mic.c176
-rw-r--r--crypto/tcrypt.c4
-rw-r--r--crypto/testmgr.c6
-rw-r--r--crypto/testmgr.h50
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c13
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c26
-rw-r--r--drivers/net/wireless/ath/ath11k/Kconfig1
-rw-r--r--drivers/net/wireless/ath/ath11k/dp.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_rx.c60
-rw-r--r--drivers/net/wireless/ath/ath11k/peer.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/Kconfig1
-rw-r--r--drivers/net/wireless/ath/ath12k/ahb.c36
-rw-r--r--drivers/net/wireless/ath/ath12k/ahb.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/ce.h13
-rw-r--r--drivers/net/wireless/ath/ath12k/core.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h13
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs.c29
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c72
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h26
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_peer.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.c55
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/ahb.c8
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c7
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal.c7
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c88
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hw.c97
-rw-r--r--drivers/net/wireless/atmel/at76c50x-usb.c22
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c15
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c17
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c4
-rw-r--r--drivers/net/wireless/intel/ipw2x00/Kconfig1
-rw-r--r--drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c120
-rw-r--r--drivers/net/wireless/intel/iwlegacy/3945-mac.c7
-rw-r--r--drivers/net/wireless/marvell/libertas/if_usb.c33
-rw-r--r--drivers/net/wireless/marvell/libertas_tf/if_usb.c46
-rw-r--r--drivers/net/wireless/microchip/wilc1000/hif.c8
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c4
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/core.c40
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/pci.c1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192d/fw_common.c12
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/usb.c4
-rw-r--r--drivers/net/wireless/realtek/rtw88/coex.c47
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c6
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h6
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.c34
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8703b.c5
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8723d.c5
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821a.c7
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821c.c7
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822b.c5
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.c5
-rw-r--r--drivers/net/wireless/realtek/rtw88/rx.c8
-rw-r--r--drivers/net/wireless/realtek/rtw88/tx.c2
-rw-r--r--drivers/net/wireless/realtek/rtw88/usb.c3
-rw-r--r--drivers/net/wireless/realtek/rtw89/chan.c72
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.c155
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.h105
-rw-r--r--drivers/net/wireless/realtek/rtw89/debug.c53
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse.c23
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c159
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.h134
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.c69
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.h34
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c11
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac_be.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci.h7
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci_be.c104
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.c71
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.h5
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy_be.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/ps.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/reg.h287
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8851b.c49
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8851bu.c1
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852a.c68
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852a_table.c51
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852a_table.h1
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852au.c1
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852b.c41
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852bt.c15
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852bu.c1
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852c.c17
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852cu.c7
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922a.c18
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922d.c3093
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922d.h83
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c372
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h22
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922de.c119
-rw-r--r--drivers/net/wireless/realtek/rtw89/ser.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/usb.c107
-rw-r--r--drivers/net/wireless/realtek/rtw89/usb.h15
-rw-r--r--drivers/net/wireless/realtek/rtw89/util.h17
-rw-r--r--drivers/net/wireless/realtek/rtw89/wow.c2
-rw-r--r--drivers/net/wireless/realtek/rtw89/wow.h7
-rw-r--r--include/linux/ieee80211-nan.h37
-rw-r--r--include/linux/ieee80211.h6
-rw-r--r--include/net/mac80211.h157
-rw-r--r--net/mac80211/Makefile3
-rw-r--r--net/mac80211/agg-tx.c3
-rw-r--r--net/mac80211/cfg.c269
-rw-r--r--net/mac80211/chan.c140
-rw-r--r--net/mac80211/driver-ops.h21
-rw-r--r--net/mac80211/he.c7
-rw-r--r--net/mac80211/ht.c19
-rw-r--r--net/mac80211/ibss.c2
-rw-r--r--net/mac80211/ieee80211_i.h52
-rw-r--r--net/mac80211/iface.c111
-rw-r--r--net/mac80211/link.c43
-rw-r--r--net/mac80211/main.c4
-rw-r--r--net/mac80211/mesh_sync.c2
-rw-r--r--net/mac80211/michael.h22
-rw-r--r--net/mac80211/mlme.c11
-rw-r--r--net/mac80211/nan.c710
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c15
-rw-r--r--net/mac80211/rx.c61
-rw-r--r--net/mac80211/scan.c2
-rw-r--r--net/mac80211/sta_info.c29
-rw-r--r--net/mac80211/sta_info.h3
-rw-r--r--net/mac80211/trace.h31
-rw-r--r--net/mac80211/tx.c52
-rw-r--r--net/mac80211/util.c146
-rw-r--r--net/mac80211/vht.c16
-rw-r--r--net/mac80211/wpa.c1
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/michael-mic.c (renamed from net/mac80211/michael.c)6
185 files changed, 7456 insertions, 1295 deletions
diff --git a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
index 3be757678764..81fd3e37452a 100644
--- a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml
@@ -42,6 +42,7 @@ properties:
- brcm,bcm4356-fmac
- brcm,bcm4359-fmac
- brcm,bcm4366-fmac
+ - brcm,bcm43752-fmac
- cypress,cyw4373-fmac
- cypress,cyw43012-fmac
- infineon,cyw43439-fmac
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
index f2440d39b7eb..c21d66c7cd55 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml
@@ -171,6 +171,12 @@ properties:
Quirk specifying that the firmware expects the 8bit version
of the host capability QMI request
+ qcom,snoc-host-cap-skip-quirk:
+ type: boolean
+ description:
+ Quirk specifying that the firmware wants to skip the host
+ capability QMI request
+
qcom,xo-cal-data:
$ref: /schemas/types.yaml#/definitions/uint32
description:
@@ -292,6 +298,11 @@ allOf:
required:
- interrupts
+ - not:
+ required:
+ - qcom,snoc-host-cap-8bit-quirk
+ - qcom,snoc-host-cap-skip-quirk
+
examples:
# SNoC
- |
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml
index 363a0ecb6ad9..37d8a0da7780 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ipq5332-wifi.yaml
@@ -17,6 +17,7 @@ properties:
compatible:
enum:
- qcom,ipq5332-wifi
+ - qcom,ipq5424-wifi
reg:
maxItems: 1
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 0464f6552169..ae2883d3ff0e 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -704,7 +704,6 @@ CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_SECURITY=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
CONFIG_CRYPTO_GHASH_ARM_CE=m
CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_AES_ARM_BS=m
diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig
index c130af6d44d4..f116a01c3f5f 100644
--- a/arch/arm/configs/spitz_defconfig
+++ b/arch/arm/configs/spitz_defconfig
@@ -230,7 +230,6 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_FONTS=y
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 0651a771f5c1..8b2343048465 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1914,7 +1914,6 @@ CONFIG_CRYPTO_USER=y
CONFIG_CRYPTO_CHACHA20=m
CONFIG_CRYPTO_BENCHMARK=m
CONFIG_CRYPTO_ECHAINIV=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA3=m
CONFIG_CRYPTO_USER_API_RNG=m
CONFIG_CRYPTO_GHASH_ARM64_CE=y
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
index c8b936bb702f..510e16f25318 100644
--- a/arch/m68k/configs/amiga_defconfig
+++ b/arch/m68k/configs/amiga_defconfig
@@ -538,7 +538,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
index fc1792495bbc..d1d8f02b4d96 100644
--- a/arch/m68k/configs/apollo_defconfig
+++ b/arch/m68k/configs/apollo_defconfig
@@ -495,7 +495,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
index e440c596e60b..2e207af4add2 100644
--- a/arch/m68k/configs/atari_defconfig
+++ b/arch/m68k/configs/atari_defconfig
@@ -515,7 +515,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
index 7aa352d14363..d75465289898 100644
--- a/arch/m68k/configs/bvme6000_defconfig
+++ b/arch/m68k/configs/bvme6000_defconfig
@@ -487,7 +487,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
index 0baaf2a82c61..c2011a749e10 100644
--- a/arch/m68k/configs/hp300_defconfig
+++ b/arch/m68k/configs/hp300_defconfig
@@ -497,7 +497,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index 0cbbfe5aeaec..e377443c56d4 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -514,7 +514,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index 2b96f90e1a4d..cdd0449f7141 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -601,7 +601,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
index b49264cec911..4e78ff8d793e 100644
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -487,7 +487,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
index 96a974b0a766..9fc30a3236e1 100644
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -488,7 +488,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
index e53361584393..c3b5fdabfe16 100644
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -504,7 +504,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
index af89287c1093..ea40f990eb22 100644
--- a/arch/m68k/configs/sun3_defconfig
+++ b/arch/m68k/configs/sun3_defconfig
@@ -485,7 +485,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
index af210e8b77f9..e20b6a9d26cd 100644
--- a/arch/m68k/configs/sun3x_defconfig
+++ b/arch/m68k/configs/sun3x_defconfig
@@ -485,7 +485,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_AEGIS128=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index 349e9e0b4f54..3b64e151e187 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -222,7 +222,6 @@ CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
diff --git a/arch/mips/configs/decstation_64_defconfig b/arch/mips/configs/decstation_64_defconfig
index dad98c575292..7c43352fac6b 100644
--- a/arch/mips/configs/decstation_64_defconfig
+++ b/arch/mips/configs/decstation_64_defconfig
@@ -180,7 +180,6 @@ CONFIG_CRYPTO_CMAC=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig
index 4e1b51a4ad90..aee10274f048 100644
--- a/arch/mips/configs/decstation_defconfig
+++ b/arch/mips/configs/decstation_defconfig
@@ -175,7 +175,6 @@ CONFIG_CRYPTO_CMAC=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
diff --git a/arch/mips/configs/decstation_r4k_defconfig b/arch/mips/configs/decstation_r4k_defconfig
index 4e550dffc23d..a1698049aa7a 100644
--- a/arch/mips/configs/decstation_r4k_defconfig
+++ b/arch/mips/configs/decstation_r4k_defconfig
@@ -175,7 +175,6 @@ CONFIG_CRYPTO_CMAC=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig
index 437ef6dc0b4c..fdd28a89e336 100644
--- a/arch/mips/configs/gpr_defconfig
+++ b/arch/mips/configs/gpr_defconfig
@@ -275,7 +275,6 @@ CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_BENCHMARK=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig
index 7568838eb08b..68558d0d3f52 100644
--- a/arch/mips/configs/ip32_defconfig
+++ b/arch/mips/configs/ip32_defconfig
@@ -159,7 +159,6 @@ CONFIG_CRYPTO_PCBC=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig
index 8d3f20ed19b5..eb3565a3f292 100644
--- a/arch/mips/configs/lemote2f_defconfig
+++ b/arch/mips/configs/lemote2f_defconfig
@@ -308,7 +308,6 @@ CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_WP512=m
diff --git a/arch/mips/configs/malta_qemu_32r6_defconfig b/arch/mips/configs/malta_qemu_32r6_defconfig
index dafc9a716e85..520ee73d0b27 100644
--- a/arch/mips/configs/malta_qemu_32r6_defconfig
+++ b/arch/mips/configs/malta_qemu_32r6_defconfig
@@ -166,7 +166,6 @@ CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/mips/configs/maltaaprp_defconfig b/arch/mips/configs/maltaaprp_defconfig
index 7361bca6a405..0a3951df2ebb 100644
--- a/arch/mips/configs/maltaaprp_defconfig
+++ b/arch/mips/configs/maltaaprp_defconfig
@@ -167,7 +167,6 @@ CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/mips/configs/maltasmvp_defconfig b/arch/mips/configs/maltasmvp_defconfig
index c848a1bfca5c..9a83b75f7c1b 100644
--- a/arch/mips/configs/maltasmvp_defconfig
+++ b/arch/mips/configs/maltasmvp_defconfig
@@ -168,7 +168,6 @@ CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig
index 905248e01b95..8fa0f3985dcb 100644
--- a/arch/mips/configs/maltasmvp_eva_defconfig
+++ b/arch/mips/configs/maltasmvp_eva_defconfig
@@ -170,7 +170,6 @@ CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/mips/configs/maltaup_defconfig b/arch/mips/configs/maltaup_defconfig
index b9bbe02f3595..518635a22fb3 100644
--- a/arch/mips/configs/maltaup_defconfig
+++ b/arch/mips/configs/maltaup_defconfig
@@ -166,7 +166,6 @@ CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index 2428a6a72747..72568f8ae653 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -662,7 +662,6 @@ CONFIG_CRYPTO_BENCHMARK=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index b507dc4dddd4..b1e67ff0c4f0 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -382,7 +382,6 @@ CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/mips/configs/sb1250_swarm_defconfig b/arch/mips/configs/sb1250_swarm_defconfig
index ae2afff00e01..4a25b8d3e507 100644
--- a/arch/mips/configs/sb1250_swarm_defconfig
+++ b/arch/mips/configs/sb1250_swarm_defconfig
@@ -85,7 +85,6 @@ CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/parisc/configs/generic-32bit_defconfig b/arch/parisc/configs/generic-32bit_defconfig
index ad2fb69184f3..3572a32f7849 100644
--- a/arch/parisc/configs/generic-32bit_defconfig
+++ b/arch/parisc/configs/generic-32bit_defconfig
@@ -258,7 +258,6 @@ CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_DEFLATE=y
diff --git a/arch/parisc/configs/generic-64bit_defconfig b/arch/parisc/configs/generic-64bit_defconfig
index b21287a9250c..0c4d54df9cf0 100644
--- a/arch/parisc/configs/generic-64bit_defconfig
+++ b/arch/parisc/configs/generic-64bit_defconfig
@@ -286,7 +286,6 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_DEFLATE=m
# CONFIG_CRYPTO_HW is not set
CONFIG_PRINTK_TIME=y
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 4247d9a30eba..04bbb37f5978 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -236,7 +236,6 @@ CONFIG_BOOTX_TEXT=y
CONFIG_CRYPTO_BENCHMARK=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
diff --git a/arch/powerpc/configs/linkstation_defconfig b/arch/powerpc/configs/linkstation_defconfig
index b564f9e33a0d..31f84d08b6ef 100644
--- a/arch/powerpc/configs/linkstation_defconfig
+++ b/arch/powerpc/configs/linkstation_defconfig
@@ -129,7 +129,6 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_SERPENT=m
diff --git a/arch/powerpc/configs/mvme5100_defconfig b/arch/powerpc/configs/mvme5100_defconfig
index fa2b3b9c5945..c82754c14e15 100644
--- a/arch/powerpc/configs/mvme5100_defconfig
+++ b/arch/powerpc/configs/mvme5100_defconfig
@@ -115,7 +115,6 @@ CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=20
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA1=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_DES=y
diff --git a/arch/powerpc/configs/powernv_defconfig b/arch/powerpc/configs/powernv_defconfig
index ce72c6d22ca2..cc9802420237 100644
--- a/arch/powerpc/configs/powernv_defconfig
+++ b/arch/powerpc/configs/powernv_defconfig
@@ -317,7 +317,6 @@ CONFIG_XMON=y
CONFIG_CRYPTO_BENCHMARK=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 7603af319385..3bf518e3a573 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -380,7 +380,6 @@ CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_LZO=m
diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig
index e44c65693b51..0fd49f67331f 100644
--- a/arch/powerpc/configs/ppc64e_defconfig
+++ b/arch/powerpc/configs/ppc64e_defconfig
@@ -223,7 +223,6 @@ CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index b70307b70af0..6f40a275b7a9 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -1076,7 +1076,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA512=m
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index 0b48d2b776c4..7cfae0b7b2f3 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -146,7 +146,6 @@ CONFIG_NLS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_LZO=m
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 2a94abcabd72..d9f0eccb05dd 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -793,7 +793,6 @@ CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA3=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index 763fc7db101f..033bf4502690 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -777,7 +777,6 @@ CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_RMD160=m
CONFIG_CRYPTO_SHA3=m
CONFIG_CRYPTO_SM3_GENERIC=m
diff --git a/arch/sh/configs/sh2007_defconfig b/arch/sh/configs/sh2007_defconfig
index e32d2ce72699..5d9080499485 100644
--- a/arch/sh/configs/sh2007_defconfig
+++ b/arch/sh/configs/sh2007_defconfig
@@ -170,7 +170,6 @@ CONFIG_CRYPTO_XTS=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig
index 896e980d04e1..00863ecb228e 100644
--- a/arch/sh/configs/titan_defconfig
+++ b/arch/sh/configs/titan_defconfig
@@ -246,7 +246,6 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=y
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
diff --git a/arch/sh/configs/ul2_defconfig b/arch/sh/configs/ul2_defconfig
index 0d1c858754db..00a37944b043 100644
--- a/arch/sh/configs/ul2_defconfig
+++ b/arch/sh/configs/ul2_defconfig
@@ -79,4 +79,3 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_932=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_CRYPTO_MICHAEL_MIC=y
diff --git a/arch/sparc/configs/sparc32_defconfig b/arch/sparc/configs/sparc32_defconfig
index e021ecfb5a77..48d834acafb4 100644
--- a/arch/sparc/configs/sparc32_defconfig
+++ b/arch/sparc/configs/sparc32_defconfig
@@ -82,7 +82,6 @@ CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_AES=m
diff --git a/arch/sparc/configs/sparc64_defconfig b/arch/sparc/configs/sparc64_defconfig
index 9f3f41246ae6..632081a262ba 100644
--- a/arch/sparc/configs/sparc64_defconfig
+++ b/arch/sparc/configs/sparc64_defconfig
@@ -210,7 +210,6 @@ CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
diff --git a/crypto/Kconfig b/crypto/Kconfig
index b4bb85e8e226..769aef52a785 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -916,18 +916,6 @@ config CRYPTO_MD5
help
MD5 message digest algorithm (RFC1321), including HMAC support.
-config CRYPTO_MICHAEL_MIC
- tristate "Michael MIC"
- select CRYPTO_HASH
- help
- Michael MIC (Message Integrity Code) (IEEE 802.11i)
-
- Defined by the IEEE 802.11i TKIP (Temporal Key Integrity Protocol),
- known as WPA (Wif-Fi Protected Access).
-
- This algorithm is required for TKIP, but it should not be used for
- other purposes because of the weakness of the algorithm.
-
config CRYPTO_RMD160
tristate "RIPEMD-160"
select CRYPTO_HASH
diff --git a/crypto/Makefile b/crypto/Makefile
index 04e269117589..aa35ba03222f 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -150,7 +150,6 @@ obj-$(CONFIG_CRYPTO_ARIA) += aria_generic.o
obj-$(CONFIG_CRYPTO_CHACHA20) += chacha.o
CFLAGS_chacha.o += -DARCH=$(ARCH)
obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
-obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c-cryptoapi.o
crc32c-cryptoapi-y := crc32c.o
obj-$(CONFIG_CRYPTO_CRC32) += crc32-cryptoapi.o
diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
deleted file mode 100644
index 69ad35f524d7..000000000000
--- a/crypto/michael_mic.c
+++ /dev/null
@@ -1,176 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Cryptographic API
- *
- * Michael MIC (IEEE 802.11i/TKIP) keyed digest
- *
- * Copyright (c) 2004 Jouni Malinen <j@w1.fi>
- */
-#include <crypto/internal/hash.h>
-#include <linux/unaligned.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/types.h>
-
-
-struct michael_mic_ctx {
- u32 l, r;
-};
-
-struct michael_mic_desc_ctx {
- __le32 pending;
- size_t pending_len;
-
- u32 l, r;
-};
-
-static inline u32 xswap(u32 val)
-{
- return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
-}
-
-
-#define michael_block(l, r) \
-do { \
- r ^= rol32(l, 17); \
- l += r; \
- r ^= xswap(l); \
- l += r; \
- r ^= rol32(l, 3); \
- l += r; \
- r ^= ror32(l, 2); \
- l += r; \
-} while (0)
-
-
-static int michael_init(struct shash_desc *desc)
-{
- struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
- struct michael_mic_ctx *ctx = crypto_shash_ctx(desc->tfm);
- mctx->pending_len = 0;
- mctx->l = ctx->l;
- mctx->r = ctx->r;
-
- return 0;
-}
-
-
-static int michael_update(struct shash_desc *desc, const u8 *data,
- unsigned int len)
-{
- struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
-
- if (mctx->pending_len) {
- int flen = 4 - mctx->pending_len;
- if (flen > len)
- flen = len;
- memcpy((u8 *)&mctx->pending + mctx->pending_len, data, flen);
- mctx->pending_len += flen;
- data += flen;
- len -= flen;
-
- if (mctx->pending_len < 4)
- return 0;
-
- mctx->l ^= le32_to_cpu(mctx->pending);
- michael_block(mctx->l, mctx->r);
- mctx->pending_len = 0;
- }
-
- while (len >= 4) {
- mctx->l ^= get_unaligned_le32(data);
- michael_block(mctx->l, mctx->r);
- data += 4;
- len -= 4;
- }
-
- if (len > 0) {
- mctx->pending_len = len;
- memcpy(&mctx->pending, data, len);
- }
-
- return 0;
-}
-
-
-static int michael_final(struct shash_desc *desc, u8 *out)
-{
- struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
- u8 *data = (u8 *)&mctx->pending;
-
- /* Last block and padding (0x5a, 4..7 x 0) */
- switch (mctx->pending_len) {
- case 0:
- mctx->l ^= 0x5a;
- break;
- case 1:
- mctx->l ^= data[0] | 0x5a00;
- break;
- case 2:
- mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000;
- break;
- case 3:
- mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) |
- 0x5a000000;
- break;
- }
- michael_block(mctx->l, mctx->r);
- /* l ^= 0; */
- michael_block(mctx->l, mctx->r);
-
- put_unaligned_le32(mctx->l, out);
- put_unaligned_le32(mctx->r, out + 4);
-
- return 0;
-}
-
-
-static int michael_setkey(struct crypto_shash *tfm, const u8 *key,
- unsigned int keylen)
-{
- struct michael_mic_ctx *mctx = crypto_shash_ctx(tfm);
-
- if (keylen != 8)
- return -EINVAL;
-
- mctx->l = get_unaligned_le32(key);
- mctx->r = get_unaligned_le32(key + 4);
- return 0;
-}
-
-static struct shash_alg alg = {
- .digestsize = 8,
- .setkey = michael_setkey,
- .init = michael_init,
- .update = michael_update,
- .final = michael_final,
- .descsize = sizeof(struct michael_mic_desc_ctx),
- .base = {
- .cra_name = "michael_mic",
- .cra_driver_name = "michael_mic-generic",
- .cra_blocksize = 8,
- .cra_ctxsize = sizeof(struct michael_mic_ctx),
- .cra_module = THIS_MODULE,
- }
-};
-
-static int __init michael_mic_init(void)
-{
- return crypto_register_shash(&alg);
-}
-
-
-static void __exit michael_mic_exit(void)
-{
- crypto_unregister_shash(&alg);
-}
-
-
-module_init(michael_mic_init);
-module_exit(michael_mic_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Michael MIC");
-MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
-MODULE_ALIAS_CRYPTO("michael_mic");
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index aded37546137..24f0ccc76796 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1557,10 +1557,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
ret = min(ret, tcrypt_test("ecb(arc4)"));
break;
- case 17:
- ret = min(ret, tcrypt_test("michael_mic"));
- break;
-
case 18:
ret = min(ret, tcrypt_test("crc32c"));
break;
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 4985411dedae..d5c38683bf46 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -5198,12 +5198,6 @@ static const struct alg_test_desc alg_test_descs[] = {
.hash = __VECS(md5_tv_template)
}
}, {
- .alg = "michael_mic",
- .test = alg_test_hash,
- .suite = {
- .hash = __VECS(michael_mic_tv_template)
- }
- }, {
.alg = "p1363(ecdsa-nist-p192)",
.test = alg_test_null,
}, {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 1c69c11c0cdb..11911bff5f79 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -32809,56 +32809,6 @@ static const struct comp_testvec lzorle_decomp_tv_template[] = {
};
/*
- * Michael MIC test vectors from IEEE 802.11i
- */
-#define MICHAEL_MIC_TEST_VECTORS 6
-
-static const struct hash_testvec michael_mic_tv_template[] = {
- {
- .key = "\x00\x00\x00\x00\x00\x00\x00\x00",
- .ksize = 8,
- .plaintext = zeroed_string,
- .psize = 0,
- .digest = "\x82\x92\x5c\x1c\xa1\xd1\x30\xb8",
- },
- {
- .key = "\x82\x92\x5c\x1c\xa1\xd1\x30\xb8",
- .ksize = 8,
- .plaintext = "M",
- .psize = 1,
- .digest = "\x43\x47\x21\xca\x40\x63\x9b\x3f",
- },
- {
- .key = "\x43\x47\x21\xca\x40\x63\x9b\x3f",
- .ksize = 8,
- .plaintext = "Mi",
- .psize = 2,
- .digest = "\xe8\xf9\xbe\xca\xe9\x7e\x5d\x29",
- },
- {
- .key = "\xe8\xf9\xbe\xca\xe9\x7e\x5d\x29",
- .ksize = 8,
- .plaintext = "Mic",
- .psize = 3,
- .digest = "\x90\x03\x8f\xc6\xcf\x13\xc1\xdb",
- },
- {
- .key = "\x90\x03\x8f\xc6\xcf\x13\xc1\xdb",
- .ksize = 8,
- .plaintext = "Mich",
- .psize = 4,
- .digest = "\xd5\x5e\x10\x05\x10\x12\x89\x86",
- },
- {
- .key = "\xd5\x5e\x10\x05\x10\x12\x89\x86",
- .ksize = 8,
- .plaintext = "Michael",
- .psize = 7,
- .digest = "\x0a\x94\x2b\x12\x4e\xca\xa5\x46",
- }
-};
-
-/*
* CRC32 test vectors
*/
static const struct hash_testvec crc32_tv_template[] = {
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index eebd78e7ff6b..e7f90fd9e9b8 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -808,6 +808,7 @@ out:
static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi)
{
struct ath10k *ar = qmi->ar;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
int ret;
ret = ath10k_qmi_ind_register_send_sync_msg(qmi);
@@ -819,9 +820,15 @@ static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi)
return;
}
- ret = ath10k_qmi_host_cap_send_sync(qmi);
- if (ret)
- return;
+ /*
+ * Skip the host capability request for the firmware versions which
+ * do not support this feature.
+ */
+ if (!test_bit(ATH10K_SNOC_FLAG_SKIP_HOST_CAP_QUIRK, &ar_snoc->flags)) {
+ ret = ath10k_qmi_host_cap_send_sync(qmi);
+ if (ret)
+ return;
+ }
ret = ath10k_qmi_msa_mem_info_send_sync_msg(qmi);
if (ret)
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index f72f236fb9eb..310650227578 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -1362,6 +1362,9 @@ static void ath10k_snoc_quirks_init(struct ath10k *ar)
if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))
set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);
+
+ if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-skip-quirk"))
+ set_bit(ATH10K_SNOC_FLAG_SKIP_HOST_CAP_QUIRK, &ar_snoc->flags);
}
int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h
index 1ecae34687c2..46574fd8f84e 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.h
+++ b/drivers/net/wireless/ath/ath10k/snoc.h
@@ -51,6 +51,7 @@ enum ath10k_snoc_flags {
ATH10K_SNOC_FLAG_MODEM_STOPPED,
ATH10K_SNOC_FLAG_RECOVERY,
ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK,
+ ATH10K_SNOC_FLAG_SKIP_HOST_CAP_QUIRK,
};
struct clk_bulk_data;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index ec8e91707f84..01f2d1fa9d7d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -3,7 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
- * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "core.h"
#include "debug.h"
@@ -14,6 +14,7 @@
#include "wmi-tlv.h"
#include "p2p.h"
#include "testmode.h"
+#include "txrx.h"
#include <linux/bitfield.h>
/***************/
@@ -224,8 +225,9 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16
const void *ptr, void *data)
{
const struct wmi_tlv_peer_stats_info *stat = ptr;
- struct ieee80211_sta *sta;
+ u32 vdev_id = *(u32 *)data;
struct ath10k_sta *arsta;
+ struct ath10k_peer *peer;
if (tag != WMI_TLV_TAG_STRUCT_PEER_STATS_INFO)
return -EPROTO;
@@ -241,20 +243,20 @@ static int ath10k_wmi_tlv_parse_peer_stats_info(struct ath10k *ar, u16 tag, u16
__le32_to_cpu(stat->last_tx_rate_code),
__le32_to_cpu(stat->last_tx_bitrate_kbps));
- rcu_read_lock();
- sta = ieee80211_find_sta_by_ifaddr(ar->hw, stat->peer_macaddr.addr, NULL);
- if (!sta) {
- rcu_read_unlock();
- ath10k_warn(ar, "not found station for peer stats\n");
+ guard(spinlock_bh)(&ar->data_lock);
+
+ peer = ath10k_peer_find(ar, vdev_id, stat->peer_macaddr.addr);
+ if (!peer || !peer->sta) {
+ ath10k_warn(ar, "not found %s with vdev id %u mac addr %pM for peer stats\n",
+ peer ? "sta" : "peer", vdev_id, stat->peer_macaddr.addr);
return -EINVAL;
}
- arsta = (struct ath10k_sta *)sta->drv_priv;
+ arsta = (struct ath10k_sta *)peer->sta->drv_priv;
arsta->rx_rate_code = __le32_to_cpu(stat->last_rx_rate_code);
arsta->rx_bitrate_kbps = __le32_to_cpu(stat->last_rx_bitrate_kbps);
arsta->tx_rate_code = __le32_to_cpu(stat->last_tx_rate_code);
arsta->tx_bitrate_kbps = __le32_to_cpu(stat->last_tx_bitrate_kbps);
- rcu_read_unlock();
return 0;
}
@@ -266,6 +268,7 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar,
const struct wmi_tlv_peer_stats_info_ev *ev;
const void *data;
u32 num_peer_stats;
+ u32 vdev_id;
int ret;
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
@@ -284,15 +287,16 @@ static int ath10k_wmi_tlv_op_pull_peer_stats_info(struct ath10k *ar,
}
num_peer_stats = __le32_to_cpu(ev->num_peers);
+ vdev_id = __le32_to_cpu(ev->vdev_id);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi tlv peer stats info update peer vdev id %d peers %i more data %d\n",
- __le32_to_cpu(ev->vdev_id),
+ vdev_id,
num_peer_stats,
__le32_to_cpu(ev->more_data));
ret = ath10k_wmi_tlv_iter(ar, data, ath10k_wmi_tlv_len(data),
- ath10k_wmi_tlv_parse_peer_stats_info, NULL);
+ ath10k_wmi_tlv_parse_peer_stats_info, &vdev_id);
if (ret)
ath10k_warn(ar, "failed to parse stats info tlv: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig
index 47dfd39caa89..385513cfdc30 100644
--- a/drivers/net/wireless/ath/ath11k/Kconfig
+++ b/drivers/net/wireless/ath/ath11k/Kconfig
@@ -2,7 +2,6 @@
config ATH11K
tristate "Qualcomm Technologies 802.11ax chipset support"
depends on MAC80211 && HAS_DMA
- select CRYPTO_MICHAEL_MIC
select ATH_COMMON
select QCOM_QMI_HELPERS
help
diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c
index c940de285276..bbb86f165141 100644
--- a/drivers/net/wireless/ath/ath11k/dp.c
+++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -5,7 +5,6 @@
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
-#include <crypto/hash.h>
#include <linux/export.h>
#include "core.h"
#include "dp_tx.h"
@@ -39,7 +38,6 @@ void ath11k_dp_peer_cleanup(struct ath11k *ar, int vdev_id, const u8 *addr)
ath11k_peer_rx_tid_cleanup(ar, peer);
peer->dp_setup_done = false;
- crypto_free_shash(peer->tfm_mmic);
spin_unlock_bh(&ab->base_lock);
}
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 85defe11750d..fe79109adc70 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -4,10 +4,10 @@
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
+#include <linux/fips.h>
#include <linux/ieee80211.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
-#include <crypto/hash.h>
#include "core.h"
#include "debug.h"
#include "debugfs_htt_stats.h"
@@ -3182,16 +3182,13 @@ static void ath11k_dp_rx_frag_timer(struct timer_list *timer)
int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id)
{
struct ath11k_base *ab = ar->ab;
- struct crypto_shash *tfm;
struct ath11k_peer *peer;
struct dp_rx_tid *rx_tid;
int i;
- tfm = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(tfm)) {
- ath11k_warn(ab, "failed to allocate michael_mic shash: %ld\n",
- PTR_ERR(tfm));
- return PTR_ERR(tfm);
+ if (fips_enabled) {
+ ath11k_warn(ab, "This driver is disabled due to FIPS\n");
+ return -ENOENT;
}
spin_lock_bh(&ab->base_lock);
@@ -3200,7 +3197,6 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id
if (!peer) {
ath11k_warn(ab, "failed to find the peer to set up fragment info\n");
spin_unlock_bh(&ab->base_lock);
- crypto_free_shash(tfm);
return -ENOENT;
}
@@ -3211,54 +3207,12 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id
skb_queue_head_init(&rx_tid->rx_frags);
}
- peer->tfm_mmic = tfm;
peer->dp_setup_done = true;
spin_unlock_bh(&ab->base_lock);
return 0;
}
-static int ath11k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
- struct ieee80211_hdr *hdr, u8 *data,
- size_t data_len, u8 *mic)
-{
- SHASH_DESC_ON_STACK(desc, tfm);
- u8 mic_hdr[16] = {};
- u8 tid = 0;
- int ret;
-
- if (!tfm)
- return -EINVAL;
-
- desc->tfm = tfm;
-
- ret = crypto_shash_setkey(tfm, key, 8);
- if (ret)
- goto out;
-
- ret = crypto_shash_init(desc);
- if (ret)
- goto out;
-
- /* TKIP MIC header */
- memcpy(mic_hdr, ieee80211_get_DA(hdr), ETH_ALEN);
- memcpy(mic_hdr + ETH_ALEN, ieee80211_get_SA(hdr), ETH_ALEN);
- if (ieee80211_is_data_qos(hdr->frame_control))
- tid = ieee80211_get_tid(hdr);
- mic_hdr[12] = tid;
-
- ret = crypto_shash_update(desc, mic_hdr, 16);
- if (ret)
- goto out;
- ret = crypto_shash_update(desc, data, data_len);
- if (ret)
- goto out;
- ret = crypto_shash_final(desc, mic);
-out:
- shash_desc_zero(desc);
- return ret;
-}
-
static int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer *peer,
struct sk_buff *msdu)
{
@@ -3267,7 +3221,7 @@ static int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer
struct ieee80211_key_conf *key_conf;
struct ieee80211_hdr *hdr;
u8 mic[IEEE80211_CCMP_MIC_LEN];
- int head_len, tail_len, ret;
+ int head_len, tail_len;
size_t data_len;
u32 hdr_len, hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
u8 *key, *data;
@@ -3293,8 +3247,8 @@ static int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer
data_len = msdu->len - head_len - tail_len;
key = &key_conf->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
- ret = ath11k_dp_rx_h_michael_mic(peer->tfm_mmic, key, hdr, data, data_len, mic);
- if (ret || memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN))
+ michael_mic(key, hdr, data, data_len, mic);
+ if (memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN))
goto mic_fail;
return 0;
diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h
index 3ad2f3355b14..f5ef1a27f8f2 100644
--- a/drivers/net/wireless/ath/ath11k/peer.h
+++ b/drivers/net/wireless/ath/ath11k/peer.h
@@ -29,7 +29,6 @@ struct ath11k_peer {
/* Info used in MMIC verification of
* RX fragments
*/
- struct crypto_shash *tfm_mmic;
u8 mcast_keyidx;
u8 ucast_keyidx;
u16 sec_type;
diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig
index 1ea1af1b8f6c..d39c075758bd 100644
--- a/drivers/net/wireless/ath/ath12k/Kconfig
+++ b/drivers/net/wireless/ath/ath12k/Kconfig
@@ -2,7 +2,6 @@
config ATH12K
tristate "Qualcomm Technologies Wi-Fi 7 support (ath12k)"
depends on MAC80211 && HAS_DMA && PCI
- select CRYPTO_MICHAEL_MIC
select QCOM_QMI_HELPERS
select MHI_BUS
select QRTR
diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c
index 9a4d34e49104..2dcf0a52e4c1 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.c
+++ b/drivers/net/wireless/ath/ath12k/ahb.c
@@ -382,8 +382,12 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
ATH12K_AHB_UPD_SWID;
/* Load FW image to a reserved memory location */
- ret = qcom_mdt_load(dev, fw, fw_name, pasid, mem_region, mem_phys, mem_size,
- &mem_phys);
+ if (ab_ahb->scm_auth_enabled)
+ ret = qcom_mdt_load(dev, fw, fw_name, pasid, mem_region,
+ mem_phys, mem_size, &mem_phys);
+ else
+ ret = qcom_mdt_load_no_init(dev, fw, fw_name, mem_region,
+ mem_phys, mem_size, &mem_phys);
if (ret) {
ath12k_err(ab, "Failed to load MDT segments: %d\n", ret);
goto err_fw;
@@ -414,11 +418,13 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
goto err_fw2;
}
- /* Authenticate FW image using peripheral ID */
- ret = qcom_scm_pas_auth_and_reset(pasid);
- if (ret) {
- ath12k_err(ab, "failed to boot the remote processor %d\n", ret);
- goto err_fw2;
+ if (ab_ahb->scm_auth_enabled) {
+ /* Authenticate FW image using peripheral ID */
+ ret = qcom_scm_pas_auth_and_reset(pasid);
+ if (ret) {
+ ath12k_err(ab, "failed to boot the remote processor %d\n", ret);
+ goto err_fw2;
+ }
}
/* Instruct Q6 to spawn userPD thread */
@@ -475,13 +481,15 @@ static void ath12k_ahb_power_down(struct ath12k_base *ab, bool is_suspend)
qcom_smem_state_update_bits(ab_ahb->stop_state, BIT(ab_ahb->stop_bit), 0);
- pasid = (u32_encode_bits(ab_ahb->userpd_id, ATH12K_USERPD_ID_MASK)) |
- ATH12K_AHB_UPD_SWID;
- /* Release the firmware */
- ret = qcom_scm_pas_shutdown(pasid);
- if (ret)
- ath12k_err(ab, "scm pas shutdown failed for userPD%d: %d\n",
- ab_ahb->userpd_id, ret);
+ if (ab_ahb->scm_auth_enabled) {
+ pasid = (u32_encode_bits(ab_ahb->userpd_id, ATH12K_USERPD_ID_MASK)) |
+ ATH12K_AHB_UPD_SWID;
+ /* Release the firmware */
+ ret = qcom_scm_pas_shutdown(pasid);
+ if (ret)
+ ath12k_err(ab, "scm pas shutdown failed for userPD%d\n",
+ ab_ahb->userpd_id);
+ }
}
static void ath12k_ahb_init_qmi_ce_config(struct ath12k_base *ab)
diff --git a/drivers/net/wireless/ath/ath12k/ahb.h b/drivers/net/wireless/ath/ath12k/ahb.h
index be9e31b3682d..0fa15daaa3e6 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.h
+++ b/drivers/net/wireless/ath/ath12k/ahb.h
@@ -68,6 +68,7 @@ struct ath12k_ahb {
int userpd_irq_num[ATH12K_USERPD_MAX_IRQ];
const struct ath12k_ahb_ops *ahb_ops;
const struct ath12k_ahb_device_family_ops *device_family_ops;
+ bool scm_auth_enabled;
};
struct ath12k_ahb_driver {
diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h
index df4f2a4f8480..009cddf2d68d 100644
--- a/drivers/net/wireless/ath/ath12k/ce.h
+++ b/drivers/net/wireless/ath/ath12k/ce.h
@@ -38,10 +38,15 @@
#define PIPEDIR_INOUT 3 /* bidirectional */
#define PIPEDIR_INOUT_H2H 4 /* bidirectional, host to host */
-/* CE address/mask */
-#define CE_HOST_IE_ADDRESS 0x75804C
-#define CE_HOST_IE_2_ADDRESS 0x758050
-#define CE_HOST_IE_3_ADDRESS CE_HOST_IE_ADDRESS
+/* IPQ5332 CE address/mask */
+#define CE_HOST_IPQ5332_IE_ADDRESS 0x75804C
+#define CE_HOST_IPQ5332_IE_2_ADDRESS 0x758050
+#define CE_HOST_IPQ5332_IE_3_ADDRESS CE_HOST_IPQ5332_IE_ADDRESS
+
+/* IPQ5424 CE address/mask */
+#define CE_HOST_IPQ5424_IE_ADDRESS 0x21804C
+#define CE_HOST_IPQ5424_IE_2_ADDRESS 0x218050
+#define CE_HOST_IPQ5424_IE_3_ADDRESS CE_HOST_IPQ5424_IE_ADDRESS
#define CE_HOST_IE_3_SHIFT 0xC
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index c31c47fb5a73..2519e2400d58 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -835,8 +835,6 @@ static int ath12k_core_soc_create(struct ath12k_base *ab)
goto err_qmi_deinit;
}
- ath12k_debugfs_pdev_create(ab);
-
return 0;
err_qmi_deinit:
@@ -869,6 +867,8 @@ static int ath12k_core_pdev_create(struct ath12k_base *ab)
goto err_dp_pdev_free;
}
+ ath12k_debugfs_pdev_create(ab);
+
return 0;
err_dp_pdev_free:
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 59c193b24764..8be435535a4e 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -157,6 +157,7 @@ enum ath12k_hw_rev {
ATH12K_HW_WCN7850_HW20,
ATH12K_HW_IPQ5332_HW10,
ATH12K_HW_QCC2072_HW10,
+ ATH12K_HW_IPQ5424_HW10,
};
enum ath12k_firmware_mode {
@@ -588,6 +589,7 @@ struct ath12k_dbg_htt_stats {
struct ath12k_debug {
struct dentry *debugfs_pdev;
struct dentry *debugfs_pdev_symlink;
+ struct dentry *debugfs_pdev_symlink_default;
struct ath12k_dbg_htt_stats htt_stats;
enum wmi_halphy_ctrl_path_stats_id tpc_stats_type;
bool tpc_request;
@@ -673,6 +675,7 @@ struct ath12k {
u8 pdev_idx;
u8 lmac_id;
u8 hw_link_id;
+ u8 radio_idx;
struct completion peer_assoc_done;
struct completion peer_delete_done;
@@ -1366,13 +1369,13 @@ static inline struct ath12k_hw *ath12k_hw_to_ah(struct ieee80211_hw *hw)
return hw->priv;
}
-static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah, u8 hw_link_id)
+static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah, u8 radio_idx)
{
- if (WARN(hw_link_id >= ah->num_radio,
- "bad hw link id %d, so switch to default link\n", hw_link_id))
- hw_link_id = 0;
+ if (WARN(radio_idx >= ah->num_radio,
+ "bad radio index %d, use default radio\n", radio_idx))
+ radio_idx = 0;
- return &ah->radio[hw_link_id];
+ return &ah->radio[radio_idx];
}
static inline struct ath12k_hw *ath12k_ar_to_ah(struct ath12k *ar)
diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
index 358031fa14eb..8c81a1c22449 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs.c
@@ -1473,18 +1473,35 @@ void ath12k_debugfs_register(struct ath12k *ar)
{
struct ath12k_base *ab = ar->ab;
struct ieee80211_hw *hw = ar->ah->hw;
- char pdev_name[5];
+ struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+ struct dentry *ath12k_fs;
char buf[100] = {};
+ char pdev_name[5];
scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
/* Create a symlink under ieee80211/phy* */
- scnprintf(buf, sizeof(buf), "../../ath12k/%pd2", ar->debug.debugfs_pdev);
- ar->debug.debugfs_pdev_symlink = debugfs_create_symlink("ath12k",
- hw->wiphy->debugfsdir,
- buf);
+ if (ar->radio_idx == 0) {
+ scnprintf(buf, sizeof(buf), "../../ath12k/%pd2",
+ ar->debug.debugfs_pdev);
+ ath12k_fs = hw->wiphy->debugfsdir;
+
+ /* symbolic link for compatibility */
+ ar->debug.debugfs_pdev_symlink_default = debugfs_create_symlink("ath12k",
+ ath12k_fs,
+ buf);
+ }
+
+ if (ah->num_radio > 1) {
+ scnprintf(buf, sizeof(buf), "../../../ath12k/%pd2",
+ ar->debug.debugfs_pdev);
+ ath12k_fs = hw->wiphy->radio_cfg[ar->radio_idx].radio_debugfsdir;
+ ar->debug.debugfs_pdev_symlink = debugfs_create_symlink("ath12k",
+ ath12k_fs,
+ buf);
+ }
if (ar->mac.sbands[NL80211_BAND_5GHZ].channels) {
debugfs_create_file("dfs_simulate_radar", 0200,
@@ -1513,7 +1530,9 @@ void ath12k_debugfs_unregister(struct ath12k *ar)
/* Remove symlink under ieee80211/phy* */
debugfs_remove(ar->debug.debugfs_pdev_symlink);
+ debugfs_remove(ar->debug.debugfs_pdev_symlink_default);
debugfs_remove_recursive(ar->debug.debugfs_pdev);
ar->debug.debugfs_pdev_symlink = NULL;
+ ar->debug.debugfs_pdev_symlink_default = NULL;
ar->debug.debugfs_pdev = NULL;
}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
index 7f6ca07fb335..b772181a496e 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -5722,6 +5722,75 @@ ath12k_htt_print_tx_hwq_stats_cmn_tlv(const void *tag_buf, u16 tag_len,
stats_req->buf_len = len;
}
+static void
+ath12k_htt_print_chan_switch_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct ath12k_htt_chan_switch_stats_tlv *sbuf = tag_buf;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 switch_freq, switch_profile;
+ u32 len = stats_req->buf_len;
+ u8 *buf = stats_req->buf;
+ u8 i;
+
+ if (tag_len < sizeof(*sbuf))
+ return;
+
+ i = min(le32_to_cpu(sbuf->switch_count), ATH12K_HTT_CHAN_SWITCH_STATS_BUF_LEN);
+ if (!i)
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "Channel Change Timings:\n");
+ len += scnprintf(buf + len, buf_len - len,
+ "|%-20s|%-21s|%-7s|%-12s|%-12s|%-15s|",
+ "PRIMARY CHANNEL FREQ", "BANDWIDTH CENTER FREQ", "PHYMODE",
+ "TX_CHAINMASK", "RX_CHAINMASK", "SWITCH TIME(us)");
+ len += scnprintf(buf + len, buf_len - len,
+ "%-7s|%-11s|%-7s|%-8s|%-7s|%-10s|\n",
+ "INI(us)", "TPC+CTL(us)", "CAL(us)", "MISC(us)", "CTL(us)",
+ "SW PROFILE");
+
+ /*
+ * sbuf->switch_count has the number of successful channel changes. The firmware
+ * sends the record of channel change in such a way that sbuf->chan_stats[0] will
+ * point to the channel change that occurred first and the recent channel change
+ * records will be stored in sbuf->chan_stats[9]. As and when new channel change
+ * occurs, sbuf->chan_stats[0] will be replaced by records from the next index,
+ * sbuf->chan_stats[1]. While printing the records, reverse chronological order
+ * is followed, i.e., the most recent channel change records are printed first
+ * and the oldest one, last.
+ */
+ while (i--) {
+ switch_freq = le32_to_cpu(sbuf->chan_stats[i].chan_switch_freq);
+ switch_profile = le32_to_cpu(sbuf->chan_stats[i].chan_switch_profile);
+
+ len += scnprintf(buf + len, buf_len - len,
+ "|%20u|%21u|%7u|%12u|%12u|%15u|",
+ u32_get_bits(switch_freq,
+ ATH12K_HTT_STATS_CHAN_SWITCH_BW_MHZ),
+ u32_get_bits(switch_freq,
+ ATH12K_HTT_STATS_CHAN_SWITCH_BAND_FREQ),
+ u32_get_bits(switch_profile,
+ ATH12K_HTT_STATS_CHAN_SWITCH_PHY_MODE),
+ u32_get_bits(switch_profile,
+ ATH12K_HTT_STATS_CHAN_SWITCH_TX_CHAINMASK),
+ u32_get_bits(switch_profile,
+ ATH12K_HTT_STATS_CHAN_SWITCH_RX_CHAINMASK),
+ le32_to_cpu(sbuf->chan_stats[i].chan_switch_time));
+ len += scnprintf(buf + len, buf_len - len,
+ "%7u|%11u|%7u|%8u|%7u|%10u|\n",
+ le32_to_cpu(sbuf->chan_stats[i].ini_module_time),
+ le32_to_cpu(sbuf->chan_stats[i].tpc_module_time),
+ le32_to_cpu(sbuf->chan_stats[i].cal_module_time),
+ le32_to_cpu(sbuf->chan_stats[i].misc_module_time),
+ le32_to_cpu(sbuf->chan_stats[i].ctl_module_time),
+ u32_get_bits(switch_profile,
+ ATH12K_HTT_STATS_CHAN_SWITCH_SW_PROFILE));
+ }
+
+ stats_req->buf_len = len;
+}
+
static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
u16 tag, u16 len, const void *tag_buf,
void *user_data)
@@ -6024,6 +6093,9 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
case HTT_STATS_TX_HWQ_CMN_TAG:
ath12k_htt_print_tx_hwq_stats_cmn_tlv(tag_buf, len, stats_req);
break;
+ case HTT_STATS_CHAN_SWITCH_STATS_TAG:
+ ath12k_htt_print_chan_switch_stats_tlv(tag_buf, len, stats_req);
+ break;
default:
break;
}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
index bfabe6500d44..82ab7b9e4db9 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
@@ -164,6 +164,7 @@ enum ath12k_dbg_htt_ext_stats_type {
ATH12K_DBG_HTT_PDEV_MLO_IPC_STATS = 64,
ATH12K_DBG_HTT_EXT_PDEV_RTT_RESP_STATS = 65,
ATH12K_DBG_HTT_EXT_PDEV_RTT_INITIATOR_STATS = 66,
+ ATH12K_DBG_HTT_EXT_CHAN_SWITCH_STATS = 76,
/* keep this last */
ATH12K_DBG_HTT_NUM_EXT_STATS,
@@ -267,6 +268,7 @@ enum ath12k_dbg_htt_tlv_tag {
HTT_STATS_PDEV_RTT_HW_STATS_TAG = 196,
HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG = 197,
HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG = 198,
+ HTT_STATS_CHAN_SWITCH_STATS_TAG = 213,
HTT_STATS_MAX_TAG,
};
@@ -2156,4 +2158,28 @@ struct htt_tx_hwq_stats_cmn_tlv {
__le32 txq_timeout;
} __packed;
+#define ATH12K_HTT_CHAN_SWITCH_STATS_BUF_LEN 10
+
+#define ATH12K_HTT_STATS_CHAN_SWITCH_BW_MHZ GENMASK(15, 0)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_BAND_FREQ GENMASK(31, 16)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_PHY_MODE GENMASK(7, 0)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_TX_CHAINMASK GENMASK(15, 8)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_RX_CHAINMASK GENMASK(23, 16)
+#define ATH12K_HTT_STATS_CHAN_SWITCH_SW_PROFILE GENMASK(31, 24)
+
+struct ath12k_htt_chan_switch_stats_tlv {
+ struct {
+ __le32 chan_switch_freq;
+ __le32 chan_switch_profile;
+ __le32 chan_switch_time;
+ __le32 cal_module_time;
+ __le32 ini_module_time;
+ __le32 tpc_module_time;
+ __le32 misc_module_time;
+ __le32 ctl_module_time;
+ __le32 reserved;
+ } chan_stats[ATH12K_HTT_CHAN_SWITCH_STATS_BUF_LEN];
+ __le32 switch_count; /* shows how many channel changes have occurred */
+} __packed;
+
#endif
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index 1c82d927d27b..90802ed1aa59 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -4,7 +4,6 @@
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
-#include <crypto/hash.h>
#include "core.h"
#include "dp_tx.h"
#include "hif.h"
@@ -41,7 +40,6 @@ void ath12k_dp_peer_cleanup(struct ath12k *ar, int vdev_id, const u8 *addr)
}
ath12k_dp_rx_peer_tid_cleanup(ar, peer);
- crypto_free_shash(peer->dp_peer->tfm_mmic);
peer->dp_peer->dp_setup_done = false;
spin_unlock_bh(&dp->dp_lock);
}
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h
index 20294ff09513..113b8040010f 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.h
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.h
@@ -139,7 +139,6 @@ struct ath12k_dp_peer {
u16 sec_type;
/* Info used in MMIC verification of * RX fragments */
- struct crypto_shash *tfm_mmic;
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS];
struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 59088ab407d0..250459facff3 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -4,10 +4,10 @@
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
+#include <linux/fips.h>
#include <linux/ieee80211.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
-#include <crypto/hash.h>
#include "core.h"
#include "debug.h"
#include "hw.h"
@@ -1433,29 +1433,27 @@ static void ath12k_dp_rx_frag_timer(struct timer_list *timer)
int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id)
{
struct ath12k_base *ab = ar->ab;
- struct crypto_shash *tfm;
struct ath12k_dp_link_peer *peer;
struct ath12k_dp_rx_tid *rx_tid;
int i;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
- tfm = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(tfm))
- return PTR_ERR(tfm);
+ if (fips_enabled) {
+ ath12k_warn(ab, "This driver is disabled due to FIPS\n");
+ return -ENOENT;
+ }
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, peer_mac);
if (!peer || !peer->dp_peer) {
spin_unlock_bh(&dp->dp_lock);
- crypto_free_shash(tfm);
ath12k_warn(ab, "failed to find the peer to set up fragment info\n");
return -ENOENT;
}
if (!peer->primary_link) {
spin_unlock_bh(&dp->dp_lock);
- crypto_free_shash(tfm);
return 0;
}
@@ -1466,55 +1464,12 @@ int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev
skb_queue_head_init(&rx_tid->rx_frags);
}
- peer->dp_peer->tfm_mmic = tfm;
peer->dp_peer->dp_setup_done = true;
spin_unlock_bh(&dp->dp_lock);
return 0;
}
-int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
- struct ieee80211_hdr *hdr, u8 *data,
- size_t data_len, u8 *mic)
-{
- SHASH_DESC_ON_STACK(desc, tfm);
- u8 mic_hdr[16] = {};
- u8 tid = 0;
- int ret;
-
- if (!tfm)
- return -EINVAL;
-
- desc->tfm = tfm;
-
- ret = crypto_shash_setkey(tfm, key, 8);
- if (ret)
- goto out;
-
- ret = crypto_shash_init(desc);
- if (ret)
- goto out;
-
- /* TKIP MIC header */
- memcpy(mic_hdr, ieee80211_get_DA(hdr), ETH_ALEN);
- memcpy(mic_hdr + ETH_ALEN, ieee80211_get_SA(hdr), ETH_ALEN);
- if (ieee80211_is_data_qos(hdr->frame_control))
- tid = ieee80211_get_tid(hdr);
- mic_hdr[12] = tid;
-
- ret = crypto_shash_update(desc, mic_hdr, 16);
- if (ret)
- goto out;
- ret = crypto_shash_update(desc, data, data_len);
- if (ret)
- goto out;
- ret = crypto_shash_final(desc, mic);
-out:
- shash_desc_zero(desc);
- return ret;
-}
-EXPORT_SYMBOL(ath12k_dp_rx_h_michael_mic);
-
void ath12k_dp_rx_h_undecap_frag(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
enum hal_encrypt_type enctype, u32 flags)
{
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index bd62af0c80d4..55a31e669b3b 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -6,7 +6,6 @@
#ifndef ATH12K_DP_RX_H
#define ATH12K_DP_RX_H
-#include <crypto/hash.h>
#include "core.h"
#include "debug.h"
@@ -204,9 +203,6 @@ void ath12k_dp_rx_h_sort_frags(struct ath12k_hal *hal,
struct sk_buff *cur_frag);
void ath12k_dp_rx_h_undecap_frag(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
enum hal_encrypt_type enctype, u32 flags);
-int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
- struct ieee80211_hdr *hdr, u8 *data,
- size_t data_len, u8 *mic);
int ath12k_dp_rx_ampdu_start(struct ath12k *ar,
struct ieee80211_ampdu_params *params,
u8 link_id);
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 553ec28b6aaa..fbdfe6424fd7 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -11131,7 +11131,7 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif,
if (arvif == arvif_p)
continue;
- if (!arvif_p->is_created)
+ if (!arvif_p->is_started)
continue;
link_conf = wiphy_dereference(ahvif->ah->hw->wiphy,
@@ -15065,6 +15065,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,
ar->hw_link_id = pdev->hw_link_id;
ar->pdev = pdev;
ar->pdev_idx = pdev_idx;
+ ar->radio_idx = i;
pdev->ar = ar;
ag->hw_links[ar->hw_link_id].device_id = ab->device_id;
@@ -15132,7 +15133,6 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
if (!ab)
continue;
- ath12k_debugfs_pdev_create(ab);
ath12k_mac_set_device_defaults(ab);
total_radio += ab->num_radios;
}
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/ahb.c b/drivers/net/wireless/ath/ath12k/wifi7/ahb.c
index a6c5f7689edd..6a8b8b2a56f9 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/ahb.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/ahb.c
@@ -19,6 +19,9 @@ static const struct of_device_id ath12k_wifi7_ahb_of_match[] = {
{ .compatible = "qcom,ipq5332-wifi",
.data = (void *)ATH12K_HW_IPQ5332_HW10,
},
+ { .compatible = "qcom,ipq5424-wifi",
+ .data = (void *)ATH12K_HW_IPQ5424_HW10,
+ },
{ }
};
@@ -38,6 +41,11 @@ static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
switch (hw_rev) {
case ATH12K_HW_IPQ5332_HW10:
ab_ahb->userpd_id = ATH12K_IPQ5332_USERPD_ID;
+ ab_ahb->scm_auth_enabled = true;
+ break;
+ case ATH12K_HW_IPQ5424_HW10:
+ ab_ahb->userpd_id = ATH12K_IPQ5332_USERPD_ID;
+ ab_ahb->scm_auth_enabled = false;
break;
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
index e6a934d74e85..945680b3ebdf 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
@@ -983,7 +983,7 @@ static int ath12k_wifi7_dp_rx_h_verify_tkip_mic(struct ath12k_pdev_dp *dp_pdev,
struct ieee80211_key_conf *key_conf;
struct ieee80211_hdr *hdr;
u8 mic[IEEE80211_CCMP_MIC_LEN];
- int head_len, tail_len, ret;
+ int head_len, tail_len;
size_t data_len;
u32 hdr_len, hal_rx_desc_sz = hal->hal_desc_sz;
u8 *key, *data;
@@ -1011,9 +1011,8 @@ static int ath12k_wifi7_dp_rx_h_verify_tkip_mic(struct ath12k_pdev_dp *dp_pdev,
data_len = msdu->len - head_len - tail_len;
key = &key_conf->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
- ret = ath12k_dp_rx_h_michael_mic(peer->tfm_mmic, key, hdr, data,
- data_len, mic);
- if (ret || memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN))
+ michael_mic(key, hdr, data, data_len, mic);
+ if (memcmp(mic, data + data_len, IEEE80211_CCMP_MIC_LEN))
goto mic_fail;
return 0;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal.c b/drivers/net/wireless/ath/ath12k/wifi7/hal.c
index bd1753ca0db6..a0a1902fb491 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal.c
@@ -50,6 +50,13 @@ static const struct ath12k_hw_version_map ath12k_wifi7_hw_ver_map[] = {
.hal_params = &ath12k_hw_hal_params_wcn7850,
.hw_regs = &qcc2072_regs,
},
+ [ATH12K_HW_IPQ5424_HW10] = {
+ .hal_ops = &hal_qcn9274_ops,
+ .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274_compact),
+ .tcl_to_wbm_rbm_map = ath12k_hal_tcl_to_wbm_rbm_map_qcn9274,
+ .hal_params = &ath12k_hw_hal_params_ipq5332,
+ .hw_regs = &ipq5424_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 9337225a5253..3d9386198893 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal.h
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal.h
@@ -364,6 +364,9 @@
#define HAL_IPQ5332_CE_WFSS_REG_BASE 0x740000
#define HAL_IPQ5332_CE_SIZE 0x100000
+#define HAL_IPQ5424_CE_WFSS_REG_BASE 0x200000
+#define HAL_IPQ5424_CE_SIZE 0x100000
+
#define HAL_RX_MAX_BA_WINDOW 256
#define HAL_DEFAULT_BE_BK_VI_REO_TIMEOUT_USEC (100 * 1000)
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c
index 41c918eb1767..ba9ce1e718e8 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.c
@@ -484,6 +484,94 @@ const struct ath12k_hw_regs ipq5332_regs = {
HAL_IPQ5332_CE_WFSS_REG_BASE,
};
+const struct ath12k_hw_regs ipq5424_regs = {
+ /* SW2TCL(x) R0 ring configuration address */
+ .tcl1_ring_id = 0x00000918,
+ .tcl1_ring_misc = 0x00000920,
+ .tcl1_ring_tp_addr_lsb = 0x0000092c,
+ .tcl1_ring_tp_addr_msb = 0x00000930,
+ .tcl1_ring_consumer_int_setup_ix0 = 0x00000940,
+ .tcl1_ring_consumer_int_setup_ix1 = 0x00000944,
+ .tcl1_ring_msi1_base_lsb = 0x00000958,
+ .tcl1_ring_msi1_base_msb = 0x0000095c,
+ .tcl1_ring_base_lsb = 0x00000910,
+ .tcl1_ring_base_msb = 0x00000914,
+ .tcl1_ring_msi1_data = 0x00000960,
+ .tcl2_ring_base_lsb = 0x00000988,
+ .tcl_ring_base_lsb = 0x00000b68,
+
+ /* TCL STATUS ring address */
+ .tcl_status_ring_base_lsb = 0x00000d48,
+
+ /* REO DEST ring address */
+ .reo2_ring_base = 0x00000578,
+ .reo1_misc_ctrl_addr = 0x00000b9c,
+ .reo1_sw_cookie_cfg0 = 0x0000006c,
+ .reo1_sw_cookie_cfg1 = 0x00000070,
+ .reo1_qdesc_lut_base0 = 0x00000074,
+ .reo1_qdesc_lut_base1 = 0x00000078,
+ .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 = 0x00000B28,
+ .reo1_aging_thres_ix1 = 0x00000B2C,
+ .reo1_aging_thres_ix2 = 0x00000B30,
+ .reo1_aging_thres_ix3 = 0x00000B34,
+
+ /* 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,
+
+ /* WBM idle link ring address */
+ .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 = 0x0000027c,
+
+ /* SW2WBM release ring address */
+ .wbm_sw_release_ring_base_lsb = 0x0000037c,
+
+ /* WBM2SW release ring address */
+ .wbm0_release_ring_base_lsb = 0x00000e08,
+ .wbm1_release_ring_base_lsb = 0x00000e80,
+
+ /* PPE release ring address */
+ .ppe_rel_ring_base = 0x0000046c,
+
+ /* CE address */
+ .umac_ce0_src_reg_base = 0x00200000 -
+ HAL_IPQ5424_CE_WFSS_REG_BASE,
+ .umac_ce0_dest_reg_base = 0x00201000 -
+ HAL_IPQ5424_CE_WFSS_REG_BASE,
+ .umac_ce1_src_reg_base = 0x00202000 -
+ HAL_IPQ5424_CE_WFSS_REG_BASE,
+ .umac_ce1_dest_reg_base = 0x00203000 -
+ HAL_IPQ5424_CE_WFSS_REG_BASE,
+};
+
static inline
bool ath12k_hal_rx_desc_get_first_msdu_qcn9274(struct hal_rx_desc *desc)
{
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.h
index 08c0a0469474..03cf3792d523 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.h
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_qcn9274.h
@@ -17,6 +17,7 @@ extern const struct hal_ops hal_qcn9274_ops;
extern const struct ath12k_hw_regs qcn9274_v1_regs;
extern const struct ath12k_hw_regs qcn9274_v2_regs;
extern const struct ath12k_hw_regs ipq5332_regs;
+extern const struct ath12k_hw_regs ipq5424_regs;
extern const struct ath12k_hal_tcl_to_wbm_rbm_map
ath12k_hal_tcl_to_wbm_rbm_map_qcn9274[DP_TCL_NUM_RING_MAX];
extern const struct ath12k_hw_hal_params ath12k_hw_hal_params_qcn9274;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
index ec6dba96640b..cb3185850439 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
@@ -329,9 +329,15 @@ static const struct ath12k_hw_ring_mask ath12k_wifi7_hw_ring_mask_wcn7850 = {
};
static const struct ce_ie_addr ath12k_wifi7_ce_ie_addr_ipq5332 = {
- .ie1_reg_addr = CE_HOST_IE_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
- .ie2_reg_addr = CE_HOST_IE_2_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
- .ie3_reg_addr = CE_HOST_IE_3_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
+ .ie1_reg_addr = CE_HOST_IPQ5332_IE_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
+ .ie2_reg_addr = CE_HOST_IPQ5332_IE_2_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
+ .ie3_reg_addr = CE_HOST_IPQ5332_IE_3_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
+};
+
+static const struct ce_ie_addr ath12k_wifi7_ce_ie_addr_ipq5424 = {
+ .ie1_reg_addr = CE_HOST_IPQ5424_IE_ADDRESS - HAL_IPQ5424_CE_WFSS_REG_BASE,
+ .ie2_reg_addr = CE_HOST_IPQ5424_IE_2_ADDRESS - HAL_IPQ5424_CE_WFSS_REG_BASE,
+ .ie3_reg_addr = CE_HOST_IPQ5424_IE_3_ADDRESS - HAL_IPQ5424_CE_WFSS_REG_BASE,
};
static const struct ce_remap ath12k_wifi7_ce_remap_ipq5332 = {
@@ -340,6 +346,12 @@ static const struct ce_remap ath12k_wifi7_ce_remap_ipq5332 = {
.cmem_offset = HAL_SEQ_WCSS_CMEM_OFFSET,
};
+static const struct ce_remap ath12k_wifi7_ce_remap_ipq5424 = {
+ .base = HAL_IPQ5424_CE_WFSS_REG_BASE,
+ .size = HAL_IPQ5424_CE_SIZE,
+ .cmem_offset = HAL_SEQ_WCSS_CMEM_OFFSET,
+};
+
static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
{
.name = "qcn9274 hw1.0",
@@ -753,6 +765,85 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.dp_primary_link_only = false,
},
+ {
+ .name = "ipq5424 hw1.0",
+ .hw_rev = ATH12K_HW_IPQ5424_HW10,
+ .fw = {
+ .dir = "IPQ5424/hw1.0",
+ .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,
+ .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ5332,
+ .internal_sleep_clock = false,
+
+ .hw_ops = &qcn9274_ops,
+ .ring_mask = &ath12k_wifi7_hw_ring_mask_ipq5332,
+
+ .host_ce_config = ath12k_wifi7_host_ce_config_ipq5332,
+ .ce_count = 12,
+ .target_ce_config = ath12k_wifi7_target_ce_config_wlan_ipq5332,
+ .target_ce_count = 12,
+ .svc_to_ce_map =
+ ath12k_wifi7_target_service_to_ce_map_wlan_ipq5332,
+ .svc_to_ce_map_len = 18,
+
+ .rxdma1_enable = true,
+ .num_rxdma_per_pdev = 1,
+ .num_rxdma_dst_ring = 0,
+ .rx_mac_buf_ring = false,
+ .vdev_start_delay = false,
+
+ .interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT),
+ .supports_monitor = true,
+
+ .idle_ps = false,
+ .download_calib = true,
+ .supports_suspend = false,
+ .tcl_ring_retry = true,
+ .reoq_lut_support = false,
+ .supports_shadow_regs = false,
+
+ .num_tcl_banks = 48,
+ .max_tx_ring = 4,
+
+ .mhi_config = NULL,
+
+ .wmi_init = &ath12k_wifi7_wmi_init_qcn9274,
+
+ .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+ .rfkill_pin = 0,
+ .rfkill_cfg = 0,
+ .rfkill_on_level = 0,
+
+ .rddm_size = 0,
+
+ .def_num_link = 0,
+ .max_mlo_peer = 256,
+
+ .otp_board_id_register = 0,
+
+ .supports_sta_ps = false,
+
+ .acpi_guid = NULL,
+ .supports_dynamic_smps_6ghz = false,
+ .iova_mask = 0,
+ .supports_aspm = false,
+
+ .ce_ie_addr = &ath12k_wifi7_ce_ie_addr_ipq5424,
+ .ce_remap = &ath12k_wifi7_ce_remap_ipq5424,
+ .bdf_addr_offset = 0x940000,
+
+ .current_cc_support = false,
+
+ .dp_primary_link_only = true,
+ },
};
/* Note: called under rcu_read_lock() */
diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c
index 44b04ea3cc8b..32e3e09e7680 100644
--- a/drivers/net/wireless/atmel/at76c50x-usb.c
+++ b/drivers/net/wireless/atmel/at76c50x-usb.c
@@ -2226,34 +2226,20 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
static int at76_alloc_urbs(struct at76_priv *priv,
struct usb_interface *interface)
{
- struct usb_endpoint_descriptor *endpoint, *ep_in, *ep_out;
- int i;
+ struct usb_endpoint_descriptor *ep_in, *ep_out;
int buffer_size;
struct usb_host_interface *iface_desc;
+ int ret;
at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);
at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __func__,
interface->cur_altsetting->desc.bNumEndpoints);
- ep_in = NULL;
- ep_out = NULL;
iface_desc = interface->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
- endpoint = &iface_desc->endpoint[i].desc;
-
- at76_dbg(DBG_URB, "%s: %d. endpoint: addr 0x%x attr 0x%x",
- __func__, i, endpoint->bEndpointAddress,
- endpoint->bmAttributes);
-
- if (!ep_in && usb_endpoint_is_bulk_in(endpoint))
- ep_in = endpoint;
- if (!ep_out && usb_endpoint_is_bulk_out(endpoint))
- ep_out = endpoint;
- }
-
- if (!ep_in || !ep_out) {
+ ret = usb_find_common_endpoints(iface_desc, &ep_in, &ep_out, NULL, NULL);
+ if (ret) {
dev_err(&interface->dev, "bulk endpoints missing\n");
return -ENXIO;
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
index a790f1693b82..4adc0d0e4251 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -1007,18 +1007,33 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci)
core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON,
SI_ENUM_BASE_DEFAULT, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV,
BCM4329_CORE_BUS_BASE, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM,
BCM4329_CORE_SOCRAM_BASE, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3,
BCM4329_CORE_ARM_BASE, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0);
+ if (IS_ERR(core))
+ return PTR_ERR(core);
+
brcmf_chip_sb_corerev(ci, core);
} else if (socitype == SOCI_AI) {
ci->iscoreup = brcmf_chip_ai_iscoreup;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
index 4bacd83db052..22ff326f1924 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
@@ -670,6 +670,9 @@ static int brcmf_fw_request_firmware(const struct firmware **fw,
}
fallback:
+ if (cur->flags & BRCMF_FW_REQF_OPTIONAL)
+ return firmware_request_nowarn(fw, cur->path, fwctx->dev);
+
return request_firmware(fw, cur->path, fwctx->dev);
}
@@ -714,9 +717,10 @@ static void brcmf_fw_request_done_alt_path(const struct firmware *fw, void *ctx)
if (!alt_path)
goto fallback;
- ret = request_firmware_nowait(THIS_MODULE, true, alt_path,
- fwctx->dev, GFP_KERNEL, fwctx,
- brcmf_fw_request_done_alt_path);
+ ret = firmware_request_nowait_nowarn(THIS_MODULE,
+ alt_path, fwctx->dev,
+ GFP_KERNEL, fwctx,
+ brcmf_fw_request_done_alt_path);
kfree(alt_path);
if (ret < 0)
@@ -779,9 +783,10 @@ int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
fwctx->req->board_types[0]);
if (alt_path) {
fwctx->board_index++;
- ret = request_firmware_nowait(THIS_MODULE, true, alt_path,
- fwctx->dev, GFP_KERNEL, fwctx,
- brcmf_fw_request_done_alt_path);
+ ret = firmware_request_nowait_nowarn(THIS_MODULE,
+ alt_path, fwctx->dev,
+ GFP_KERNEL, fwctx,
+ brcmf_fw_request_done_alt_path);
kfree(alt_path);
} else {
ret = request_firmware_nowait(THIS_MODULE, true, first->path,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
index 1681ad00f82e..03efae36a0b2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
@@ -128,7 +128,9 @@ int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
if (err)
brcmf_err("failed to get OF country code map (err=%d)\n", err);
- of_get_mac_address(np, settings->mac);
+ err = of_get_mac_address(np, settings->mac);
+ if (err == -EPROBE_DEFER)
+ return err;
if (bus_type != BRCMF_BUSTYPE_SDIO)
return 0;
diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig
index b92df91adb3a..b508f14542d5 100644
--- a/drivers/net/wireless/intel/ipw2x00/Kconfig
+++ b/drivers/net/wireless/intel/ipw2x00/Kconfig
@@ -154,7 +154,6 @@ config LIBIPW
depends on PCI && CFG80211
select WIRELESS_EXT
select CRYPTO
- select CRYPTO_MICHAEL_MIC
select CRYPTO_LIB_ARC4
select CRC32
help
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
index c6b0de8d91ae..24bb28ab7a49 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
@@ -25,8 +25,6 @@
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
#include <crypto/arc4.h>
-#include <crypto/hash.h>
-#include <linux/crypto.h>
#include <linux/crc32.h>
#include "libipw.h"
@@ -57,11 +55,6 @@ struct libipw_tkip_data {
struct arc4_ctx rx_ctx_arc4;
struct arc4_ctx tx_ctx_arc4;
- struct crypto_shash *rx_tfm_michael;
- struct crypto_shash *tx_tfm_michael;
-
- /* scratch buffers for virt_to_page() (crypto API) */
- u8 rx_hdr[16], tx_hdr[16];
unsigned long flags;
};
@@ -89,41 +82,14 @@ static void *libipw_tkip_init(int key_idx)
priv = kzalloc_obj(*priv, GFP_ATOMIC);
if (priv == NULL)
- goto fail;
+ return priv;
priv->key_idx = key_idx;
-
- priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(priv->tx_tfm_michael)) {
- priv->tx_tfm_michael = NULL;
- goto fail;
- }
-
- priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(priv->rx_tfm_michael)) {
- priv->rx_tfm_michael = NULL;
- goto fail;
- }
-
return priv;
-
- fail:
- if (priv) {
- crypto_free_shash(priv->tx_tfm_michael);
- crypto_free_shash(priv->rx_tfm_michael);
- kfree(priv);
- }
-
- return NULL;
}
static void libipw_tkip_deinit(void *priv)
{
- struct libipw_tkip_data *_priv = priv;
- if (_priv) {
- crypto_free_shash(_priv->tx_tfm_michael);
- crypto_free_shash(_priv->rx_tfm_michael);
- }
kfree_sensitive(priv);
}
@@ -464,73 +430,6 @@ static int libipw_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
return keyidx;
}
-static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr,
- u8 *data, size_t data_len, u8 *mic)
-{
- SHASH_DESC_ON_STACK(desc, tfm_michael);
- int err;
-
- if (tfm_michael == NULL) {
- pr_warn("%s(): tfm_michael == NULL\n", __func__);
- return -1;
- }
-
- desc->tfm = tfm_michael;
-
- if (crypto_shash_setkey(tfm_michael, key, 8))
- return -1;
-
- err = crypto_shash_init(desc);
- if (err)
- goto out;
- err = crypto_shash_update(desc, hdr, 16);
- if (err)
- goto out;
- err = crypto_shash_update(desc, data, data_len);
- if (err)
- goto out;
- err = crypto_shash_final(desc, mic);
-
-out:
- shash_desc_zero(desc);
- return err;
-}
-
-static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
-{
- struct ieee80211_hdr *hdr11;
-
- hdr11 = (struct ieee80211_hdr *)skb->data;
-
- switch (le16_to_cpu(hdr11->frame_control) &
- (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
- case IEEE80211_FCTL_TODS:
- memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
- memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
- break;
- case IEEE80211_FCTL_FROMDS:
- memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
- memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
- break;
- case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
- memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
- break;
- default:
- memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
- memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
- break;
- }
-
- if (ieee80211_is_data_qos(hdr11->frame_control)) {
- hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11)))
- & IEEE80211_QOS_CTL_TID_MASK;
- } else
- hdr[12] = 0; /* priority */
-
- hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
-}
-
static int libipw_michael_mic_add(struct sk_buff *skb, int hdr_len,
void *priv)
{
@@ -544,12 +443,9 @@ static int libipw_michael_mic_add(struct sk_buff *skb, int hdr_len,
return -1;
}
- michael_mic_hdr(skb, tkey->tx_hdr);
pos = skb_put(skb, 8);
- if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
- skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
- return -1;
-
+ michael_mic(&tkey->key[16], (struct ieee80211_hdr *)skb->data,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, pos);
return 0;
}
@@ -583,10 +479,8 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx,
if (!tkey->key_set)
return -1;
- michael_mic_hdr(skb, tkey->rx_hdr);
- if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
- skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
- return -1;
+ michael_mic(&tkey->key[24], (struct ieee80211_hdr *)skb->data,
+ skb->data + hdr_len, skb->len - 8 - hdr_len, mic);
if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -614,17 +508,13 @@ static int libipw_tkip_set_key(void *key, int len, u8 * seq, void *priv)
{
struct libipw_tkip_data *tkey = priv;
int keyidx;
- struct crypto_shash *tfm = tkey->tx_tfm_michael;
struct arc4_ctx *tfm2 = &tkey->tx_ctx_arc4;
- struct crypto_shash *tfm3 = tkey->rx_tfm_michael;
struct arc4_ctx *tfm4 = &tkey->rx_ctx_arc4;
keyidx = tkey->key_idx;
memset(tkey, 0, sizeof(*tkey));
tkey->key_idx = keyidx;
- tkey->tx_tfm_michael = tfm;
tkey->tx_ctx_arc4 = *tfm2;
- tkey->rx_tfm_michael = tfm3;
tkey->rx_ctx_arc4 = *tfm4;
if (len == TKIP_KEY_LEN) {
memcpy(tkey->key, key, TKIP_KEY_LEN);
diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
index c148654aa953..cbaf250626c5 100644
--- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
@@ -979,9 +979,10 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority)
struct page *page;
dma_addr_t page_dma;
unsigned long flags;
- gfp_t gfp_mask = priority;
while (1) {
+ gfp_t gfp_mask = priority;
+
spin_lock_irqsave(&rxq->lock, flags);
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
@@ -1002,9 +1003,9 @@ il3945_rx_allocate(struct il_priv *il, gfp_t priority)
D_INFO("Failed to allocate SKB buffer.\n");
if (rxq->free_count <= RX_LOW_WATERMARK &&
net_ratelimit())
- IL_ERR("Failed to allocate SKB buffer with %0x."
+ IL_ERR("Failed to allocate SKB buffer with %pGg. "
"Only %u free buffers remaining.\n",
- priority, rxq->free_count);
+ &gfp_mask, rxq->free_count);
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c
index 176f2106bab6..4fae0e335136 100644
--- a/drivers/net/wireless/marvell/libertas/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas/if_usb.c
@@ -193,13 +193,12 @@ static void if_usb_reset_olpc_card(struct lbs_private *priv)
static int if_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct usb_endpoint_descriptor *ep_in, *ep_out;
struct usb_device *udev;
struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
struct lbs_private *priv;
struct if_usb_card *cardp;
int r = -ENOMEM;
- int i;
udev = interface_to_usbdev(intf);
@@ -224,25 +223,25 @@ static int if_usb_probe(struct usb_interface *intf,
init_usb_anchor(&cardp->rx_submitted);
init_usb_anchor(&cardp->tx_submitted);
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- if (usb_endpoint_is_bulk_in(endpoint)) {
- cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_in = usb_endpoint_num(endpoint);
+ if (usb_find_common_endpoints_reverse(iface_desc, &ep_in, &ep_out, NULL, NULL)) {
+ lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
+ goto dealloc;
+ }
- lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
- lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+ cardp->ep_in_size = usb_endpoint_maxp(ep_in);
+ cardp->ep_in = usb_endpoint_num(ep_in);
- } else if (usb_endpoint_is_bulk_out(endpoint)) {
- cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_out = usb_endpoint_num(endpoint);
+ lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
+ lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+
+ cardp->ep_out_size = usb_endpoint_maxp(ep_out);
+ cardp->ep_out = usb_endpoint_num(ep_out);
+
+ lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+ lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
- lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
- lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
- }
- }
if (!cardp->ep_out_size || !cardp->ep_in_size) {
- lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
+ lbs_deb_usbd(&udev->dev, "Endpoints not valid\n");
goto dealloc;
}
if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
index 07b38f2b8f58..b85c6d783bf7 100644
--- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c
@@ -144,12 +144,12 @@ static const struct lbtf_ops if_usb_ops = {
static int if_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct usb_endpoint_descriptor *ep_in, *ep_out;
struct usb_device *udev;
struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
struct lbtf_private *priv;
struct if_usb_card *cardp;
- int i;
+ int ret;
lbtf_deb_enter(LBTF_DEB_USB);
udev = interface_to_usbdev(intf);
@@ -171,31 +171,27 @@ static int if_usb_probe(struct usb_interface *intf,
udev->descriptor.bDeviceSubClass,
udev->descriptor.bDeviceProtocol);
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- if (usb_endpoint_is_bulk_in(endpoint)) {
- cardp->ep_in_size =
- le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_in = usb_endpoint_num(endpoint);
-
- lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n",
- cardp->ep_in);
- lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n",
- cardp->ep_in_size);
- } else if (usb_endpoint_is_bulk_out(endpoint)) {
- cardp->ep_out_size =
- le16_to_cpu(endpoint->wMaxPacketSize);
- cardp->ep_out = usb_endpoint_num(endpoint);
-
- lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n",
- cardp->ep_out);
- lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n",
- cardp->ep_out_size);
- }
+ ret = usb_find_common_endpoints_reverse(iface_desc, &ep_in, &ep_out,
+ NULL, NULL);
+ if (ret) {
+ lbtf_deb_usbd(&udev->dev, "Endpoints not found\n");
+ goto dealloc;
}
+
+ cardp->ep_in_size = usb_endpoint_maxp(ep_in);
+ cardp->ep_in = usb_endpoint_num(ep_in);
+
+ lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
+ lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
+
+ cardp->ep_out_size = usb_endpoint_maxp(ep_out);
+ cardp->ep_out = usb_endpoint_num(ep_out);
+
+ lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+ lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
+
if (!cardp->ep_out_size || !cardp->ep_in_size) {
- lbtf_deb_usbd(&udev->dev, "Endpoints not found\n");
- /* Endpoints not found */
+ lbtf_deb_usbd(&udev->dev, "Endpoints not valid\n");
goto dealloc;
}
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
index 944b2a812b63..009c4770a6f9 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.c
+++ b/drivers/net/wireless/microchip/wilc1000/hif.c
@@ -1123,7 +1123,7 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
wid_list[0].size = sizeof(char);
wid_list[0].val = (s8 *)&cipher_mode;
- key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+ key_buf = kzalloc_flex(*key_buf, key, t_key_len);
if (!key_buf)
return -ENOMEM;
@@ -1151,7 +1151,7 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
struct wid wid;
struct wilc_sta_wpa_ptk *key_buf;
- key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+ key_buf = kzalloc_flex(*key_buf, key, t_key_len);
if (!key_buf)
return -ENOMEM;
@@ -1186,7 +1186,7 @@ int wilc_add_igtk(struct wilc_vif *vif, const u8 *igtk, u8 igtk_key_len,
struct wid wid;
struct wilc_wpa_igtk *key_buf;
- key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+ key_buf = kzalloc_flex(*key_buf, key, t_key_len);
if (!key_buf)
return -ENOMEM;
@@ -1217,7 +1217,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
struct wilc_gtk_key *gtk_key;
int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;
- gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);
+ gtk_key = kzalloc_flex(*gtk_key, key, t_key_len);
if (!gtk_key)
return -ENOMEM;
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index f7e0f6573180..1d21c468a236 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -1475,8 +1475,6 @@ static int rtl8187_probe(struct usb_interface *intf,
usb_set_intfdata(intf, dev);
priv->udev = udev;
- usb_get_dev(udev);
-
skb_queue_head_init(&priv->rx_queue);
BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels));
@@ -1663,7 +1661,6 @@ static int rtl8187_probe(struct usb_interface *intf,
err_free_dmabuf:
kfree(priv->io_dmabuf);
usb_set_intfdata(intf, NULL);
- usb_put_dev(udev);
err_free_dev:
ieee80211_free_hw(dev);
return err;
@@ -1685,7 +1682,6 @@ static void rtl8187_disconnect(struct usb_interface *intf)
priv = dev->priv;
usb_reset_device(priv->udev);
- usb_put_dev(interface_to_usbdev(intf));
kfree(priv->io_dmabuf);
ieee80211_free_hw(dev);
}
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c
index 804fc604e5f8..f20fade0c099 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c
@@ -4697,20 +4697,6 @@ static const struct ieee80211_rate rtl8xxxu_legacy_ratetable[] = {
{.bitrate = 540, .hw_value = 0x0b,},
};
-static void rtl8xxxu_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
-{
- if (rate <= DESC_RATE_54M)
- return;
-
- if (rate >= DESC_RATE_MCS0 && rate <= DESC_RATE_MCS15) {
- if (rate < DESC_RATE_MCS8)
- *nss = 1;
- else
- *nss = 2;
- *mcs = rate - DESC_RATE_MCS0;
- }
-}
-
static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg)
{
struct ieee80211_hw *hw = priv->hw;
@@ -4820,23 +4806,25 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time)
void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt,
u8 rate, u8 sgi, u8 bw)
{
- u8 mcs, nss;
-
rarpt->txrate.flags = 0;
if (rate <= DESC_RATE_54M) {
rarpt->txrate.legacy = rtl8xxxu_legacy_ratetable[rate].bitrate;
- } else {
- rtl8xxxu_desc_to_mcsrate(rate, &mcs, &nss);
+ } else if (rate >= DESC_RATE_MCS0 && rate <= DESC_RATE_MCS15) {
rarpt->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ if (rate < DESC_RATE_MCS8)
+ rarpt->txrate.nss = 1;
+ else
+ rarpt->txrate.nss = 2;
- rarpt->txrate.mcs = mcs;
- rarpt->txrate.nss = nss;
+ rarpt->txrate.mcs = rate - DESC_RATE_MCS0;
if (sgi)
rarpt->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
rarpt->txrate.bw = bw;
+ } else {
+ return;
}
rarpt->bit_rate = cfg80211_calculate_bitrate(&rarpt->txrate);
@@ -7698,11 +7686,12 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
int ret;
int untested = 1;
- udev = usb_get_dev(interface_to_usbdev(interface));
+ udev = interface_to_usbdev(interface);
switch (id->idVendor) {
case USB_VENDOR_ID_REALTEK:
switch(id->idProduct) {
+ case 0x0179:
case 0x1724:
case 0x8176:
case 0x8178:
@@ -7756,10 +7745,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
}
hw = ieee80211_alloc_hw(sizeof(struct rtl8xxxu_priv), &rtl8xxxu_ops);
- if (!hw) {
- ret = -ENOMEM;
- goto err_put_dev;
- }
+ if (!hw)
+ return -ENOMEM;
priv = hw->priv;
priv->hw = hw;
@@ -7901,8 +7888,6 @@ err_set_intfdata:
mutex_destroy(&priv->h2c_mutex);
ieee80211_free_hw(hw);
-err_put_dev:
- usb_put_dev(udev);
return ret;
}
@@ -7935,7 +7920,6 @@ static void rtl8xxxu_disconnect(struct usb_interface *interface)
"Device still attached, trying to reset\n");
usb_reset_device(priv->udev);
}
- usb_put_dev(priv->udev);
ieee80211_free_hw(hw);
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c
index 19e2ff62d9f1..9cc0a871ea3c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/pci.c
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.c
@@ -1674,6 +1674,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw)
synchronize_irq(rtlpci->pdev->irq);
tasklet_kill(&rtlpriv->works.irq_tasklet);
+ tasklet_kill(&rtlpriv->works.irq_prepare_bcn_tasklet);
cancel_work_sync(&rtlpriv->works.lps_change_work);
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192d/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192d/fw_common.c
index aa54dbde6ea8..a255a5061d77 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192d/fw_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192d/fw_common.c
@@ -212,9 +212,9 @@ void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 boxcontent[4], boxextcontent[2];
u16 box_reg = 0, box_extreg = 0;
- u8 wait_writeh2c_limmit = 100;
+ u8 wait_writeh2c_limit = 100;
bool bwrite_success = false;
- u8 wait_h2c_limmit = 100;
+ u8 wait_h2c_limit = 100;
u32 h2c_waitcounter = 0;
bool isfw_read = false;
unsigned long flag;
@@ -261,8 +261,8 @@ void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
}
while (!bwrite_success) {
- wait_writeh2c_limmit--;
- if (wait_writeh2c_limmit == 0) {
+ wait_writeh2c_limit--;
+ if (wait_writeh2c_limit == 0) {
pr_err("Write H2C fail because no trigger for FW INT!\n");
break;
}
@@ -278,8 +278,8 @@ void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
while (!isfw_read) {
- wait_h2c_limmit--;
- if (wait_h2c_limmit == 0) {
+ wait_h2c_limit--;
+ if (wait_h2c_limit == 0) {
rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
"Waiting too long for FW read clear HMEBox(%d)!\n",
boxnum);
diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c
index d35ed56d6db9..9a64df9eed39 100644
--- a/drivers/net/wireless/realtek/rtlwifi/usb.c
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.c
@@ -986,7 +986,6 @@ int rtl_usb_probe(struct usb_interface *intf,
init_completion(&rtlpriv->firmware_loading_complete);
SET_IEEE80211_DEV(hw, &intf->dev);
udev = interface_to_usbdev(intf);
- usb_get_dev(udev);
usb_priv = rtl_usbpriv(hw);
memset(usb_priv, 0, sizeof(*usb_priv));
usb_priv->dev.intf = intf;
@@ -1038,7 +1037,6 @@ error_out:
rtl_deinit_core(hw);
error_out2:
_rtl_usb_io_handler_release(hw);
- usb_put_dev(udev);
kfree(rtlpriv->usb_data);
ieee80211_free_hw(hw);
return -ENODEV;
@@ -1050,7 +1048,6 @@ void rtl_usb_disconnect(struct usb_interface *intf)
struct ieee80211_hw *hw = usb_get_intfdata(intf);
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
- struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
if (unlikely(!rtlpriv))
return;
@@ -1072,7 +1069,6 @@ void rtl_usb_disconnect(struct usb_interface *intf)
kfree(rtlpriv->usb_data);
rtlpriv->cfg->ops->deinit_sw_vars(hw);
_rtl_usb_io_handler_release(hw);
- usb_put_dev(rtlusb->udev);
usb_set_intfdata(intf, NULL);
ieee80211_free_hw(hw);
}
diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c
index b4dc6ff2c175..37c336def419 100644
--- a/drivers/net/wireless/realtek/rtw88/coex.c
+++ b/drivers/net/wireless/realtek/rtw88/coex.c
@@ -485,6 +485,13 @@ static void rtw_coex_monitor_bt_ctr(struct rtw_dev *rtwdev)
"[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n",
coex_stat->hi_pri_rx, coex_stat->hi_pri_tx,
coex_stat->lo_pri_rx, coex_stat->lo_pri_tx);
+
+ if (coex_stat->wl_under_lps || coex_stat->wl_under_ips ||
+ (coex_stat->hi_pri_rx > 60000 && coex_stat->hi_pri_tx == 60000 &&
+ coex_stat->lo_pri_rx > 60000 && coex_stat->lo_pri_tx == 60000))
+ coex_stat->bt_ctr_ok = false;
+ else
+ coex_stat->bt_ctr_ok = true;
}
static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
@@ -1959,14 +1966,18 @@ static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse;
+ bool is_bt_ctr_hi = false, is_toggle_table = false;
u8 table_case, tdma_case;
u32 slot_type = 0;
- bool bt_multi_link_remain = false, is_toggle_table = false;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+ if (coex_stat->bt_ctr_ok &&
+ coex_stat->lo_pri_rx + coex_stat->lo_pri_tx > 360)
+ is_bt_ctr_hi = true;
+
if (efuse->share_ant) {
/* Shared-Ant */
if (coex_stat->bt_ble_exist) {
@@ -1980,28 +1991,31 @@ static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)
}
} else {
/* Legacy HID */
- if (coex_stat->bt_profile_num == 1 &&
- (coex_stat->bt_multi_link ||
- (coex_stat->lo_pri_rx +
- coex_stat->lo_pri_tx > 360) ||
- coex_stat->bt_slave ||
- bt_multi_link_remain)) {
- slot_type = TDMA_4SLOT;
- table_case = 12;
- tdma_case = 20;
- } else if (coex_stat->bt_a2dp_active) {
+ if (coex_stat->bt_a2dp_active) {
table_case = 9;
tdma_case = 18;
+ } else if (coex_stat->bt_profile_num == 1 &&
+ (coex_stat->bt_multi_link &&
+ (is_bt_ctr_hi || coex_stat->bt_slave ||
+ coex_stat->bt_multi_link_remain))) {
+ if (coex_stat->wl_gl_busy &&
+ (coex_stat->wl_rx_rate <= 3 ||
+ coex_stat->wl_rts_rx_rate <= 3))
+ table_case = 13;
+ else
+ table_case = 12;
+
+ tdma_case = 26;
} else if (coex_stat->bt_418_hid_exist &&
coex_stat->wl_gl_busy) {
is_toggle_table = true;
slot_type = TDMA_4SLOT;
- table_case = 9;
- tdma_case = 24;
+ table_case = 32;
+ tdma_case = 27;
} else if (coex_stat->bt_ble_hid_exist &&
coex_stat->wl_gl_busy) {
- table_case = 32;
- tdma_case = 9;
+ table_case = 36;
+ tdma_case = 0;
} else {
table_case = 9;
tdma_case = 9;
@@ -3095,6 +3109,9 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
for (i = 0; i < COEX_BTINFO_LENGTH; i++)
coex_stat->bt_info_c2h[rsp_source][i] = buf[i];
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A)
+ coex_stat->bt_info_c2h[rsp_source][5] = 0;
+
/* get the same info from bt, skip it */
if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 &&
coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 &&
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index c4f9758b4e96..cd9254370fcc 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1805,6 +1805,7 @@ static void rtw_load_firmware_cb(const struct firmware *firmware, void *context)
{
struct rtw_fw_state *fw = context;
struct rtw_dev *rtwdev = fw->rtwdev;
+ struct wiphy *wiphy = rtwdev->hw->wiphy;
if (!firmware || !firmware->data) {
rtw_err(rtwdev, "failed to request firmware\n");
@@ -1819,6 +1820,11 @@ static void rtw_load_firmware_cb(const struct firmware *firmware, void *context)
rtw_info(rtwdev, "%sFirmware version %u.%u.%u, H2C version %u\n",
fw->type == RTW_WOWLAN_FW ? "WOW " : "",
fw->version, fw->sub_version, fw->sub_index, fw->h2c_version);
+
+ if (fw->type == RTW_NORMAL_FW)
+ snprintf(wiphy->fw_version, sizeof(wiphy->fw_version),
+ "%u.%u.%u",
+ fw->version, fw->sub_version, fw->sub_index);
}
static int rtw_load_firmware(struct rtw_dev *rtwdev, enum rtw_fw_type type)
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 1ab70214ce36..9c0b746540b0 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -432,6 +432,11 @@ enum rtw_wow_flags {
RTW_WOW_FLAG_MAX,
};
+enum rtw_quirk_dis_caps {
+ QUIRK_DIS_CAP_PCI_ASPM,
+ QUIRK_DIS_CAP_LPS_DEEP,
+};
+
/* the power index is represented by differences, which cck-1s & ht40-1s are
* the base values, so for 1s's differences, there are only ht20 & ofdm
*/
@@ -1475,6 +1480,7 @@ struct rtw_coex_stat {
bool bt_game_hid_exist;
bool bt_hid_handle_cnt;
bool bt_mailbox_reply;
+ bool bt_ctr_ok;
bool wl_under_lps;
bool wl_under_ips;
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 56b16186d3aa..bba370ad510c 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2018-2019 Realtek Corporation
*/
+#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "main.h"
@@ -1744,6 +1745,34 @@ const struct pci_error_handlers rtw_pci_err_handler = {
};
EXPORT_SYMBOL(rtw_pci_err_handler);
+static int rtw_pci_disable_caps(const struct dmi_system_id *dmi)
+{
+ uintptr_t dis_caps = (uintptr_t)dmi->driver_data;
+
+ if (dis_caps & BIT(QUIRK_DIS_CAP_PCI_ASPM))
+ rtw_pci_disable_aspm = true;
+
+ if (dis_caps & BIT(QUIRK_DIS_CAP_LPS_DEEP))
+ rtw_disable_lps_deep_mode = true;
+
+ return 1;
+}
+
+static const struct dmi_system_id rtw_pci_quirks[] = {
+ {
+ .callback = rtw_pci_disable_caps,
+ .ident = "HP Notebook - P3S95EA#ACB",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Notebook"),
+ DMI_MATCH(DMI_PRODUCT_SKU, "P3S95EA#ACB"),
+ },
+ .driver_data = (void *)(BIT(QUIRK_DIS_CAP_PCI_ASPM) |
+ BIT(QUIRK_DIS_CAP_LPS_DEEP)),
+ },
+ {}
+};
+
int rtw_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -1771,6 +1800,8 @@ int rtw_pci_probe(struct pci_dev *pdev,
rtwpci = (struct rtw_pci *)rtwdev->priv;
atomic_set(&rtwpci->link_usage, 1);
+ dmi_check_system(rtw_pci_quirks);
+
ret = rtw_core_init(rtwdev);
if (ret)
goto err_release_hw;
@@ -1804,7 +1835,8 @@ int rtw_pci_probe(struct pci_dev *pdev,
}
/* Disable PCIe ASPM L1 while doing NAPI poll for 8821CE */
- if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C && bridge->vendor == PCI_VENDOR_ID_INTEL)
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C &&
+ bridge && bridge->vendor == PCI_VENDOR_ID_INTEL)
rtwpci->rx_no_aspm = true;
rtw_pci_phy_cfg(rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c
index 821c28d9cb5d..b5e7ae7ebd95 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c
@@ -1794,6 +1794,11 @@ static const struct coex_table_para table_sant_8703b[] = {
{0x66556aaa, 0x6a5a6aaa}, /* case-30 */
{0xffffffff, 0x5aaa5aaa},
{0x56555555, 0x5a5a5aaa},
+ {0xdaffdaff, 0xdaffdaff},
+ {0xddffddff, 0xddffddff},
+ {0xe5555555, 0xe5555555}, /* case-35 */
+ {0xea5a5a5a, 0xea5a5a5a},
+ {0xea6a6a6a, 0xea6a6a6a},
};
/* Shared-Antenna TDMA */
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c
index 8715e0435f17..a2b3e7a2ad99 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c
@@ -1459,6 +1459,11 @@ static const struct coex_table_para table_sant_8723d[] = {
{0x66556aaa, 0x6a5a6aaa}, /* case-30 */
{0xffffffff, 0x5aaa5aaa},
{0x56555555, 0x5a5a5aaa},
+ {0xdaffdaff, 0xdaffdaff},
+ {0xddffddff, 0xddffddff},
+ {0xe5555555, 0xe5555555}, /* case-35 */
+ {0xea5a5a5a, 0xea5a5a5a},
+ {0xea6a6a6a, 0xea6a6a6a},
};
/* Non-Shared-Antenna Coex Table */
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
index 414b77eef07c..cab85203b828 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c
@@ -998,7 +998,12 @@ static const struct coex_table_para table_sant_8821a[] = {
{0x66556655, 0x66556655},
{0x66556aaa, 0x6a5a6aaa}, /* case-30 */
{0xffffffff, 0x5aaa5aaa},
- {0x56555555, 0x5a5a5aaa}
+ {0x56555555, 0x5a5a5aaa},
+ {0xdaffdaff, 0xdaffdaff},
+ {0xddffddff, 0xddffddff},
+ {0xe5555555, 0xe5555555}, /* case-35 */
+ {0xea5a5a5a, 0xea5a5a5a},
+ {0xea6a6a6a, 0xea6a6a6a},
};
/* Non-Shared-Antenna Coex Table */
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
index 2078b067562e..246046da4f13 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
@@ -1727,7 +1727,12 @@ static const struct coex_table_para table_sant_8821c[] = {
{0x66556655, 0x66556655},
{0x66556aaa, 0x6a5a6aaa}, /* case-30 */
{0xffffffff, 0x5aaa5aaa},
- {0x56555555, 0x5a5a5aaa}
+ {0x56555555, 0x5a5a5aaa},
+ {0xdaffdaff, 0xdaffdaff},
+ {0xddffddff, 0xddffddff},
+ {0xe5555555, 0xe5555555}, /* case-35 */
+ {0xea5a5a5a, 0xea5a5a5a},
+ {0xea6a6a6a, 0xea6a6a6a},
};
/* Non-Shared-Antenna Coex Table */
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
index 4d88cc2f4148..e9e8a7f3f382 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c
@@ -2217,6 +2217,11 @@ static const struct coex_table_para table_sant_8822b[] = {
{0x66556aaa, 0x6a5a6aaa}, /* case-30 */
{0xffffffff, 0x5aaa5aaa},
{0x56555555, 0x5a5a5aaa},
+ {0xdaffdaff, 0xdaffdaff},
+ {0xddffddff, 0xddffddff},
+ {0xe5555555, 0xe5555555}, /* case-35 */
+ {0xea5a5a5a, 0xea5a5a5a},
+ {0xea6a6a6a, 0xea6a6a6a},
};
/* Non-Shared-Antenna Coex Table */
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 28c121cf1e68..244c8026479c 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -5035,6 +5035,9 @@ static const struct coex_table_para table_sant_8822c[] = {
{0x56555555, 0x5a5a5aaa},
{0xdaffdaff, 0xdaffdaff},
{0xddffddff, 0xddffddff},
+ {0xe5555555, 0xe5555555}, /* case-35 */
+ {0xea5a5a5a, 0xea5a5a5a},
+ {0xea6a6a6a, 0xea6a6a6a},
};
/* Non-Shared-Antenna Coex Table */
@@ -5401,7 +5404,7 @@ const struct rtw_chip_info rtw8822c_hw_spec = {
.max_sched_scan_ssids = 4,
#endif
.max_scan_ie_len = (RTW_PROBE_PG_CNT - 1) * TX_PAGE_SIZE,
- .coex_para_ver = 0x22020720,
+ .coex_para_ver = 0x26020420,
.bt_desired_ver = 0x20,
.scbd_support = true,
.new_scbd10_def = true,
diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c
index 8b0afaaffaa0..d9e11343d498 100644
--- a/drivers/net/wireless/realtek/rtw88/rx.c
+++ b/drivers/net/wireless/realtek/rtw88/rx.c
@@ -295,6 +295,14 @@ void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL);
+ if (unlikely(pkt_stat->rate >= DESC_RATE_MAX)) {
+ rtw_dbg(rtwdev, RTW_DBG_UNEXP,
+ "unexpected RX rate=0x%x\n", pkt_stat->rate);
+
+ pkt_stat->rate = DESC_RATE1M;
+ pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
+ }
+
/* drv_info_sz is in unit of 8-bytes */
pkt_stat->drv_info_sz *= 8;
diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c
index 2ab440cb2d67..3106edb84fb4 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.c
+++ b/drivers/net/wireless/realtek/rtw88/tx.c
@@ -421,7 +421,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev,
pkt_info->mac_id = rtwvif->mac_id;
}
- if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc))
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc))
rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb);
else if (ieee80211_is_data(fc))
rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb);
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index 433b06c8d8a6..718940ebba31 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -1041,7 +1041,7 @@ static int rtw_usb_intf_init(struct rtw_dev *rtwdev,
struct usb_interface *intf)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
- struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf));
+ struct usb_device *udev = interface_to_usbdev(intf);
int ret;
rtwusb->udev = udev;
@@ -1067,7 +1067,6 @@ static void rtw_usb_intf_deinit(struct rtw_dev *rtwdev,
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
- usb_put_dev(rtwusb->udev);
kfree(rtwusb->usb_data);
usb_set_intfdata(intf, NULL);
}
diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index 9b2f6f0a00fd..ceb399fc2b94 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -276,7 +276,6 @@ void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
}
hal->roc_chandef = *chandef;
- hal->roc_link_index = rtw89_vif_link_inst_get_index(rtwvif_link);
} else {
cur = atomic_cmpxchg(&hal->roc_chanctx_idx, idx,
RTW89_CHANCTX_IDLE);
@@ -382,6 +381,23 @@ static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev,
rtw89_swap_chanctx(rtwdev, rtwvif_link->chanctx_idx, cur->chanctx_idx);
}
+static u8 rtw89_entity_role_get_index(struct rtw89_dev *rtwdev)
+{
+ enum rtw89_entity_mode mode;
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ default:
+ WARN(1, "Invalid ent mode: %d\n", mode);
+ fallthrough;
+ case RTW89_ENTITY_MODE_SCC_OR_SMLD:
+ case RTW89_ENTITY_MODE_MCC:
+ return 0;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ return 1;
+ }
+}
+
const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
const char *caller_message,
u8 link_index, bool nullchk)
@@ -389,8 +405,6 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
enum rtw89_chanctx_idx chanctx_idx;
- enum rtw89_chanctx_idx roc_idx;
- enum rtw89_entity_mode mode;
u8 role_index;
lockdep_assert_wiphy(rtwdev->hw->wiphy);
@@ -401,33 +415,12 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
goto dflt;
}
- mode = rtw89_get_entity_mode(rtwdev);
- switch (mode) {
- case RTW89_ENTITY_MODE_SCC_OR_SMLD:
- case RTW89_ENTITY_MODE_MCC:
- role_index = 0;
- break;
- case RTW89_ENTITY_MODE_MCC_PREPARE:
- role_index = 1;
- break;
- default:
- WARN(1, "Invalid ent mode: %d\n", mode);
- goto dflt;
- }
+ role_index = rtw89_entity_role_get_index(rtwdev);
chanctx_idx = mgnt->chanctx_tbl[role_index][link_index];
if (chanctx_idx == RTW89_CHANCTX_IDLE)
goto dflt;
- roc_idx = atomic_read(&hal->roc_chanctx_idx);
- if (roc_idx != RTW89_CHANCTX_IDLE) {
- /* ROC is ongoing (given ROC runs on @hal->roc_link_index).
- * If @link_index is the same, get the ongoing ROC chanctx.
- */
- if (link_index == hal->roc_link_index)
- chanctx_idx = roc_idx;
- }
-
return rtw89_chan_get(rtwdev, chanctx_idx);
dflt:
@@ -490,10 +483,28 @@ rtw89_entity_sel_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws)
}
}
-static
-void rtw89_entity_recalc_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws)
+static void rtw89_entity_recalc_mlo_dbcc_mode(struct rtw89_dev *rtwdev)
{
+ struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt;
enum rtw89_mlo_dbcc_mode mode;
+ struct rtw89_vif *role;
+ u8 active_hws = 0;
+ u8 ridx;
+
+ ridx = rtw89_entity_role_get_index(rtwdev);
+ role = mgnt->active_roles[ridx];
+ if (role) {
+ struct rtw89_vif_link *link;
+ int i;
+
+ for (i = 0; i < role->links_inst_valid_num; i++) {
+ link = rtw89_vif_get_link_inst(role, i);
+ if (!link || !link->chanctx_assigned)
+ continue;
+
+ active_hws |= BIT(i);
+ }
+ }
mode = rtw89_entity_sel_mlo_dbcc_mode(rtwdev, active_hws);
rtwdev->mlo_dbcc_mode = mode;
@@ -507,7 +518,6 @@ static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
struct rtw89_vif_link *link;
struct rtw89_vif *role;
- u8 active_hws = 0;
u8 pos = 0;
int i, j;
@@ -556,13 +566,10 @@ fill:
continue;
mgnt->chanctx_tbl[pos][i] = link->chanctx_idx;
- active_hws |= BIT(i);
}
mgnt->active_roles[pos++] = role;
}
-
- rtw89_entity_recalc_mlo_dbcc_mode(rtwdev, active_hws);
}
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
@@ -632,6 +639,9 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
return rtw89_get_entity_mode(rtwdev);
rtw89_set_entity_mode(rtwdev, mode);
+
+ rtw89_entity_recalc_mlo_dbcc_mode(rtwdev);
+
return mode;
}
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 36e988277b2b..70feab97dccb 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -463,7 +463,7 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
chan = rtw89_mgnt_chan_get(rtwdev, 0);
__rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_0);
- if (!rtwdev->support_mlo)
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_AX)
return;
chan = rtw89_mgnt_chan_get(rtwdev, 1);
@@ -558,7 +558,7 @@ int rtw89_set_channel(struct rtw89_dev *rtwdev)
chan = rtw89_mgnt_chan_get(rtwdev, 0);
__rtw89_set_channel(rtwdev, chan, RTW89_MAC_0, RTW89_PHY_0);
- if (!rtwdev->support_mlo)
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_AX)
return 0;
chan = rtw89_mgnt_chan_get(rtwdev, 1);
@@ -3203,7 +3203,7 @@ static void rtw89_core_update_rx_freq_from_ie(struct rtw89_dev *rtwdev,
u8 *variable;
int chan;
- if (!rtwdev->chip->rx_freq_frome_ie)
+ if (!rtwdev->chip->rx_freq_from_ie)
return;
if (!rtwdev->scanning)
@@ -3272,6 +3272,114 @@ out:
rcu_read_unlock();
}
+static void __rtw89_core_tid_rx_stats_reset(struct rtw89_tid_stats *tid_stats)
+{
+ tid_stats->last_pn = -1LL;
+ tid_stats->last_sn = IEEE80211_SN_MASK;
+}
+
+void rtw89_core_tid_rx_stats_ctrl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+ struct ieee80211_ampdu_params *params, bool enable)
+{
+ struct rtw89_tid_stats *tid_stats;
+ u16 tid = params->tid;
+
+ tid_stats = &rtwsta->tid_rx_stats[tid];
+
+ if (enable) {
+ __rtw89_core_tid_rx_stats_reset(tid_stats);
+ tid_stats->started = true;
+ } else {
+ tid_stats->started = false;
+ }
+}
+
+void rtw89_core_tid_rx_stats_reset(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_tid_stats *tid_stats;
+ struct ieee80211_sta *sta;
+ struct rtw89_sta *rtwsta;
+ u16 tid;
+
+ for_each_station(sta, rtwdev->hw) {
+ rtwsta = sta_to_rtwsta(sta);
+
+ for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
+ tid_stats = &rtwsta->tid_rx_stats[tid];
+
+ if (!tid_stats->started)
+ continue;
+
+ __rtw89_core_tid_rx_stats_reset(tid_stats);
+ }
+ }
+}
+
+static bool rtw89_core_skb_pn_valid(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_desc_info *desc_info,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_sta_link *rtwsta_link;
+ struct rtw89_tid_stats *tid_stats;
+ struct rtw89_sta *rtwsta;
+ u8 tid, *ccmp_hdr_ptr;
+ s64 pn, last_pn;
+ u16 mpdu_sn;
+ int hdrlen;
+
+ if (chip->chip_gen != RTW89_CHIP_AX)
+ return true;
+
+ if (!ieee80211_is_data_qos(hdr->frame_control))
+ return true;
+
+ if (!desc_info->hw_dec || !desc_info->addr1_match)
+ return true;
+
+ guard(rcu)();
+
+ rtwsta_link = rtw89_assoc_link_rcu_dereference(rtwdev, desc_info->mac_id);
+ if (!rtwsta_link)
+ return true;
+
+ rtwsta = rtwsta_link->rtwsta;
+ tid = ieee80211_get_tid(hdr);
+ tid_stats = &rtwsta->tid_rx_stats[tid];
+
+ if (!tid_stats->started)
+ return true;
+
+ switch (desc_info->sec_type) {
+ case RTW89_SEC_KEY_TYPE_CCMP128:
+ case RTW89_SEC_KEY_TYPE_CCMP256:
+ case RTW89_SEC_KEY_TYPE_GCMP128:
+ case RTW89_SEC_KEY_TYPE_GCMP256:
+ mpdu_sn = ieee80211_get_sn(hdr);
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ ccmp_hdr_ptr = skb->data + hdrlen;
+ ccmp_hdr2pn(&pn, ccmp_hdr_ptr);
+ last_pn = tid_stats->last_pn;
+
+ if (pn > last_pn) {
+ if (ieee80211_sn_less(mpdu_sn, tid_stats->last_sn)) {
+ dev_kfree_skb_any(skb);
+
+ return false;
+ }
+
+ tid_stats->last_sn = mpdu_sn;
+ tid_stats->last_pn = pn;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev,
struct rtw89_rx_phy_ppdu *phy_ppdu,
struct rtw89_rx_desc_info *desc_info,
@@ -3421,6 +3529,7 @@ void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev,
desc_info->sec_cam_id = le32_get_bits(rxd_l->dword5, AX_RXD_SEC_CAM_IDX_MASK);
desc_info->mac_id = le32_get_bits(rxd_l->dword5, AX_RXD_MAC_ID_MASK);
desc_info->rx_pl_id = le32_get_bits(rxd_l->dword5, AX_RXD_RX_PL_ID_MASK);
+ desc_info->sec_type = le32_get_bits(rxd_l->dword7, AX_RXD_SEC_TYPE_MASK);
}
EXPORT_SYMBOL(rtw89_core_query_rxdesc);
@@ -3450,6 +3559,7 @@ void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev,
desc_info->mac_id = le32_get_bits(rxd_s->dword2, BE_RXD_MAC_ID_MASK);
desc_info->addr_cam_valid = le32_get_bits(rxd_s->dword2, BE_RXD_ADDR_CAM_VLD);
+ desc_info->sec_type = le32_get_bits(rxd_s->dword3, BE_RXD_SEC_TYPE_MASK);
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);
@@ -3523,6 +3633,7 @@ void rtw89_core_query_rxdesc_v3(struct rtw89_dev *rtwdev,
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->sec_type = le32_get_bits(rxd_s->dword3, BE_RXD_SEC_TYPE_MASK);
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);
@@ -3802,6 +3913,10 @@ void rtw89_core_rx(struct rtw89_dev *rtwdev,
memset(rx_status, 0, sizeof(*rx_status));
rtw89_core_update_rx_status(rtwdev, skb, desc_info, rx_status);
rtw89_core_rx_pkt_hdl(rtwdev, skb, desc_info);
+
+ if (!rtw89_core_skb_pn_valid(rtwdev, desc_info, skb))
+ return;
+
if (desc_info->long_rxdesc &&
BIT(desc_info->frame_type) & PPDU_FILTER_BITMAP)
skb_queue_tail(&ppdu_sts->rx_queue[band], skb);
@@ -4713,6 +4828,35 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
rtw89_enter_lps_track(rtwdev);
}
+void rtw89_core_dm_disable_cfg(struct rtw89_dev *rtwdev, u32 new)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 old = hal->disabled_dm_bitmap;
+
+ if (new == old)
+ return;
+
+ hal->disabled_dm_bitmap = new;
+
+ rtw89_debug(rtwdev, RTW89_DBG_STATE, "Disable DM: 0x%x -> 0x%x\n", old, new);
+}
+
+void rtw89_core_dm_disable_set(struct rtw89_dev *rtwdev, enum rtw89_dm_type type)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 cur = hal->disabled_dm_bitmap;
+
+ rtw89_core_dm_disable_cfg(rtwdev, cur | BIT(type));
+}
+
+void rtw89_core_dm_disable_clr(struct rtw89_dev *rtwdev, enum rtw89_dm_type type)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 cur = hal->disabled_dm_bitmap;
+
+ rtw89_core_dm_disable_cfg(rtwdev, cur & ~BIT(type));
+}
+
u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size)
{
unsigned long bit;
@@ -6118,7 +6262,6 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
return -ENOMEM;
spin_lock_init(&rtwdev->ba_lock);
spin_lock_init(&rtwdev->rpwm_lock);
- mutex_init(&rtwdev->rf_mutex);
rtwdev->total_sta_assoc = 0;
rtw89_init_wait(&rtwdev->mcc.wait);
@@ -6177,7 +6320,6 @@ void rtw89_core_deinit(struct rtw89_dev *rtwdev)
__rtw89_fw_free_all_early_h2c(rtwdev);
destroy_workqueue(rtwdev->txq_wq);
- mutex_destroy(&rtwdev->rf_mutex);
}
EXPORT_SYMBOL(rtw89_core_deinit);
@@ -6753,7 +6895,8 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
bool support_mlo;
bool no_chanctx;
- firmware = rtw89_early_fw_feature_recognize(device, chip, &early_fw, &fw_format);
+ firmware = rtw89_early_fw_feature_recognize(device, chip, variant,
+ &early_fw, &fw_format);
ops = kmemdup(&rtw89_ops, sizeof(rtw89_ops), GFP_KERNEL);
if (!ops)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 4778957d6b2d..fd29dbbb120d 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -873,6 +873,14 @@ enum rtw89_phy_idx {
RTW89_PHY_NUM,
};
+enum rtw89_fbtc_bt_index {
+ BTC_BT_1ST = 0x0,
+ BTC_BT_2ND = 0x1,
+ BTC_BT_EXT = 0x2,
+ BTC_ALL_BT = 0x2,
+ BTC_ALL_BT_EZL = 0x3 /* BT0+BT1+Ext-ZB(or Thread, or LTE) */
+};
+
#define __RTW89_MLD_MAX_LINK_NUM 2
#define RTW89_MLD_NON_STA_LINK_NUM 1
@@ -1126,6 +1134,7 @@ struct rtw89_rx_desc_info {
bool addr_cam_valid;
u8 addr_cam_id;
u8 sec_cam_id;
+ u8 sec_type;
u8 mac_id;
u16 offset;
u16 rxd_len;
@@ -2196,6 +2205,15 @@ struct rtw89_btc_bt_info {
u32 rsvd: 17;
};
+struct rtw89_btc_rf_trx_para_v9 {
+ u32 wl_tx_power[RTW89_PHY_NUM]; /* absolute Tx power (dBm), 1's complement -5->0x85 */
+ u32 wl_rx_gain[RTW89_PHY_NUM]; /* rx gain table index (TBD.) */
+ u32 bt_tx_power[BTC_ALL_BT]; /* decrease Tx power (dB) */
+ u32 bt_rx_gain[BTC_ALL_BT]; /* LNA constrain level */
+ u32 zb_tx_power[BTC_ALL_BT]; /* 15.4 devrease Tx power (dB) */
+ u32 zb_rx_gain[BTC_ALL_BT]; /* 15.4 constrain level */
+};
+
struct rtw89_btc_cx {
struct rtw89_btc_wl_info wl;
struct rtw89_btc_bt_info bt;
@@ -3561,6 +3579,8 @@ struct rtw89_efuse {
u8 rfe_type;
char country_code[2];
u8 adc_td;
+ u8 bt_setting_2;
+ u8 bt_setting_3;
};
struct rtw89_phy_rate_pattern {
@@ -4152,6 +4172,21 @@ struct rtw89_reg_imr {
u32 set;
};
+#define RTW89_MODULE_FWNAME_PLACEHOLDER_0 0,
+#define __RTW89_GEN_MODULE_FWNAME_FMT(placeholder_or_ignored, strfmt) \
+ __take_second_arg(placeholder_or_ignored, strfmt)
+#define RTW89_GEN_MODULE_FWNAME_FMT(maxfmt) \
+ __RTW89_GEN_MODULE_FWNAME_FMT(RTW89_MODULE_FWNAME_PLACEHOLDER_ ## maxfmt, \
+ "-" __stringify(maxfmt))
+#define RTW89_GEN_MODULE_FWNAME(basename, maxformat) \
+ basename RTW89_GEN_MODULE_FWNAME_FMT(maxformat) ".bin"
+
+struct rtw89_fw_def {
+ const char *fw_basename;
+ u8 fw_format_max;
+ u16 fw_b_aid;
+};
+
struct rtw89_phy_table {
const struct rtw89_reg2_def *regs;
u32 n_regs;
@@ -4494,8 +4529,7 @@ struct rtw89_chip_info {
const struct rtw89_chip_ops *ops;
const struct rtw89_mac_gen_def *mac_def;
const struct rtw89_phy_gen_def *phy_def;
- const char *fw_basename;
- u8 fw_format_max;
+ struct rtw89_fw_def fw_def;
bool try_ce_fw;
u8 bbmcu_nr;
u32 needed_fw_elms;
@@ -4529,7 +4563,7 @@ struct rtw89_chip_info {
bool support_noise;
bool ul_tb_waveform_ctrl;
bool ul_tb_pwr_diff;
- bool rx_freq_frome_ie;
+ bool rx_freq_from_ie;
bool hw_sec_hdr;
bool hw_mgmt_tx_encrypt;
bool hw_tkip_crypto;
@@ -4592,6 +4626,10 @@ struct rtw89_chip_info {
const struct rtw89_btc_rf_trx_para *rf_para_ulink;
u8 rf_para_dlink_num;
const struct rtw89_btc_rf_trx_para *rf_para_dlink;
+ const struct rtw89_btc_rf_trx_para_v9 *rf_para_ulink_v9;
+ const struct rtw89_btc_rf_trx_para_v9 *rf_para_dlink_v9;
+ u8 rf_para_ulink_num_v9;
+ u8 rf_para_dlink_num_v9;
u8 ps_mode_supported;
u8 low_power_hci_modes;
@@ -4633,6 +4671,7 @@ struct rtw89_chip_info {
struct rtw89_chip_variant {
bool no_mcs_12_13: 1;
u32 fw_min_ver_code;
+ const struct rtw89_fw_def *fw_def_override;
};
union rtw89_bus_info {
@@ -4724,6 +4763,8 @@ enum rtw89_fw_type {
RTW89_FW_NORMAL = 1,
RTW89_FW_WOWLAN = 3,
RTW89_FW_NORMAL_CE = 5,
+ RTW89_FW_NORMAL_B = 14,
+ RTW89_FW_WOWLAN_B = 15,
RTW89_FW_BBMCU0 = 64,
RTW89_FW_BBMCU1 = 65,
RTW89_FW_LOGFMT = 255,
@@ -4779,6 +4820,7 @@ enum rtw89_fw_feature {
RTW89_FW_FEATURE_SER_L1_BY_EVENT,
RTW89_FW_FEATURE_SIM_SER_L0L1_BY_HALT_H2C,
RTW89_FW_FEATURE_LPS_ML_INFO_V1,
+ RTW89_FW_FEATURE_SER_POST_RECOVER_DMAC,
NUM_OF_RTW89_FW_FEATURES,
};
@@ -5152,7 +5194,6 @@ struct rtw89_hal {
bool no_eht;
atomic_t roc_chanctx_idx;
- u8 roc_link_index;
DECLARE_BITMAP(changes, NUM_OF_RTW89_CHANCTX_CHANGES);
DECLARE_BITMAP(entity_map, NUM_OF_RTW89_CHANCTX);
@@ -5575,9 +5616,11 @@ struct rtw89_tssi_info {
struct rtw89_power_trim_info {
bool pg_thermal_trim;
bool pg_pa_bias_trim;
+ bool pg_vco_trim;
u8 thermal_trim[RF_PATH_MAX];
u8 pa_bias_trim[RF_PATH_MAX];
u8 pad_bias_trim[RF_PATH_MAX];
+ u8 vco_trim[RF_PATH_MAX];
};
enum rtw89_regd_func {
@@ -5736,11 +5779,18 @@ enum rtw89_ser_rcvy_step {
RTW89_NUM_OF_SER_FLAGS
};
+struct rtw89_ser_count {
+ unsigned int l1;
+ unsigned int l2;
+};
+
struct rtw89_ser {
u8 state;
u8 alarm_event;
bool prehandle_l1;
+ struct rtw89_ser_count sw_cnt;
+
struct work_struct ser_hdl_work;
struct delayed_work ser_alarm_work;
const struct state_ent *st_tbl;
@@ -5901,8 +5951,11 @@ struct rtw89_phy_efuse_gain {
bool offset_valid;
bool comp_valid;
s8 offset[RF_PATH_MAX][RTW89_GAIN_OFFSET_NR]; /* S(8, 0) */
+ s8 offset2[RF_PATH_MAX][RTW89_GAIN_OFFSET_NR]; /* S(8, 0) */
s8 offset_base[RTW89_PHY_NUM]; /* S(8, 4) */
s8 rssi_base[RTW89_PHY_NUM]; /* S(8, 4) */
+ s8 ref_gain_base[RTW89_PHY_NUM]; /* S(8, 2) */
+ s8 cck_rpl_base[RTW89_PHY_NUM]; /* S(8, 0) */
s8 comp[RF_PATH_MAX][RTW89_SUBBAND_NR]; /* S(8, 0) */
};
@@ -6129,6 +6182,12 @@ struct rtw89_beacon_track_info {
u32 tbtt_diff_th;
};
+struct rtw89_tid_stats {
+ s64 last_pn;
+ u16 last_sn;
+ bool started;
+};
+
struct rtw89_dev {
struct ieee80211_hw *hw;
struct device *dev;
@@ -6158,8 +6217,6 @@ struct rtw89_dev {
refcount_t refcount_ap_info;
struct list_head rtwvifs_list;
- /* used to protect rf read write */
- struct mutex rf_mutex;
struct workqueue_struct *txq_wq;
struct work_struct txq_work;
struct delayed_work txq_reinvoke_work;
@@ -6337,6 +6394,7 @@ struct rtw89_sta {
struct sk_buff_head roc_queue;
struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS];
+ struct rtw89_tid_stats tid_rx_stats[IEEE80211_NUM_TIDS];
DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS);
DECLARE_BITMAP(pairwise_sec_cam_map, RTW89_MAX_SEC_CAM_NUM);
@@ -6784,22 +6842,18 @@ static inline u32
rtw89_read_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
u32 addr, u32 mask)
{
- u32 val;
-
- mutex_lock(&rtwdev->rf_mutex);
- val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
- mutex_unlock(&rtwdev->rf_mutex);
+ lockdep_assert_wiphy(rtwdev->hw->wiphy);
- return val;
+ return rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
}
static inline void
rtw89_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
u32 addr, u32 mask, u32 data)
{
- mutex_lock(&rtwdev->rf_mutex);
+ lockdep_assert_wiphy(rtwdev->hw->wiphy);
+
rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data);
- mutex_unlock(&rtwdev->rf_mutex);
}
static inline u32 rtw89_read32_pci_cfg(struct rtw89_dev *rtwdev, u32 addr)
@@ -7379,6 +7433,22 @@ void rtw89_chip_calc_rx_gain_normal(struct rtw89_dev *rtwdev,
chip->ops->calc_rx_gain_normal(rtwdev, chan, path, phy_idx, calc);
}
+static inline const struct rtw89_fw_def *
+__rtw89_chip_get_fw_def(const struct rtw89_chip_info *chip,
+ const struct rtw89_chip_variant *variant)
+{
+ if (variant && variant->fw_def_override)
+ return variant->fw_def_override;
+
+ return &chip->fw_def;
+}
+
+static inline
+const struct rtw89_fw_def *rtw89_chip_get_fw_def(struct rtw89_dev *rtwdev)
+{
+ return __rtw89_chip_get_fw_def(rtwdev->chip, rtwdev->variant);
+}
+
static inline void rtw89_load_txpwr_table(struct rtw89_dev *rtwdev,
const struct rtw89_txpwr_table *tbl)
{
@@ -7541,6 +7611,7 @@ static inline struct rtw89_fw_suit *rtw89_fw_suit_get(struct rtw89_dev *rtwdev,
switch (type) {
case RTW89_FW_WOWLAN:
+ case RTW89_FW_WOWLAN_B:
return &fw_info->wowlan;
case RTW89_FW_LOGFMT:
return &fw_info->log.suit;
@@ -7734,6 +7805,9 @@ int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev,
void rtw89_core_set_tid_config(struct rtw89_dev *rtwdev,
struct ieee80211_sta *sta,
struct cfg80211_tid_config *tid_config);
+void rtw89_core_tid_rx_stats_ctrl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+ struct ieee80211_ampdu_params *params, bool enable);
+void rtw89_core_tid_rx_stats_reset(struct rtw89_dev *rtwdev);
void rtw89_core_rfkill_poll(struct rtw89_dev *rtwdev, bool force);
void rtw89_check_quirks(struct rtw89_dev *rtwdev, const struct dmi_system_id *quirks);
int rtw89_core_init(struct rtw89_dev *rtwdev);
@@ -7820,5 +7894,8 @@ void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev,
void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event);
int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
unsigned int link_id);
+void rtw89_core_dm_disable_cfg(struct rtw89_dev *rtwdev, u32 new);
+void rtw89_core_dm_disable_set(struct rtw89_dev *rtwdev, enum rtw89_dm_type type);
+void rtw89_core_dm_disable_clr(struct rtw89_dev *rtwdev, enum rtw89_dm_type type);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index 012ead92f5f2..7d8d22311018 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -1129,7 +1129,7 @@ static int rtw89_debug_dump_mac_mem(struct rtw89_dev *rtwdev,
pages = len / mem_page_size + 1;
start_page = start_addr / mem_page_size;
residue = start_addr % mem_page_size;
- base_addr = mac->mem_base_addrs[sel];
+ base_addr = rtw89_mac_mem_base_addrs(rtwdev, sel);
base_addr += start_page * mem_page_size;
for (pp = 0; pp < pages; pp++) {
@@ -3552,6 +3552,8 @@ static int rtw89_dbg_trigger_l1_error_by_halt_h2c_be(struct rtw89_dev *rtwdev)
if (!test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags))
return -EBUSY;
+ rtw89_leave_ps_mode(rtwdev);
+
rtw89_write32_set(rtwdev, R_BE_FW_TRIGGER_IDCT_ISR,
B_BE_DMAC_FW_TRIG_IDCT | B_BE_DMAC_FW_ERR_IDCT_IMR);
@@ -3654,6 +3656,8 @@ static int rtw89_dbg_trigger_l0_error_by_halt_h2c_be(struct rtw89_dev *rtwdev)
if (!test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags))
return -EBUSY;
+ rtw89_leave_ps_mode(rtwdev);
+
rtw89_write32_set(rtwdev, R_BE_CMAC_FW_TRIGGER_IDCT_ISR,
B_BE_CMAC_FW_TRIG_IDCT | B_BE_CMAC_FW_ERR_IDCT_IMR);
@@ -3781,6 +3785,7 @@ 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_ser_count *sw_cnt = &rtwdev->ser.sw_cnt;
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_dbg_ser_counters cnt = {};
char *p = buf, *end = buf + bufsz;
@@ -3798,6 +3803,11 @@ static ssize_t rtw89_debug_priv_ser_counters_get(struct rtw89_dev *rtwdev,
return -EOPNOTSUPP;
}
+ p += scnprintf(p, end - p, "SER L1 SW Count: %u\n", sw_cnt->l1);
+ p += scnprintf(p, end - p, "SER L2 SW Count: %u\n", sw_cnt->l2);
+
+ /* Some chipsets won't record SER simulation in HW cnt. */
+ p += scnprintf(p, end - p, "---\n");
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);
@@ -4327,35 +4337,6 @@ static ssize_t rtw89_debug_priv_stations_get(struct rtw89_dev *rtwdev,
return p - buf;
}
-static void rtw89_debug_disable_dm_cfg_bmap(struct rtw89_dev *rtwdev, u32 new)
-{
- struct rtw89_hal *hal = &rtwdev->hal;
- u32 old = hal->disabled_dm_bitmap;
-
- if (new == old)
- return;
-
- hal->disabled_dm_bitmap = new;
-
- rtw89_debug(rtwdev, RTW89_DBG_STATE, "Disable DM: 0x%x -> 0x%x\n", old, new);
-}
-
-static void rtw89_debug_disable_dm_set_flag(struct rtw89_dev *rtwdev, u8 flag)
-{
- struct rtw89_hal *hal = &rtwdev->hal;
- u32 cur = hal->disabled_dm_bitmap;
-
- rtw89_debug_disable_dm_cfg_bmap(rtwdev, cur | BIT(flag));
-}
-
-static void rtw89_debug_disable_dm_clr_flag(struct rtw89_dev *rtwdev, u8 flag)
-{
- struct rtw89_hal *hal = &rtwdev->hal;
- u32 cur = hal->disabled_dm_bitmap;
-
- rtw89_debug_disable_dm_cfg_bmap(rtwdev, cur & ~BIT(flag));
-}
-
#define DM_INFO(type) {RTW89_DM_ ## type, #type}
static const struct rtw89_disabled_dm_info {
@@ -4406,7 +4387,7 @@ rtw89_debug_priv_disable_dm_set(struct rtw89_dev *rtwdev,
if (ret)
return -EINVAL;
- rtw89_debug_disable_dm_cfg_bmap(rtwdev, conf);
+ rtw89_core_dm_disable_cfg(rtwdev, conf);
return count;
}
@@ -4469,7 +4450,7 @@ rtw89_debug_priv_mlo_mode_set(struct rtw89_dev *rtwdev,
if (num != 2)
return -EINVAL;
- rtw89_debug_disable_dm_set_flag(rtwdev, RTW89_DM_MLO);
+ rtw89_core_dm_disable_set(rtwdev, RTW89_DM_MLO);
rtw89_debug(rtwdev, RTW89_DBG_STATE, "Set MLO mode to %x\n", mlo_mode);
@@ -4479,7 +4460,7 @@ rtw89_debug_priv_mlo_mode_set(struct rtw89_dev *rtwdev,
break;
default:
rtw89_debug(rtwdev, RTW89_DBG_STATE, "Unsupported MLO mode\n");
- rtw89_debug_disable_dm_clr_flag(rtwdev, RTW89_DM_MLO);
+ rtw89_core_dm_disable_clr(rtwdev, RTW89_DM_MLO);
return -EOPNOTSUPP;
}
@@ -4882,9 +4863,9 @@ rtw89_debug_priv_beacon_info_get(struct rtw89_dev *rtwdev,
static const struct rtw89_debugfs rtw89_debugfs_templ = {
.read_reg = rtw89_debug_priv_select_and_get(read_reg),
.write_reg = rtw89_debug_priv_set(write_reg),
- .read_rf = rtw89_debug_priv_select_and_get(read_rf),
- .write_rf = rtw89_debug_priv_set(write_rf),
- .rf_reg_dump = rtw89_debug_priv_get(rf_reg_dump, RSIZE_8K),
+ .read_rf = rtw89_debug_priv_select_and_get(read_rf, RLOCK),
+ .write_rf = rtw89_debug_priv_set(write_rf, WLOCK),
+ .rf_reg_dump = rtw89_debug_priv_get(rf_reg_dump, RSIZE_8K, RLOCK),
.txpwr_table = rtw89_debug_priv_get(txpwr_table, RSIZE_20K, RLOCK),
.mac_reg_dump = rtw89_debug_priv_select_and_get(mac_reg_dump, RSIZE_128K),
.mac_mem_dump = rtw89_debug_priv_select_and_get(mac_mem_dump, RSIZE_16K, RLOCK),
diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c
index a2757a88d55d..89d4b1b865f8 100644
--- a/drivers/net/wireless/realtek/rtw89/efuse.c
+++ b/drivers/net/wireless/realtek/rtw89/efuse.c
@@ -185,8 +185,8 @@ static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
return 0;
}
-static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
- u32 dump_addr, u32 dump_size, bool dav)
+static int __rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
+ u32 dump_addr, u32 dump_size, bool dav)
{
int ret;
@@ -208,6 +208,25 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
return 0;
}
+static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
+ u32 dump_addr, u32 dump_size, bool dav)
+{
+ int retry;
+ int ret;
+
+ for (retry = 0; retry < 5; retry++) {
+ ret = __rtw89_dump_physical_efuse_map(rtwdev, map, dump_addr,
+ dump_size, dav);
+ if (!ret)
+ return 0;
+
+ rtw89_warn(rtwdev, "efuse dump (dav=%d) failed, retrying (%d)\n",
+ dav, retry);
+ }
+
+ return ret;
+}
+
#define invalid_efuse_header(hdr1, hdr2) \
((hdr1) == 0xff || (hdr2) == 0xff)
#define invalid_efuse_content(word_en, i) \
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index c52f9e11a8b2..17704f054727 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -730,6 +730,7 @@ static int rtw89_fw_update_ver(struct rtw89_dev *rtwdev,
{
const struct rtw89_fw_hdr *v0 = (const struct rtw89_fw_hdr *)fw_suit->data;
const struct rtw89_fw_hdr_v1 *v1 = (const struct rtw89_fw_hdr_v1 *)fw_suit->data;
+ struct wiphy *wiphy = rtwdev->hw->wiphy;
if (type == RTW89_FW_LOGFMT)
return 0;
@@ -755,6 +756,13 @@ static int rtw89_fw_update_ver(struct rtw89_dev *rtwdev,
fw_suit->major_ver, fw_suit->minor_ver, fw_suit->sub_ver,
fw_suit->sub_idex, fw_suit->commitid, fw_suit->cmd_ver, type);
+ if (type == RTW89_FW_NORMAL || type == RTW89_FW_NORMAL_CE ||
+ type == RTW89_FW_NORMAL_B)
+ snprintf(wiphy->fw_version, sizeof(wiphy->fw_version),
+ "%u.%u.%u.%u",
+ fw_suit->major_ver, fw_suit->minor_ver,
+ fw_suit->sub_ver, fw_suit->sub_idex);
+
return 0;
}
@@ -923,6 +931,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__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),
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 97, 0, SIM_SER_L0L1_BY_HALT_H2C),
+ __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 100, 0, SER_POST_RECOVER_DMAC),
};
static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
@@ -965,18 +974,20 @@ static void rtw89_fw_recognize_features(struct rtw89_dev *rtwdev)
const struct firmware *
rtw89_early_fw_feature_recognize(struct device *device,
const struct rtw89_chip_info *chip,
+ const struct rtw89_chip_variant *variant,
struct rtw89_fw_info *early_fw,
int *used_fw_format)
{
+ const struct rtw89_fw_def *fw_def = __rtw89_chip_get_fw_def(chip, variant);
const struct firmware *firmware;
char fw_name[64];
int fw_format;
u32 ver_code;
int ret;
- for (fw_format = chip->fw_format_max; fw_format >= 0; fw_format--) {
+ for (fw_format = fw_def->fw_format_max; fw_format >= 0; fw_format--) {
rtw89_fw_get_filename(fw_name, sizeof(fw_name),
- chip->fw_basename, fw_format);
+ fw_def->fw_basename, fw_format);
ret = request_firmware(&firmware, fw_name, device);
if (!ret) {
@@ -1025,16 +1036,25 @@ static int rtw89_fw_validate_ver_required(struct rtw89_dev *rtwdev)
int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_fw_def *fw_def = rtw89_chip_get_fw_def(rtwdev);
const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_hal *hal = &rtwdev->hal;
+ enum rtw89_fw_type normal_fw_type = RTW89_FW_NORMAL;
+ enum rtw89_fw_type wowlan_fw_type = RTW89_FW_WOWLAN;
int ret;
+ if (fw_def->fw_b_aid && fw_def->fw_b_aid == hal->aid) {
+ normal_fw_type = RTW89_FW_NORMAL_B;
+ wowlan_fw_type = RTW89_FW_WOWLAN_B;
+ }
+
if (chip->try_ce_fw) {
ret = __rtw89_fw_recognize(rtwdev, RTW89_FW_NORMAL_CE, true);
if (!ret)
goto normal_done;
}
- ret = __rtw89_fw_recognize(rtwdev, RTW89_FW_NORMAL, false);
+ ret = __rtw89_fw_recognize(rtwdev, normal_fw_type, false);
if (ret)
return ret;
@@ -1044,7 +1064,7 @@ normal_done:
return ret;
/* It still works if wowlan firmware isn't existing. */
- __rtw89_fw_recognize(rtwdev, RTW89_FW_WOWLAN, false);
+ __rtw89_fw_recognize(rtwdev, wowlan_fw_type, false);
/* It still works if log format file isn't existing. */
__rtw89_fw_recognize(rtwdev, RTW89_FW_LOGFMT, true);
@@ -1062,6 +1082,7 @@ 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;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_phy_table *tbl, **pp;
struct rtw89_reg2_def *regs;
@@ -1118,7 +1139,9 @@ int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev,
if (radio) {
tbl->rf_path = arg.rf_path;
- tbl->config = rtw89_phy_config_rf_reg_v1;
+ tbl->config = chip->chip_id == RTL8852A ?
+ rtw89_phy_config_rf_reg :
+ rtw89_phy_config_rf_reg_v1;
}
*pp = tbl;
@@ -1138,8 +1161,13 @@ int rtw89_fw_recognize_txpwr_from_elm(struct rtw89_dev *rtwdev,
const struct __rtw89_fw_txpwr_element *txpwr_elm = &elm->u.txpwr;
const unsigned long offset = arg.offset;
struct rtw89_efuse *efuse = &rtwdev->efuse;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u16 aid = le16_to_cpu(elm->aid);
struct rtw89_txpwr_conf *conf;
+ if (aid && aid != hal->aid)
+ return 1;
+
if (!rtwdev->rfe_data) {
rtwdev->rfe_data = kzalloc_obj(*rtwdev->rfe_data);
if (!rtwdev->rfe_data)
@@ -2024,11 +2052,11 @@ void rtw89_load_firmware_work(struct work_struct *work)
{
struct rtw89_dev *rtwdev =
container_of(work, struct rtw89_dev, load_firmware_work);
- const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_fw_def *fw_def = rtw89_chip_get_fw_def(rtwdev);
char fw_name[64];
rtw89_fw_get_filename(fw_name, sizeof(fw_name),
- chip->fw_basename, rtwdev->fw.fw_format);
+ fw_def->fw_basename, rtwdev->fw.fw_format);
rtw89_load_firmware_req(rtwdev, &rtwdev->fw.req, fw_name, false);
}
@@ -6857,6 +6885,93 @@ flex_member:
return 0;
}
+int rtw89_fw_h2c_trx_protect(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx, bool enable)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_h2c_trx_protect *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ if (chip->chip_gen != RTW89_CHIP_BE)
+ return 0;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c trx protect\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_trx_protect *)skb->data;
+
+ h2c->c0 = le32_encode_bits(BIT(phy_idx), RTW89_H2C_TRX_PROTECT_C0_BAND_BITMAP) |
+ le32_encode_bits(0, RTW89_H2C_TRX_PROTECT_C0_OP_MODE);
+ h2c->c1 = le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_C1_RX_IN) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_C1_PPDU_STS) |
+ le32_encode_bits(1, RTW89_H2C_TRX_PROTECT_C1_MSK_RX_IN) |
+ le32_encode_bits(1, RTW89_H2C_TRX_PROTECT_C1_MSK_PPDU_STS);
+ h2c->w0 = le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_BE0) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_BK0) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_VI0) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_VO0) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_BE1) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_BK1) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_VI1) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_VO1) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_MG0) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_MG1) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_MG2) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_HI) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_BCN) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_UL) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT0) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT1) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT2) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT3) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_SPEQ0) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W0_TXEN_SPEQ1);
+ h2c->m0 = cpu_to_le32(RTW89_H2C_TRX_PROTECT_W0_TXEN_BE0 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_BK0 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_VI0 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_VO0 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_BE1 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_BK1 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_VI1 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_VO1 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_MG0 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_MG1 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_MG2 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_HI |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_BCN |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_UL |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT0 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT1 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT2 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT3 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_SPEQ0 |
+ RTW89_H2C_TRX_PROTECT_W0_TXEN_SPEQ1);
+ h2c->w1 = le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W1_CHINFO_EN) |
+ le32_encode_bits(enable, RTW89_H2C_TRX_PROTECT_W1_DFS_EN);
+ h2c->m1 = cpu_to_le32(RTW89_H2C_TRX_PROTECT_W1_CHINFO_EN |
+ RTW89_H2C_TRX_PROTECT_W1_DFS_EN);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
+ H2C_FUNC_TRX_PROTECT, 0, 1, len);
+
+ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait,
+ RTW89_FW_OFLD_WAIT_COND_TRX_PROTECT);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to trx protect\n");
+ return ret;
+ }
+
+ return 0;
+}
+
int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
struct rtw89_fw_h2c_rf_reg_info *info,
u16 len, u8 page)
@@ -7270,6 +7385,7 @@ v1:
h2c = (struct rtw89_fw_h2c_rfk_pre_info_mcc *)skb->data;
h2c->aid = cpu_to_le32(hal->aid);
+ h2c->acv = hal->acv;
done:
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
@@ -9602,38 +9718,49 @@ fail:
return ret;
}
-#define H2C_WAKEUP_CTRL_LEN 4
int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
bool enable)
{
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
+ struct rtw89_h2c_wow_wakeup_ctrl *h2c;
struct sk_buff *skb;
+ u32 len = sizeof(*h2c);
u8 macid = rtwvif_link->mac_id;
int ret;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WAKEUP_CTRL_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for wakeup ctrl\n");
return -ENOMEM;
}
- skb_put(skb, H2C_WAKEUP_CTRL_LEN);
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_wow_wakeup_ctrl *)skb->data;
if (rtw_wow->pattern_cnt)
- RTW89_SET_WOW_WAKEUP_CTRL_PATTERN_MATCH_ENABLE(skb->data, enable);
- if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags))
- RTW89_SET_WOW_WAKEUP_CTRL_MAGIC_ENABLE(skb->data, enable);
+ h2c->w0 |= le32_encode_bits(enable,
+ RTW89_H2C_WOW_WAKEUP_CTRL_W0_PATTERN_MATCH_ENABLE);
+ if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) {
+ h2c->w0 |= le32_encode_bits(enable,
+ RTW89_H2C_WOW_WAKEUP_CTRL_W0_MAGIC_ENABLE);
+ if (ieee80211_vif_is_mld(vif))
+ h2c->w0 |= le32_encode_bits(enable,
+ RTW89_H2C_WOW_WAKEUP_CTRL_W0_MAGIC_MLD_ENABLE);
+ }
+
if (test_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags))
- RTW89_SET_WOW_WAKEUP_CTRL_DEAUTH_ENABLE(skb->data, enable);
+ h2c->w0 |= le32_encode_bits(enable,
+ RTW89_H2C_WOW_WAKEUP_CTRL_W0_DEAUTH_ENABLE);
- RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(skb->data, macid);
+ h2c->w0 |= le32_encode_bits(macid, RTW89_H2C_WOW_WAKEUP_CTRL_W0_MAC_ID);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
H2C_CL_MAC_WOW,
H2C_FUNC_WAKEUP_CTRL, 0, 1,
- H2C_WAKEUP_CTRL_LEN);
+ len);
ret = rtw89_h2c_tx(rtwdev, skb, false);
if (ret) {
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index d45b6ea6ea1b..db252d45e498 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2219,50 +2219,21 @@ struct rtw89_h2c_cfg_nlo {
#define RTW89_H2C_NLO_W0_IGNORE_CIPHER BIT(2)
#define RTW89_H2C_NLO_W0_MACID GENMASK(31, 24)
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_PATTERN_MATCH_ENABLE(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, BIT(0));
-}
-
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAGIC_ENABLE(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, BIT(1));
-}
-
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_HW_UNICAST_ENABLE(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, BIT(2));
-}
-
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_FW_UNICAST_ENABLE(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, BIT(3));
-}
-
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_DEAUTH_ENABLE(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, BIT(4));
-}
-
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_REKEYP_ENABLE(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, BIT(5));
-}
-
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_EAP_ENABLE(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, BIT(6));
-}
-
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_ALL_DATA_ENABLE(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, BIT(7));
-}
+struct rtw89_h2c_wow_wakeup_ctrl {
+ __le32 w0;
+} __packed;
-static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(void *h2c, u32 val)
-{
- le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24));
-}
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_PATTERN_MATCH_ENABLE BIT(0)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_MAGIC_ENABLE BIT(1)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_HW_UNICAST_ENABLE BIT(2)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_FW_UNICAST_ENABLE BIT(3)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_DEAUTH_ENABLE BIT(4)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_REKEYP_ENABLE BIT(5)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_EAP_ENABLE BIT(6)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_ALL_DATA_ENABLE BIT(7)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_MAGIC_MLD_ENABLE BIT(8)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_MAC_ID_EXT GENMASK(23, 16)
+#define RTW89_H2C_WOW_WAKEUP_CTRL_W0_MAC_ID GENMASK(31, 24)
struct rtw89_h2c_wow_cam_update {
__le32 w0;
@@ -3106,6 +3077,44 @@ struct rtw89_h2c_scanofld_be {
#define RTW89_H2C_SCANOFLD_BE_W9_SIZE_MACC GENMASK(15, 8)
#define RTW89_H2C_SCANOFLD_BE_W9_SIZE_OP GENMASK(23, 16)
+struct rtw89_h2c_trx_protect {
+ __le32 c0;
+ __le32 c1;
+ __le32 w0;
+ __le32 m0;
+ __le32 w1;
+ __le32 m1;
+} __packed;
+
+#define RTW89_H2C_TRX_PROTECT_C0_BAND_BITMAP GENMASK(2, 0)
+#define RTW89_H2C_TRX_PROTECT_C0_OP_MODE GENMASK(4, 3)
+#define RTW89_H2C_TRX_PROTECT_C1_RX_IN BIT(0)
+#define RTW89_H2C_TRX_PROTECT_C1_PPDU_STS BIT(4)
+#define RTW89_H2C_TRX_PROTECT_C1_MSK_RX_IN BIT(16)
+#define RTW89_H2C_TRX_PROTECT_C1_MSK_PPDU_STS BIT(20)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_BE0 BIT(0)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_BK0 BIT(1)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_VI0 BIT(2)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_VO0 BIT(3)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_BE1 BIT(4)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_BK1 BIT(5)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_VI1 BIT(6)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_VO1 BIT(7)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_MG0 BIT(8)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_MG1 BIT(9)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_MG2 BIT(10)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_HI BIT(11)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_BCN BIT(12)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_UL BIT(13)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT0 BIT(14)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT1 BIT(15)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT2 BIT(16)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_TWT3 BIT(17)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_SPEQ0 BIT(18)
+#define RTW89_H2C_TRX_PROTECT_W0_TXEN_SPEQ1 BIT(19)
+#define RTW89_H2C_TRX_PROTECT_W1_CHINFO_EN BIT(0)
+#define RTW89_H2C_TRX_PROTECT_W1_DFS_EN BIT(1)
+
struct rtw89_h2c_fwips {
__le32 w0;
} __packed;
@@ -4289,13 +4298,22 @@ enum rtw89_fw_element_id {
BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
BITS_OF_RTW89_TXPWR_FW_ELEMENTS_NO_6GHZ)
-#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS (BIT(RTW89_FW_ELEMENT_ID_BBMCU0) | \
- BIT(RTW89_FW_ELEMENT_ID_BB_REG) | \
- BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
- BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \
- BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \
- BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
- BITS_OF_RTW89_TXPWR_FW_ELEMENTS)
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE \
+ (BIT(RTW89_FW_ELEMENT_ID_BB_REG) | \
+ BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
+ BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \
+ BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \
+ BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
+ BITS_OF_RTW89_TXPWR_FW_ELEMENTS)
+
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS \
+ (RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE | \
+ BIT(RTW89_FW_ELEMENT_ID_BBMCU0))
+
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_V1 \
+ (RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE | \
+ BIT(RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ) | \
+ BIT(RTW89_FW_ELEMENT_ID_TX_COMP))
struct __rtw89_fw_txpwr_element {
u8 rsvd0;
@@ -4598,6 +4616,7 @@ enum rtw89_fw_ofld_h2c_func {
H2C_FUNC_OFLD_TP = 0x20,
H2C_FUNC_MAC_MACID_PAUSE_SLEEP = 0x28,
H2C_FUNC_SCANOFLD_BE = 0x2c,
+ H2C_FUNC_TRX_PROTECT = 0x34,
NUM_OF_RTW89_FW_OFLD_H2C_FUNC,
};
@@ -4608,6 +4627,7 @@ enum rtw89_fw_ofld_h2c_func {
#define RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(pkt_id, pkt_op) \
RTW89_FW_OFLD_WAIT_COND(RTW89_PKT_OFLD_WAIT_TAG(pkt_id, pkt_op), \
H2C_FUNC_PACKET_OFLD)
+#define RTW89_FW_OFLD_WAIT_COND_TRX_PROTECT RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_TRX_PROTECT)
#define RTW89_SCANOFLD_WAIT_COND_ADD_CH RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH)
@@ -4841,6 +4861,8 @@ struct rtw89_fw_h2c_rfk_pre_info_mcc {
struct rtw89_fw_h2c_rfk_pre_info_mcc_v1 base;
u8 rsvd[2];
__le32 aid;
+ u8 acv;
+ u8 rsvd2[3];
} __packed;
struct rtw89_h2c_rf_tssi {
@@ -5171,6 +5193,7 @@ int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev);
const struct firmware *
rtw89_early_fw_feature_recognize(struct device *device,
const struct rtw89_chip_info *chip,
+ const struct rtw89_chip_variant *variant,
struct rtw89_fw_info *early_fw,
int *used_fw_format);
int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
@@ -5293,6 +5316,8 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *opt,
struct rtw89_vif_link *vif,
bool wowlan);
+int rtw89_fw_h2c_trx_protect(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx, bool enable);
int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
struct rtw89_fw_h2c_rf_reg_info *info,
u16 len, u8 page);
@@ -5468,6 +5493,15 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev)
rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(rtwdev);
}
+static inline void rtw89_fw_h2c_init_trx_protect(struct rtw89_dev *rtwdev)
+{
+ u8 active_bands = rtw89_get_active_phy_bitmap(rtwdev);
+ int i;
+
+ for (i = 0; i < RTW89_PHY_NUM; i++)
+ rtw89_fw_h2c_trx_protect(rtwdev, i, active_bands & BIT(i));
+}
+
static inline int rtw89_chip_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct rtw89_sta_link *rtwsta_link)
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index 8472f1a63951..54aad37485d6 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -43,7 +43,7 @@ static void rtw89_mac_mem_write(struct rtw89_dev *rtwdev, u32 offset,
u32 val, enum rtw89_mac_mem_sel sel)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
- u32 addr = mac->mem_base_addrs[sel] + offset;
+ u32 addr = rtw89_mac_mem_base_addrs(rtwdev, sel) + offset;
rtw89_write32(rtwdev, mac->filter_model_addr, addr);
rtw89_write32(rtwdev, mac->indir_access_addr, val);
@@ -53,7 +53,7 @@ static u32 rtw89_mac_mem_read(struct rtw89_dev *rtwdev, u32 offset,
enum rtw89_mac_mem_sel sel)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
- u32 addr = mac->mem_base_addrs[sel] + offset;
+ u32 addr = rtw89_mac_mem_base_addrs(rtwdev, sel) + offset;
rtw89_write32(rtwdev, mac->filter_model_addr, addr);
return rtw89_read32(rtwdev, mac->indir_access_addr);
@@ -814,6 +814,7 @@ static bool rtw89_mac_suppress_log(struct rtw89_dev *rtwdev, u32 err)
u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
u32 err, err_scnr;
int ret;
@@ -825,7 +826,9 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev)
}
err = rtw89_read32(rtwdev, R_AX_HALT_C2H);
- rtw89_write32(rtwdev, R_AX_HALT_C2H_CTRL, 0);
+
+ if (!RTW89_CHK_FW_FEATURE(SER_POST_RECOVER_DMAC, &rtwdev->fw))
+ rtw89_write32(rtwdev, R_AX_HALT_C2H_CTRL, 0);
err_scnr = RTW89_ERROR_SCENARIO(err);
if (err_scnr == RTW89_WCPU_CPU_EXCEPTION)
@@ -836,11 +839,18 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev)
err = MAC_AX_ERR_RXI300;
if (rtw89_mac_suppress_log(rtwdev, err))
- return err;
+ goto bottom;
rtw89_fw_st_dbg_dump(rtwdev);
mac->dump_err_status(rtwdev, err);
+bottom:
+ if (chip->chip_gen != RTW89_CHIP_AX)
+ rtw89_write32(rtwdev, R_AX_HALT_C2H, 0);
+
+ if (RTW89_CHK_FW_FEATURE(SER_POST_RECOVER_DMAC, &rtwdev->fw))
+ rtw89_write32(rtwdev, R_AX_HALT_C2H_CTRL, 0);
+
return err;
}
EXPORT_SYMBOL(rtw89_mac_get_err_status);
@@ -1729,8 +1739,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
/* 8852C PCIE SCC */
.wde_size19 = {RTW89_WDE_PG_64, 3328, 0,},
.wde_size23 = {RTW89_WDE_PG_64, 1022, 2,},
- /* 8852B USB2.0/USB3.0 SCC */
- .wde_size25 = {RTW89_WDE_PG_64, 162, 94,},
+ /* 8852B USB2.0/USB3.0 SCC turbo */
+ .wde_size30 = {RTW89_WDE_PG_64, 220, 36,},
/* 8852C USB2.0 */
.wde_size31 = {RTW89_WDE_PG_64, 384, 0,},
/* PCIE */
@@ -1754,10 +1764,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
.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 */
- .ple_size33 = {RTW89_PLE_PG_128, 632, 8,},
+ /* 8851B USB2.0 SCC turbo */
+ .ple_size27 = {RTW89_PLE_PG_128, 1396, 12,},
+ /* 8852B USB3.0 SCC turbo */
+ .ple_size31 = {RTW89_PLE_PG_128, 1392, 16,},
/* 8852C USB2.0 */
.ple_size34 = {RTW89_PLE_PG_128, 3374, 18,},
/* PCIE 64 */
@@ -1780,8 +1790,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
.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,},
+ /* 8852B USB2.0/USB3.0 SCC turbo */
+ .wde_qt30 = {210, 2, 0, 8,},
/* 8852C USB2.0 */
.wde_qt31 = {338, 6, 0, 40,},
.ple_qt0 = {320, 320, 32, 16, 13, 13, 292, 292, 64, 18, 1, 4, 0,},
@@ -1799,6 +1809,9 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
/* 8852A USB SCC */
.ple_qt25 = {1536, 0, 16, 48, 13, 13, 360, 0, 32, 40, 8, 0,},
.ple_qt26 = {2654, 0, 1134, 48, 64, 13, 1478, 0, 64, 128, 120, 0,},
+ /* 8852B USB3.0 SCC turbo */
+ .ple_qt27 = {1040, 0, 16, 48, 13, 13, 178, 0, 32, 14, 8, 0,},
+ .ple_qt28 = {1040, 0, 32, 48, 43, 13, 208, 0, 62, 14, 24, 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,},
@@ -1817,13 +1830,9 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
/* PCIE 64 */
.ple_qt58 = {147, 0, 16, 20, 157, 13, 229, 0, 172, 14, 24, 0,},
.ple_qt59 = {147, 0, 32, 20, 1860, 13, 2025, 0, 1879, 14, 24, 0,},
- /* USB2.0 52B SCC */
- .ple_qt72 = {130, 0, 16, 48, 4, 13, 322, 0, 32, 14, 8, 0, 0,},
- /* USB2.0 52B 92K */
- .ple_qt73 = {130, 0, 32, 48, 37, 13, 355, 0, 65, 14, 24, 0, 0,},
- /* USB3.0 52B 92K */
- .ple_qt74 = {286, 0, 16, 48, 4, 13, 178, 0, 32, 14, 8, 0, 0,},
- .ple_qt75 = {286, 0, 32, 48, 37, 13, 211, 0, 65, 14, 24, 0, 0,},
+ /* 8851B USB2.0 SCC turbo */
+ .ple_qt61 = {858, 0, 16, 48, 4, 13, 370, 0, 32, 14, 8, 0, 0,},
+ .ple_qt62 = {858, 0, 32, 48, 37, 13, 403, 0, 65, 14, 24, 0, 0,},
/* USB2.0 52C */
.ple_qt78 = {1560, 0, 16, 48, 13, 13, 390, 0, 32, 38, 8, 16, 0,},
/* USB2.0 52C */
@@ -2004,7 +2013,7 @@ static u32 dle_expected_used_size(struct rtw89_dev *rtwdev,
{
u32 size = rtwdev->chip->fifo_size;
- if (mode == RTW89_QTA_SCC)
+ if (mode == RTW89_QTA_SCC && rtwdev->hci.type != RTW89_HCI_TYPE_USB)
size -= rtwdev->chip->dle_scc_rsvd_size;
return size;
@@ -5412,6 +5421,9 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le
cond = RTW89_SCANOFLD_BE_WAIT_COND_START;
h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN;
break;
+ case H2C_FUNC_TRX_PROTECT:
+ cond = RTW89_FW_OFLD_WAIT_COND_TRX_PROTECT;
+ break;
}
data.err = !!h2c_return;
@@ -7171,7 +7183,7 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
return ret;
}
-int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable)
+static int _rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable)
{
struct rtw89_mac_h2c_info h2c_info = {};
struct rtw89_mac_c2h_info c2h_info = {};
@@ -7194,6 +7206,19 @@ int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable)
return ret;
}
+int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable)
+{
+ int i, ret;
+
+ for (i = 0; i < CPU_IO_RX_RETRY_CNT; i++) {
+ ret = _rtw89_mac_cpu_io_rx(rtwdev, wow_enable);
+ if (!ret)
+ return 0;
+ }
+
+ return ret;
+}
+
static int rtw89_wow_config_mac_ax(struct rtw89_dev *rtwdev, bool enable_wow)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
@@ -7307,6 +7332,8 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
},
.wow_ctrl = {.addr = R_AX_WOW_CTRL, .mask = B_AX_WOW_WOWEN,},
.agg_limit = {.addr = R_AX_AMPDU_AGG_LIMIT, .mask = B_AX_AMPDU_MAX_TIME_MASK,},
+ .ra_agg_limit = {.addr = R_AX_AMPDU_AGG_LIMIT,
+ .mask = B_AX_RA_TRY_RATE_AGG_LMT_MASK,},
.txcnt_limit = {.addr = R_AX_TXCNT, .mask = B_AX_L_TXCNT_LMT_MASK,},
.check_mac_en = rtw89_mac_check_mac_en_ax,
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index e71a71648ab8..9db9ae219cd6 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -17,6 +17,7 @@
#define BSSID_CAM_ENT_SIZE 0x08
#define HFC_PAGE_UNIT 64
#define RPWM_TRY_CNT 3
+#define CPU_IO_RX_RETRY_CNT 3
enum rtw89_mac_hwmod_sel {
RTW89_DMAC_SEL = 0,
@@ -333,6 +334,7 @@ enum rtw89_mac_dbg_port_sel {
#define NAT25_CAM_BASE_ADDR_BE 0x18820000
#define RXPLD_FLTR_CAM_BASE_ADDR_BE 0x18823000
#define SEC_CAM_BASE_ADDR_BE 0x18824000
+#define SEC_CAM_BASE_ADDR_BE_8922D 0x1882C000
#define WOW_CAM_BASE_ADDR_BE 0x18828000
#define MLD_TBL_BASE_ADDR_BE 0x18829000
#define RX_CLSF_CAM_BASE_ADDR_BE 0x1882A000
@@ -938,7 +940,7 @@ struct rtw89_mac_size_set {
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;
+ const struct rtw89_dle_size wde_size30;
const struct rtw89_dle_size wde_size31;
const struct rtw89_dle_size ple_size0;
const struct rtw89_dle_size ple_size1;
@@ -953,8 +955,8 @@ struct rtw89_mac_size_set {
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_size27;
+ const struct rtw89_dle_size ple_size31;
const struct rtw89_dle_size ple_size34;
const struct rtw89_wde_quota wde_qt0;
const struct rtw89_wde_quota wde_qt1;
@@ -968,7 +970,7 @@ struct rtw89_mac_size_set {
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_qt30;
const struct rtw89_wde_quota wde_qt31;
const struct rtw89_ple_quota ple_qt0;
const struct rtw89_ple_quota ple_qt1;
@@ -980,6 +982,8 @@ struct rtw89_mac_size_set {
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_qt27;
+ const struct rtw89_ple_quota ple_qt28;
const struct rtw89_ple_quota ple_qt42;
const struct rtw89_ple_quota ple_qt42_v2;
const struct rtw89_ple_quota ple_qt43;
@@ -991,10 +995,8 @@ struct rtw89_mac_size_set {
const struct rtw89_ple_quota ple_qt57;
const struct rtw89_ple_quota ple_qt58;
const struct rtw89_ple_quota ple_qt59;
- const struct rtw89_ple_quota ple_qt72;
- const struct rtw89_ple_quota ple_qt73;
- const struct rtw89_ple_quota ple_qt74;
- const struct rtw89_ple_quota ple_qt75;
+ const struct rtw89_ple_quota ple_qt61;
+ const struct rtw89_ple_quota ple_qt62;
const struct rtw89_ple_quota ple_qt78;
const struct rtw89_ple_quota ple_qt79;
const struct rtw89_ple_quota ple_qt_52a_wow;
@@ -1037,6 +1039,7 @@ struct rtw89_mac_gen_def {
struct rtw89_reg_def narrow_bw_ru_dis;
struct rtw89_reg_def wow_ctrl;
struct rtw89_reg_def agg_limit;
+ struct rtw89_reg_def ra_agg_limit;
struct rtw89_reg_def txcnt_limit;
int (*check_mac_en)(struct rtw89_dev *rtwdev, u8 band,
@@ -1130,6 +1133,18 @@ extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax;
extern const struct rtw89_mac_gen_def rtw89_mac_gen_be;
static inline
+u32 rtw89_mac_mem_base_addrs(struct rtw89_dev *rtwdev, u8 sel)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+
+ if (rtwdev->chip->chip_id == RTL8922D &&
+ sel == RTW89_MAC_MEM_SECURITY_CAM)
+ return SEC_CAM_BASE_ADDR_BE_8922D;
+
+ return mac->mem_base_addrs[sel];
+}
+
+static inline
u32 rtw89_mac_reg_by_idx(struct rtw89_dev *rtwdev, u32 reg_base, u8 band)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
@@ -1813,8 +1828,7 @@ 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;
+ /* The RTL8922DE will re-enable pre-load function after verification. */
return false;
}
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 0ea33743853e..501c3af1da01 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -528,6 +528,8 @@ static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev,
if (vif->type == NL80211_IFTYPE_AP || sta->tdls)
rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
+ rtw89_fw_h2c_init_trx_protect(rtwdev);
+
return 0;
unset_link:
@@ -962,6 +964,7 @@ static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
rtw89_err(rtwdev, "failed to add key to sec cam\n");
return ret;
}
+ rtw89_core_tid_rx_stats_reset(rtwdev);
break;
case DISABLE_KEY:
flush_work(&rtwdev->txq_work);
@@ -1003,6 +1006,8 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw,
clear_bit(tid, rtwsta->ampdu_map);
rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ rtw89_leave_ps_mode(rtwdev);
+ rtw89_phy_ra_recalc_agg_limit(rtwdev);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
set_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags);
@@ -1011,11 +1016,14 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw,
set_bit(tid, rtwsta->ampdu_map);
rtw89_leave_ps_mode(rtwdev);
rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta);
+ rtw89_phy_ra_recalc_agg_limit(rtwdev);
break;
case IEEE80211_AMPDU_RX_START:
+ rtw89_core_tid_rx_stats_ctrl(rtwdev, rtwsta, params, true);
rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, true, params);
break;
case IEEE80211_AMPDU_RX_STOP:
+ rtw89_core_tid_rx_stats_ctrl(rtwdev, rtwsta, params, false);
rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, false, params);
break;
default:
@@ -1584,6 +1592,8 @@ static void __rtw89_ops_clr_vif_links(struct rtw89_dev *rtwdev,
if (unlikely(!rtwvif_link))
continue;
+ rtw89_fw_h2c_trx_protect(rtwdev, rtwvif_link->phy_idx, false);
+
__rtw89_ops_remove_iface_link(rtwdev, rtwvif_link);
rtw89_vif_unset_link(rtwvif, link_id);
@@ -1609,6 +1619,7 @@ static int __rtw89_ops_set_vif_links(struct rtw89_dev *rtwdev,
__func__, link_id);
return ret;
}
+ rtw89_fw_h2c_trx_protect(rtwdev, rtwvif_link->phy_idx, true);
}
return 0;
diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c
index dc66b1ee851a..39a28fd27412 100644
--- a/drivers/net/wireless/realtek/rtw89/mac_be.c
+++ b/drivers/net/wireless/realtek/rtw89/mac_be.c
@@ -3193,6 +3193,8 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
},
.wow_ctrl = {.addr = R_BE_WOW_CTRL, .mask = B_BE_WOW_WOWEN,},
.agg_limit = {.addr = R_BE_AMPDU_AGG_LIMIT, .mask = B_BE_AMPDU_MAX_TIME_MASK,},
+ .ra_agg_limit = {.addr = R_BE_AMPDU_AGG_LIMIT,
+ .mask = B_BE_RA_TRY_RATE_AGG_LMT_MASK,},
.txcnt_limit = {.addr = R_BE_TXCNT, .mask = B_BE_L_TXCNT_LMT_MASK,},
.check_mac_en = rtw89_mac_check_mac_en_be,
diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index ccfa6d33623a..e7da37b9da7d 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_ANA40 0x40
+#define PHY_ERR_IMR_DIS (BIT(9) | BIT(0))
#define RAC_ANA41 0x41
#define PHY_ERR_FLAG_EN BIT(6)
@@ -1016,6 +1018,7 @@
#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 PCIE_SER_WOW_TIMER_UNIT 0x4
#define B_BE_PL1_TIMER_CLEAR BIT(0)
#define R_BE_REG_PL1_MASK 0x34B0
@@ -1028,6 +1031,7 @@
#define B_BE_SER_PMU_IMR BIT(0)
#define R_BE_REG_PL1_ISR 0x34B4
+#define B_PCIE_SER_ALL_ISR 0x7F
#define R_BE_RX_APPEND_MODE 0x8920
#define B_BE_APPEND_OFFSET_MASK GENMASK(23, 16)
@@ -1101,6 +1105,9 @@
B_BE_CH6_BUSY | B_BE_CH7_BUSY | B_BE_CH8_BUSY | \
B_BE_CH9_BUSY | B_BE_CH10_BUSY | B_BE_CH11_BUSY | \
B_BE_CH12_BUSY | B_BE_CH13_BUSY | B_BE_CH14_BUSY)
+#define DMA_BUSY1_CHECK_BE_V1 (B_BE_CH0_BUSY | B_BE_CH2_BUSY | B_BE_CH4_BUSY | \
+ B_BE_CH6_BUSY | B_BE_CH8_BUSY | B_BE_CH10_BUSY | \
+ B_BE_CH12_BUSY)
#define R_BE_HAXI_EXP_CTRL_V1 0xB020
#define B_BE_R_NO_SEC_ACCESS BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c
index 114f40c6c31b..dfffec1ff3c7 100644
--- a/drivers/net/wireless/realtek/rtw89/pci_be.c
+++ b/drivers/net/wireless/realtek/rtw89/pci_be.c
@@ -351,14 +351,41 @@ static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev)
return;
rtw89_write32(rtwdev, R_BE_PL1_DBG_INFO, 0x0);
- rtw89_write32_set(rtwdev, R_BE_FWS1IMR, B_BE_PCIE_SER_TIMEOUT_INDIC_EN);
- rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN);
- rtw89_write32_mask(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_TIMER_UNIT_MASK, 1);
- 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;
- rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32);
+ switch (hal->cv) {
+ case CHIP_CAV:
+ case CHIP_CBV:
+ rtw89_write32_clr(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN);
+ rtw89_write32_mask(rtwdev, R_BE_SER_PL1_CTRL,
+ B_BE_PL1_TIMER_UNIT_MASK, PCIE_SER_TIMER_UNIT);
+
+ 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);
+ rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32);
+ break;
+ case CHIP_CCV:
+ default:
+ rtw89_write32_clr(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN);
+
+ 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");
+
+ 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);
+
+ val32 = rtw89_read32(rtwdev, R_BE_REG_PL1_MASK);
+ val32 |= (B_BE_SER_PMU_IMR | B_BE_SER_PM_MASTER_IMR |
+ B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK |
+ B_BE_SER_PCLKREQ_ACK_MASK);
+ val32 &= ~B_BE_SER_L1SUB_IMR;
+ rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32);
+ break;
+ }
return;
@@ -367,6 +394,11 @@ be2_chips:
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_ANA40 * RAC_MULT, PHY_ERR_IMR_DIS);
+ rtw89_write16_clr(rtwdev, RAC_DIRECT_OFFESET_L0_G2 +
+ RAC_ANA40 * RAC_MULT, PHY_ERR_IMR_DIS);
+
+ 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);
@@ -378,6 +410,7 @@ be2_chips:
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);
+ rtw89_write32(rtwdev, R_BE_REG_PL1_ISR, B_PCIE_SER_ALL_ISR);
ret = read_poll_timeout_atomic(rtw89_read32, val32, !val32,
1, 1000, false, rtwdev, R_BE_REG_PL1_ISR);
@@ -385,9 +418,10 @@ be2_chips:
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 |
+ val32 |= B_BE_SER_PMU_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;
+ val32 &= ~B_BE_SER_L1SUB_IMR;
rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32);
rtw89_write32_mask(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_TIMER_UNIT_MASK,
@@ -721,12 +755,24 @@ static int __maybe_unused rtw89_pci_suspend_be(struct device *dev)
{
struct ieee80211_hw *hw = dev_get_drvdata(dev);
struct rtw89_dev *rtwdev = hw->priv;
+ u32 val32;
rtw89_write32_set(rtwdev, R_BE_RSV_CTRL, B_BE_WLOCK_1C_BIT6);
rtw89_write32_set(rtwdev, R_BE_RSV_CTRL, B_BE_R_DIS_PRST);
rtw89_write32_clr(rtwdev, R_BE_RSV_CTRL, B_BE_WLOCK_1C_BIT6);
rtw89_write32_set(rtwdev, R_BE_PCIE_FRZ_CLK, B_BE_PCIE_FRZ_REG_RST);
- rtw89_write32_clr(rtwdev, R_BE_REG_PL1_MASK, B_BE_SER_PM_MASTER_IMR);
+
+ val32 = rtw89_read32(rtwdev, R_BE_SER_PL1_CTRL);
+ if (val32 & B_BE_PL1_SER_PL1_EN) {
+ val32 = u32_replace_bits(val32, PCIE_SER_WOW_TIMER_UNIT,
+ B_BE_PL1_TIMER_UNIT_MASK);
+ rtw89_write32(rtwdev, R_BE_SER_PL1_CTRL, val32);
+
+ if (rtwdev->chip->chip_id == RTL8922A)
+ rtw89_write32_clr(rtwdev, R_BE_REG_PL1_MASK,
+ B_BE_SER_PM_MASTER_IMR);
+ }
+
return 0;
}
@@ -735,21 +781,57 @@ static int __maybe_unused rtw89_pci_resume_be(struct device *dev)
struct ieee80211_hw *hw = dev_get_drvdata(dev);
struct rtw89_dev *rtwdev = hw->priv;
u32 polling;
+ u32 val32;
+ u16 val16;
int ret;
rtw89_write32_set(rtwdev, R_BE_RSV_CTRL, B_BE_WLOCK_1C_BIT6);
rtw89_write32_clr(rtwdev, R_BE_RSV_CTRL, B_BE_R_DIS_PRST);
rtw89_write32_clr(rtwdev, R_BE_RSV_CTRL, B_BE_WLOCK_1C_BIT6);
rtw89_write32_clr(rtwdev, R_BE_PCIE_FRZ_CLK, B_BE_PCIE_FRZ_REG_RST);
+
+ val32 = rtw89_read32(rtwdev, R_BE_SER_PL1_CTRL);
+ if (!(val32 & B_BE_PL1_SER_PL1_EN))
+ goto clear_phy_isr;
+
rtw89_write32_clr(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN);
+ if (rtwdev->chip->chip_id == RTL8922D)
+ rtw89_write32(rtwdev, R_BE_REG_PL1_ISR, B_PCIE_SER_ALL_ISR);
ret = read_poll_timeout_atomic(rtw89_read32, polling, !polling, 1, 1000,
false, rtwdev, R_BE_REG_PL1_ISR);
if (ret)
rtw89_warn(rtwdev, "[ERR] PCIE SER clear polling fail\n");
- rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN);
- rtw89_write32_set(rtwdev, R_BE_REG_PL1_MASK, B_BE_SER_PM_MASTER_IMR);
+ if (rtwdev->chip->chip_id == RTL8922A)
+ rtw89_write32_set(rtwdev, R_BE_REG_PL1_MASK,
+ B_BE_SER_PM_MASTER_IMR | B_BE_SER_PCLKREQ_ACK_MASK);
+
+ val32 = rtw89_read32(rtwdev, R_BE_SER_PL1_CTRL);
+ val32 = u32_replace_bits(val32, PCIE_SER_TIMER_UNIT, B_BE_PL1_TIMER_UNIT_MASK);
+ val32 |= B_BE_PL1_SER_PL1_EN;
+ rtw89_write32(rtwdev, R_BE_SER_PL1_CTRL, val32);
+
+clear_phy_isr:
+ if (rtwdev->chip->chip_id == RTL8922D) {
+ val16 = rtw89_read16(rtwdev, RAC_DIRECT_OFFESET_L0_G2 +
+ RAC_ANA41 * RAC_MULT);
+ if (val16 & 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_G2 +
+ RAC_ANA41 * RAC_MULT, PHY_ERR_FLAG_EN);
+ }
+
+ val16 = rtw89_read16(rtwdev, RAC_DIRECT_OFFESET_L0_G1 +
+ RAC_ANA41 * RAC_MULT);
+ if (val16 & PHY_ERR_FLAG_EN) {
+ rtw89_write16_clr(rtwdev, RAC_DIRECT_OFFESET_L0_G1 +
+ 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_pci_basic_cfg(rtwdev, true);
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index ee6ab2136b9a..e70d0e283987 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -775,6 +775,33 @@ void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_
rtw89_fw_h2c_ra(rtwdev, ra, csi);
}
+void rtw89_phy_ra_recalc_agg_limit(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ const struct rtw89_reg_def *ra_limit = &mac->ra_agg_limit;
+ struct ieee80211_sta *sta;
+ struct rtw89_sta *rtwsta;
+ u16 agg_num = U16_MAX;
+ u8 tid;
+
+ for_each_station(sta, rtwdev->hw) {
+ rtwsta = sta_to_rtwsta(sta);
+
+ for_each_set_bit(tid, rtwsta->ampdu_map, IEEE80211_NUM_TIDS)
+ agg_num = min(agg_num, rtwsta->ampdu_params[tid].agg_num);
+ }
+
+ if (agg_num == U16_MAX)
+ agg_num = 0x3F;
+ else
+ agg_num = clamp(agg_num, 1, 256) - 1;
+
+ rtw89_write32_idx(rtwdev, ra_limit->addr, ra_limit->mask, agg_num, RTW89_MAC_0);
+ if (!rtwdev->dbcc_en)
+ return;
+ rtw89_write32_idx(rtwdev, ra_limit->addr, ra_limit->mask, agg_num, RTW89_MAC_1);
+}
+
u8 rtw89_phy_get_txsc(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_bandwidth dbw)
@@ -1659,10 +1686,10 @@ static void rtw89_phy_config_rf_reg_noio(struct rtw89_dev *rtwdev,
(struct rtw89_fw_h2c_rf_reg_info *)extra_data);
}
-static void rtw89_phy_config_rf_reg(struct rtw89_dev *rtwdev,
- const struct rtw89_reg2_def *reg,
- enum rtw89_rf_path rf_path,
- void *extra_data)
+void rtw89_phy_config_rf_reg(struct rtw89_dev *rtwdev,
+ const struct rtw89_reg2_def *reg,
+ enum rtw89_rf_path rf_path,
+ void *extra_data)
{
if (reg->addr == 0xfe) {
mdelay(50);
@@ -1781,7 +1808,7 @@ static int rtw89_phy_sel_headline(struct rtw89_dev *rtwdev,
}
static void rtw89_phy_init_reg(struct rtw89_dev *rtwdev,
- const struct rtw89_phy_table *table,
+ const struct rtw89_phy_table *table, bool by_acv,
void (*config)(struct rtw89_dev *rtwdev,
const struct rtw89_reg2_def *reg,
enum rtw89_rf_path rf_path,
@@ -1790,8 +1817,8 @@ static void rtw89_phy_init_reg(struct rtw89_dev *rtwdev,
{
const struct rtw89_reg2_def *reg;
enum rtw89_rf_path rf_path = table->rf_path;
+ u8 cv = by_acv ? rtwdev->hal.acv : rtwdev->hal.cv;
u8 rfe = rtwdev->efuse.rfe_type;
- u8 cv = rtwdev->hal.cv;
u32 i;
u32 headline_size = 0, headline_idx = 0;
u32 target = 0, cfg_target;
@@ -1858,16 +1885,16 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev)
const struct rtw89_phy_table *bb_gain_table;
bb_table = elm_info->bb_tbl ? elm_info->bb_tbl : chip->bb_table;
- rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, NULL);
+ rtw89_phy_init_reg(rtwdev, bb_table, false, rtw89_phy_config_bb_reg, NULL);
if (rtwdev->dbcc_en)
- rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg,
+ rtw89_phy_init_reg(rtwdev, bb_table, false, rtw89_phy_config_bb_reg,
(void *)RTW89_PHY_1);
rtw89_chip_init_txpwr_unit(rtwdev);
bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table;
if (bb_gain_table)
- rtw89_phy_init_reg(rtwdev, bb_gain_table,
+ rtw89_phy_init_reg(rtwdev, bb_gain_table, false,
chip->phy_def->config_bb_gain, NULL);
rtw89_phy_bb_reset(rtwdev);
@@ -1973,6 +2000,7 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_phy_table *rf_table;
struct rtw89_fw_h2c_rf_reg_info *rf_reg_info;
+ bool by_acv = chip->chip_id == RTL8922D;
u8 path;
rf_reg_info = kzalloc_obj(*rf_reg_info);
@@ -1988,7 +2016,7 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
else
config = rf_table->config ? rf_table->config :
rtw89_phy_config_rf_reg;
- rtw89_phy_init_reg(rtwdev, rf_table, config, (void *)rf_reg_info);
+ rtw89_phy_init_reg(rtwdev, rf_table, by_acv, config, (void *)rf_reg_info);
if (rtw89_phy_config_rf_reg_fw(rtwdev, rf_reg_info))
rtw89_warn(rtwdev, "rf path %d reg h2c config failed\n",
rf_reg_info->rf_path);
@@ -2029,7 +2057,7 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
rtw89_phy_preinit_rf_nctl(rtwdev);
nctl_table = elm_info->rf_nctl ? elm_info->rf_nctl : chip->nctl_table;
- rtw89_phy_init_reg(rtwdev, nctl_table, rtw89_phy_config_bb_reg, NULL);
+ rtw89_phy_init_reg(rtwdev, nctl_table, false, rtw89_phy_config_bb_reg, NULL);
if (chip->nctl_post_table)
rtw89_rfk_parser(rtwdev, chip->nctl_post_table);
@@ -3186,7 +3214,8 @@ struct rtw89_phy_iter_ra_data {
static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
struct ieee80211_link_sta *link_sta,
- struct rtw89_phy_iter_ra_data *ra_data)
+ struct rtw89_phy_iter_ra_data *ra_data,
+ bool *changed)
{
struct rtw89_dev *rtwdev = ra_data->rtwdev;
const struct rtw89_c2h_ra_rpt *c2h =
@@ -3195,7 +3224,7 @@ static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
const struct rtw89_chip_info *chip = rtwdev->chip;
bool format_v1 = chip->chip_gen == RTW89_CHIP_BE;
u8 mode, rate, bw, giltf, mac_id;
- u16 legacy_bitrate;
+ u16 legacy_bitrate, amsdu_len;
bool valid;
u8 mcs = 0;
u8 t;
@@ -3292,7 +3321,13 @@ static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
u16_encode_bits(mode, RTW89_HW_RATE_MASK_MOD) |
u16_encode_bits(rate, RTW89_HW_RATE_MASK_VAL);
ra_report->might_fallback_legacy = mcs <= 2;
- link_sta->agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
+
+ amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
+ if (link_sta->agg.max_rc_amsdu_len != amsdu_len) {
+ link_sta->agg.max_rc_amsdu_len = amsdu_len;
+ *changed = true;
+ }
+
rtwsta_link->max_agg_wait = link_sta->agg.max_rc_amsdu_len / 1500 - 1;
}
@@ -3303,14 +3338,18 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
struct rtw89_sta_link *rtwsta_link;
struct ieee80211_link_sta *link_sta;
unsigned int link_id;
+ bool changed = false;
rcu_read_lock();
rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
- __rtw89_phy_c2h_ra_rpt_iter(rtwsta_link, link_sta, ra_data);
+ __rtw89_phy_c2h_ra_rpt_iter(rtwsta_link, link_sta, ra_data, &changed);
}
+ if (changed)
+ ieee80211_sta_recalc_aggregates(sta);
+
rcu_read_unlock();
}
@@ -4860,7 +4899,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev,
{
struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
const struct rtw89_chip_info *chip = rtwdev->chip;
- u8 sc_xi_val, sc_xo_val;
+ u8 sc_xi_val = 0, sc_xo_val = 0;
if (!force && cfo->crystal_cap == crystal_cap)
return;
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index ab263738d212..bde419edf744 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -852,6 +852,10 @@ bool rtw89_phy_write_rf_v3(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev);
void rtw89_phy_init_bb_afe(struct rtw89_dev *rtwdev);
void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio);
+void rtw89_phy_config_rf_reg(struct rtw89_dev *rtwdev,
+ const struct rtw89_reg2_def *reg,
+ enum rtw89_rf_path rf_path,
+ void *extra_data);
void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev,
const struct rtw89_reg2_def *reg,
enum rtw89_rf_path rf_path,
@@ -1002,6 +1006,7 @@ void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta
void rtw89_phy_ra_update_sta_link(struct rtw89_dev *rtwdev,
struct rtw89_sta_link *rtwsta_link,
u32 changed);
+void rtw89_phy_ra_recalc_agg_limit(struct rtw89_dev *rtwdev);
void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask);
diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c
index 08fd24a55d85..929fac1b10d2 100644
--- a/drivers/net/wireless/realtek/rtw89/phy_be.c
+++ b/drivers/net/wireless/realtek/rtw89/phy_be.c
@@ -199,7 +199,7 @@ static u32 rtw89_phy0_phy1_offset_be_v1(struct rtw89_dev *rtwdev, u32 addr)
(phy_page >= 0x240 && phy_page <= 0x24f) ||
(phy_page >= 0x260 && phy_page <= 0x26f) ||
(phy_page >= 0x2C0 && phy_page <= 0x2C9) ||
- (phy_page >= 0x2E4 && phy_page <= 0x2E8) ||
+ (phy_page >= 0x2E0 && phy_page <= 0x2E8) ||
phy_page == 0x2EE)
ofst = 0x1000;
else
diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c
index aad2ee7926d6..125cf14fa581 100644
--- a/drivers/net/wireless/realtek/rtw89/ps.c
+++ b/drivers/net/wireless/realtek/rtw89/ps.c
@@ -226,6 +226,8 @@ void rtw89_leave_lps(struct rtw89_dev *rtwdev)
rtw89_for_each_rtwvif(rtwdev, rtwvif)
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
rtw89_leave_lps_vif(rtwdev, rtwvif_link);
+
+ rtw89_fw_h2c_init_trx_protect(rtwdev);
}
void rtw89_enter_ips(struct rtw89_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 9b605617c3f0..42ffe83931a3 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -4291,6 +4291,20 @@
#define B_BE_VERIFY_ENV_MASK GENMASK(9, 8)
#define B_BE_HW_ID_MASK GENMASK(7, 0)
+#define R_BE_SCOREBOARD_0 0x0110
+#define B_BE_SB0_TOGGLE BIT(31)
+#define B_BE_SB0_WL_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_0_BT_DATA 0x0114
+#define B_BE_SB0_BT_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_1 0x0118
+#define B_BE_SB1_TOGGLE BIT(31)
+#define B_BE_SB1_WL_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_1_BT_DATA 0x011C
+#define B_BE_SB1_BT_DATA_LINE_MASK GENMASK(30, 0)
+
#define R_BE_HALT_H2C_CTRL 0x0160
#define B_BE_HALT_H2C_TRIGGER BIT(0)
@@ -4403,6 +4417,31 @@
#define B_BE_FS_GPIO17_INT_EN BIT(1)
#define B_BE_FS_GPIO16_INT_EN BIT(0)
+#define R_BE_FWS1ISR 0x019C
+#define B_BE_FS_WL_HW_RADIO_OFF_INT BIT(28)
+#define B_BE_SWRD_BOD_INT BIT(27)
+#define B_BE_HCIDBG_INT BIT(25)
+#define B_BE_FS_RPWM_INT_V1 BIT(24)
+#define B_BE_PCIE_HOTRST BIT(22)
+#define B_BE_PCIE_SER_TIMEOUT_INDIC BIT(21)
+#define B_BE_PCIE_RXI300_SLVTOUT_INDIC BIT(20)
+#define B_BE_AON_PCIE_FLR_INT BIT(19)
+#define B_BE_PCIE_ERR_INDIC BIT(18)
+#define B_BE_SDIO_ERR_INDIC BIT(17)
+#define B_BE_USB_ERR_INDIC BIT(16)
+#define B_BE_FS_GPIO27_INT BIT(11)
+#define B_BE_FS_GPIO26_INT BIT(10)
+#define B_BE_FS_GPIO25_INT BIT(9)
+#define B_BE_FS_GPIO24_INT BIT(8)
+#define B_BE_FS_GPIO23_INT BIT(7)
+#define B_BE_FS_GPIO22_INT BIT(6)
+#define B_BE_FS_GPIO21_INT BIT(5)
+#define B_BE_FS_GPIO20_INT BIT(4)
+#define B_BE_FS_GPIO19_INT BIT(3)
+#define B_BE_FS_GPIO18_INT BIT(2)
+#define B_BE_FS_GPIO17_INT BIT(1)
+#define B_BE_FS_GPIO16_INT BIT(0)
+
#define R_BE_HIMR0 0x01A0
#define B_BE_WDT_DATACPU_TIMEOUT_INT_EN BIT(25)
#define B_BE_HALT_D2H_INT_EN BIT(24)
@@ -4503,6 +4542,44 @@
#define R_BE_UDM2 0x01F8
#define B_BE_UDM2_EPC_RA_MASK GENMASK(31, 0)
+#define R_BE_SPS_DIG_ON_CTRL1 0x0204
+#define B_BE_SN_N_L_MASK GENMASK(31, 28)
+#define B_BE_SP_N_L_MASK GENMASK(27, 24)
+#define B_BE_SN_P_L_MASK GENMASK(23, 20)
+#define B_BE_SP_P_L_MASK GENMASK(19, 16)
+#define B_BE_VO_DISCHG_PWM_H BIT(15)
+#define B_BE_REG_MODE_PREDRIVER BIT(14)
+#define B_BE_VREFOCP_MASK GENMASK(13, 10)
+#define B_BE_POWOCP_L1 BIT(9)
+#define B_BE_PWM_FORCE BIT(8)
+#define B_BE_PFM_PD_RST BIT(7)
+#define B_BE_VC_PFM_RSTB BIT(6)
+#define B_BE_PFM_IN_SEL BIT(5)
+#define B_BE_VC_RSTB BIT(4)
+#define B_BE_FPWMDELAY BIT(3)
+#define B_BE_ENFPWMDELAY_H BIT(2)
+#define B_BE_REG_MOS_HALF_L BIT(1)
+#define B_BE_CURRENT_SENSE_MOS BIT(0)
+
+#define R_BE_SPS_ANA_ON_CTRL1 0x0224
+#define B_BE_SN_N_L_ANA_MASK GENMASK(31, 28)
+#define B_BE_SP_N_L_ANA_MASK GENMASK(27, 24)
+#define B_BE_SN_P_L_ANA_MASK GENMASK(23, 20)
+#define B_BE_SP_P_L_ANA_MASK GENMASK(19, 16)
+#define B_BE_VO_DISCHG_PWM_H_ANA BIT(15)
+#define B_BE_REG_MODE_PREDRIVER_ANA BIT(14)
+#define B_BE_VREFOCP_ANA_MASK GENMASK(13, 10)
+#define B_BE_POWOCP_L1_ANA BIT(9)
+#define B_BE_PWM_FORCE_ANA BIT(8)
+#define B_BE_PFM_PD_RST_ANA BIT(7)
+#define B_BE_VC_PFM_RSTB_ANA BIT(6)
+#define B_BE_PFM_IN_SEL_ANA BIT(5)
+#define B_BE_VC_RSTB_ANA BIT(4)
+#define B_BE_FPWMDELAY_ANA BIT(3)
+#define B_BE_ENFPWMDELAY_H_ANA BIT(2)
+#define B_BE_REG_MOS_HALF_L_ANA BIT(1)
+#define B_BE_CURRENT_SENSE_MOS_ANA BIT(0)
+
#define R_BE_AFE_ON_CTRL0 0x0240
#define B_BE_REG_LPF_R3_3_0_MASK GENMASK(31, 29)
#define B_BE_REG_LPF_R2_MASK GENMASK(28, 24)
@@ -6738,6 +6815,7 @@
#define R_BE_MUEDCA_EN 0x10370
#define R_BE_MUEDCA_EN_C1 0x14370
#define B_BE_SIFS_TIMEOUT_TB_T2_MASK GENMASK(30, 24)
+#define B_BE_SIFS_MACTXEN_TB_T1_DOT05US_MASK GENMASK(23, 16)
#define B_BE_SIFS_MACTXEN_TB_T1_MASK GENMASK(22, 16)
#define B_BE_MUEDCA_WMM_SEL BIT(8)
#define B_BE_SET_MUEDCATIMER_TF_MASK GENMASK(5, 4)
@@ -8320,6 +8398,9 @@
#define B_BE_PWR_BT_VAL GENMASK(8, 0)
#define B_BE_PWR_FORCE_COEX_ON GENMASK(29, 27)
+#define R_PWR_BOOST_BE4 0x11A64
+#define B_PWR_BOOST_BE4 BIT(8)
+
#define R_BE_PWR_TH 0x11A78
#define R_BE_PWR_RSSI_TARGET_LMT 0x11A84
@@ -8378,6 +8459,8 @@
#define RR_MOD_M_RXBB GENMASK(9, 5)
#define RR_MOD_LO_SEL BIT(1)
#define RR_MODOPT 0x01
+#define RR_MODOPT_V1 0x10001
+#define RR_SW_SEL BIT(19)
#define RR_TXG_SEL GENMASK(19, 17)
#define RR_MODOPT_M_TXPWR GENMASK(5, 0)
#define RR_WLSEL 0x02
@@ -8454,6 +8537,7 @@
#define RR_LUTWD0_LB GENMASK(5, 0)
#define RR_TM 0x42
#define RR_TM_TRI BIT(19)
+#define RR_TM_TRM GENMASK(17, 11)
#define RR_TM_VAL_V1 GENMASK(7, 0)
#define RR_TM_VAL GENMASK(6, 1)
#define RR_TM2 0x43
@@ -8586,6 +8670,7 @@
#define RR_LDO 0xb1
#define RR_LDO_SEL GENMASK(8, 6)
#define RR_VCO 0xb2
+#define RR_VCO_VAL GENMASK(18, 14)
#define RR_VCO_SEL GENMASK(9, 8)
#define RR_VCI 0xb3
#define RR_VCI_ON BIT(7)
@@ -8709,6 +8794,7 @@
#define B_P0_HW_ANTSW_DIS_BY_GNT_BT BIT(12)
#define B_P0_TRSW_TX_EXTEND GENMASK(3, 0)
#define R_MAC_PIN_SEL 0x0734
+#define R_MAC_PIN_SEL_BE4 0x20734
#define B_CH_IDX_SEG0 GENMASK(23, 16)
#define R_PLCP_HISTOGRAM 0x0738
#define R_PLCP_HISTOGRAM_BE_V1 0x20738
@@ -8737,6 +8823,7 @@
#define R_PHY_STS_BITMAP_EHT 0x0788
#define R_PHY_STS_BITMAP_EHT_BE4 0x20788
#define R_EDCCA_RPTREG_SEL_BE 0x078C
+#define R_EDCCA_RPTREG_SEL_BE4 0x2078C
#define B_EDCCA_RPTREG_SEL_BE_MSK GENMASK(22, 20)
#define R_PMAC_GNT 0x0980
#define B_PMAC_GNT_TXEN BIT(0)
@@ -8850,6 +8937,7 @@
#define R_UDP_COEEF 0x0CBC
#define B_UDP_COEEF BIT(19)
#define R_TX_COLLISION_T2R_ST_BE 0x0CC8
+#define R_TX_COLLISION_T2R_ST_BE4 0x20CC8
#define B_TX_COLLISION_T2R_ST_BE_M GENMASK(13, 8)
#define R_RXHT_MCS_LIMIT 0x0D18
#define B_RXHT_MCS_LIMIT GENMASK(9, 8)
@@ -9078,7 +9166,11 @@
#define R_P1_EN_SOUND_WO_NDP 0x2D7C
#define B_P1_EN_SOUND_WO_NDP BIT(1)
#define R_EDCCA_RPT_A_BE 0x2E38
+#define R_EDCCA_RPT_A_BE4 0x2EE30
+#define R_EDCCA_RPT_A_BE4_C1 0x2FE30
#define R_EDCCA_RPT_B_BE 0x2E3C
+#define R_EDCCA_RPT_B_BE4 0x2EE34
+#define R_EDCCA_RPT_B_BE4_C1 0x2FE34
#define R_EDCCA_RPT_P1_A_BE 0x2E40
#define R_EDCCA_RPT_P1_B_BE 0x2E44
#define R_S1_HW_SI_DIS 0x3200
@@ -9262,11 +9354,13 @@
#define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V1 0x4C24
#define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V2 0x46E8
#define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V3 0x41C8
+#define R_PATH0_P20_FOLLOW_BY_PAGCUGC_BE4 0x241C8
#define B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5)
#define R_PATH0_S20_FOLLOW_BY_PAGCUGC 0x46A4
#define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V1 0x4C28
#define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V2 0x46EC
#define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V3 0x41CC
+#define R_PATH0_S20_FOLLOW_BY_PAGCUGC_BE4 0x241CC
#define B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5)
#define R_PATH0_RXB_INIT_V1 0x46A8
#define B_PATH0_RXB_INIT_IDX_MSK_V1 GENMASK(14, 10)
@@ -9313,11 +9407,13 @@
#define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V1 0x4CE8
#define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V2 0x47A8
#define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V3 0x45C8
+#define R_PATH1_P20_FOLLOW_BY_PAGCUGC_BE4 0x245C8
#define B_PATH1_P20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5)
#define R_PATH1_S20_FOLLOW_BY_PAGCUGC 0x4778
#define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V1 0x4CEC
#define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V2 0x47AC
#define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V3 0x45CC
+#define R_PATH1_S20_FOLLOW_BY_PAGCUGC_BE4 0x245CC
#define B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5)
#define R_PATH1_G_TIA0_LNA6_OP1DB_V1 0x4778
#define B_PATH1_G_TIA0_LNA6_OP1DB_V1 GENMASK(7, 0)
@@ -9338,6 +9434,7 @@
#define R_SEG0R_PD 0x481C
#define R_SEG0R_PD_V1 0x4860
#define R_SEG0R_PD_V2 0x6A74
+#define R_SEG0R_PD_BE4 0x26210
#define R_SEG0R_EDCCA_LVL 0x4840
#define R_SEG0R_EDCCA_LVL_V1 0x4884
#define B_EDCCA_LVL_MSK3 GENMASK(31, 24)
@@ -9476,9 +9573,11 @@
#define B_DCFO_COMP_S0_V1_MSK GENMASK(13, 0)
#define R_BMODE_PDTH_V1 0x4B64
#define R_BMODE_PDTH_V2 0x6708
+#define R_BMODE_PDTH_BE4 0x26040
#define B_BMODE_PDTH_LOWER_BOUND_MSK_V1 GENMASK(31, 24)
#define R_BMODE_PDTH_EN_V1 0x4B74
#define R_BMODE_PDTH_EN_V2 0x6718
+#define R_BMODE_PDTH_EN_BE4 0x26050
#define B_BMODE_PDTH_LIMIT_EN_MSK_V1 BIT(30)
#define R_BSS_CLR_VLD_V2 0x4EBC
#define B_BSS_CLR_VLD0_V2 BIT(2)
@@ -9653,7 +9752,9 @@
#define R_CCK_FC0INV 0x675c
#define B_CCK_FC0INV GENMASK(18, 0)
#define R_SEG0R_EDCCA_LVL_BE 0x69EC
+#define R_SEG0R_EDCCA_LVL_BE4 0x2623C
#define R_SEG0R_PPDU_LVL_BE 0x69F0
+#define R_SEG0R_PPDU_LVL_BE4 0x26240
#define R_SEGSND 0x6A14
#define B_SEGSND_EN BIT(31)
#define R_DBCC 0x6B48
@@ -10148,6 +10249,8 @@
#define B_TSSI_CONT_EN BIT(3)
#define R_P0_TXPWRB_BE 0xE61C
#define R_P1_TXPWRB_BE 0xE71C
+#define R_P0_TXPWRB_BE4 0x2251C
+#define R_P1_TXPWRB_BE4 0x2261C
#define B_TXPWRB_MAX_BE GENMASK(20, 12)
#define R_TSSI_MAP_OFST_P0 0xE620
#define R_TSSI_MAP_OFST_P1 0xE720
@@ -10166,6 +10269,8 @@
#define R_TSSI_K_P1 0xE7A0
#define B_TSSI_K_OFDM_P1 GENMASK(29, 20)
+#define R_BBWRAP_ELMSR_BE4 0x11974
+#define B_BBWRAP_ELMSR_EN_BE4 GENMASK(29, 28)
#define R_COMP_CIM3K_BE4 0x11998
#define B_COMP_CIM3K_OW_BE4 BIT(1)
#define B_COMP_CIM3K_TH_BE4 BIT(2)
@@ -10370,16 +10475,51 @@
#define R_BANDEDGE_DBWY_BE4 0x11AD0
#define B_BANDEDGE_DBW160_BE4 BIT(0)
+#define R_SYS_DBCC_BE4 0x20000
+#define B_SYS_DBCC_BE4 BIT(0)
+#define B_SYS_DBCC_24G_BAND_SEL_BE4 BIT(1)
+#define R_EMLSR_SWITCH_BE4 0x20044
+#define B_EMLSR_SWITCH_BE4 GENMASK(27, 12)
+#define B_EMLSR_BB_CLK_BE4 GENMASK(31, 30)
#define R_CHINFO_SEG_BE4 0x200B4
#define B_CHINFO_SEG_LEN_BE4 GENMASK(12, 10)
-#define R_STS_HDR2_PARSING_BE4 0x2070C
-#define B_STS_HDR2_PARSING_BE4 BIT(10)
+#define R_SEL_GNT_BT_RX_BE4 0x2010C
+#define B_SEL_GNT_BT_RX_PATH0_BE4 GENMASK(3, 0)
+#define B_SEL_GNT_BT_RX_PATH1_BE4 GENMASK(11, 8)
#define R_SW_SI_WDATA_BE4 0x20370
#define B_SW_SI_DATA_PATH_BE4 GENMASK(31, 28)
#define B_SW_SI_DATA_ADR_BE4 GENMASK(27, 20)
#define B_SW_SI_DATA_DAT_BE4 GENMASK(19, 0)
#define R_SW_SI_READ_ADDR_BE4 0x20378
#define B_SW_SI_READ_ADDR_BE4 GENMASK(10, 0)
+#define R_RXBW67_BE4 0x2040C
+#define B_RXBW6_BE4 GENMASK(22, 20)
+#define B_RXBW7_BE4 GENMASK(25, 23)
+#define R_RXBW_BE4 0x20410
+#define B_RXBW_BE4 GENMASK(29, 27)
+#define R_TXERRCT_EN_BE4 0x20518
+#define B_TXERRCT_EN_BE4 BIT(13)
+#define R_TXERRCT1_EN_BE4 0x2051C
+#define B_TXERRCT1_EN_BE4 BIT(31)
+#define R_ENABLE_CCK0_BE4 0x20700
+#define B_ENABLE_CCK0_BE4 BIT(5)
+#define R_RSTB_ASYNC_BE4 0x20704
+#define B_RSTB_ASYNC_BE4 BIT(1)
+#define R_STS_HDR2_PARSING_BE4 0x2070C
+#define B_STS_HDR2_PARSING_BE4 BIT(10)
+#define R_EDCCA_RPT_SEL_BE4 0x20780
+#define R_EDCCA_RPT_SEL_BE4_C1 0x21780
+#define B_EDCCA_RPT_SEL_BE4_MSK 0xE0000
+#define R_SEL_GNT_BT_RXPHY_BE4 0x2079C
+#define B_SEL_GNT_BT_RXPHY_BE4 GENMASK(11, 8)
+#define R_IMR_TX_ERROR_BE4 0x20920
+#define B_IMR_TX_ERROR_BE4 BIT(30)
+#define R_TXINFO_PATH_BE4 0x209A4
+#define B_TXINFO_PATH_EN_BE4 BIT(17)
+#define B_TXINFO_PATH_MA_BE4 BIT(18)
+#define B_TXINFO_PATH_MB_BE4 BIT(19)
+#define R_SHAPER_COEFF_BE4 0x20CBC
+#define B_SHAPER_COEFF_BE4 BIT(19)
#define R_IFS_T1_AVG_BE4 0x20EDC
#define B_IFS_T1_AVG_BE4 GENMASK(15, 0)
#define B_IFS_T2_AVG_BE4 GENMASK(31, 16)
@@ -10402,15 +10542,137 @@
#define B_IFS_T3_HIS_BE4 GENMASK(15, 0)
#define B_IFS_T4_HIS_BE4 GENMASK(31, 16)
+#define R_TX_ERROR_SEL_BE4 0x21254
+#define B_TX_ERROR_PSDU_BE4 BIT(11)
+#define B_TX_ERROR_NSYM_BE4 BIT(10)
+#define B_TX_ERROR_LSIG_BE4 BIT(9)
+#define B_TX_ERROR_TXINFO_BE4 BIT(8)
+
+#define R_TXPWR_RSTB0_BE4 0x2250C
+#define B_TXPWR_RSTB0_BE4 BIT(16)
+#define R_TSSI_EN_P0_BE4 0x22510
+#define B_TSSI_EN_P0_BE4 GENMASK(3, 0)
+#define R_TXAGC_REF_DBM_PATH0_TBL0_BE4 0x22528
+#define B_TXAGC_OFDM_REF_DBM_PATH0_TBL0_BE4 GENMASK(8, 0)
+#define B_TXAGC_CCK_REF_DBM_PATH0_TBL0_BE4 GENMASK(17, 9)
+#define R_USED_TSSI_TRK_ON_P0_BE4 0x22534
+#define B_USED_TSSI_TRK_ON_P0_BE4 BIT(22)
+#define R_TSSI_K_OFDM_PATH0_TBL0_BE4 0x225A0
+#define B_TSSI_K_OFDM_PATH0_TBL0_BE4 GENMASK(29, 20)
+#define R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 0x225CC
+#define B_TSSI_DCK_MOV_AVG_LEN_P0_BE4 GENMASK(8, 6)
+#define R_TXPWR_RSTB1_BE4 0x2260C
+#define B_TXPWR_RSTB1_BE4 BIT(16)
+
+#define R_TXAGC_REF_DBM_PATH0_TBL1_BE4 0x23528
+#define B_TXAGC_OFDM_REF_DBM_PATH0_TBL1_BE4 GENMASK(8, 0)
+#define B_TXAGC_CCK_REF_DBM_PATH0_TBL1_BE4 GENMASK(17, 9)
+#define R_TSSI_K_OFDM_PATH0_TBL1_BE4 0x235A0
+#define B_TSSI_K_OFDM_PATH0_TBL1_BE4 GENMASK(29, 20)
+
+#define R_OFDM_OFST_P0_BE4 0x240C8
+#define B_OFDM_OFST_P0_BE4 GENMASK(31, 24)
+#define R_PATH0_RXIDX_INIT_BE4 0x24108
+#define B_PATH0_RXIDX_INIT_BE4 GENMASK(29, 25)
+#define R_PATH0_LNA_INIT_BE4 0x24158
+#define B_PATH0_LNA_INIT_IDX_BE4 GENMASK(14, 12)
+#define R_BAND_SEL0_BE4 0x24160
+#define B_BAND_SEL0_BE4 BIT(26)
+#define R_PATH0_TIA_INIT_BE4 0x24168
+#define B_PATH0_TIA_INIT_IDX_BE4 BIT(18)
+#define R_OFDM_RPL_BIAS_P0_BE4 0x2420C
+#define B_OFDM_RPL_BIAS_P0_BE4 GENMASK(11, 2)
+#define R_OFDM_OFST_P1_BE4 0x244C8
+#define B_OFDM_OFST_P1_BE4 GENMASK(31, 24)
+#define R_PATH1_RXIDX_INIT_BE4 0x24508
+#define B_PATH1_RXIDX_INIT_BE4 GENMASK(29, 25)
+#define R_PATH1_LNA_INIT_BE4 0x24558
+#define B_PATH1_LNA_INIT_IDX_BE4 GENMASK(14, 12)
+#define R_BAND_SEL1_BE4 0x24560
+#define B_BAND_SEL1_BE4 BIT(26)
+#define R_PATH1_TIA_INIT_BE4 0x24568
+#define B_PATH1_TIA_INIT_IDX_BE4 BIT(18)
+#define R_OFDM_RPL_BIAS_P1_BE4 0x2460C
+#define B_OFDM_RPL_BIAS_P1_BE4 GENMASK(11, 2)
#define R_TX_CFR_MANUAL_EN_BE4 0x2483C
#define B_TX_CFR_MANUAL_EN_BE4_M BIT(30)
-
+#define R_PCOEFF0_BE4 0x24880
+#define B_PCOEFF01_BE4 GENMASK(23, 0)
+#define R_PCOEFF2_BE4 0x24884
+#define B_PCOEFF23_BE4 GENMASK(23, 0)
+#define R_PCOEFF4_BE4 0x24888
+#define B_PCOEFF45_BE4 GENMASK(23, 0)
+#define R_PCOEFF6_BE4 0x2488C
+#define B_PCOEFF67_BE4 GENMASK(23, 0)
+#define R_PCOEFF8_BE4 0x24890
+#define B_PCOEFF89_BE4 GENMASK(23, 0)
+#define R_PCOEFF10_BE4 0x24894
+#define B_PCOEFF10_BE4 GENMASK(23, 0)
+#define R_PCOEFF12_BE4 0x24898
+#define B_PCOEFF12_BE4 GENMASK(23, 0)
+#define R_PCOEFF14_BE4 0x2489C
+#define B_PCOEFF14_BE4 GENMASK(23, 0)
+#define R_BW_BE4 0x24EE4
+#define B_BW_BE4 GENMASK(6, 4)
+#define B_PRISB_BE4 GENMASK(3, 0)
+#define R_FC0_BE4 0x24EE8
+#define B_FC0_BE4 GENMASK(12, 0)
+#define R_ANT_RX_1RCCA_BE4 0x24EEC
+#define B_ANT_RX_1RCCA_BE4 GENMASK(17, 14)
+#define R_ANT_RX_BE4 0x24EF0
+#define B_ANT_RX_BE4 GENMASK(3, 0)
+#define R_FC0_INV_BE4 0x24EF4
+#define B_FC0_INV_BE4 GENMASK(15, 0)
+
+#define R_CCK_RPL_OFST_BE4 0x26084
+#define B_CCK_RPL_OFST_BE4 GENMASK(7, 0)
+#define R_BK_FC0_INV_BE4 0x2608C
+#define B_BK_FC0_INV_BE4 GENMASK(18, 0)
+#define R_CCK_FC0_INV_BE4 0x26090
+#define B_CCK_FC0_INV_BE4 GENMASK(18, 0)
+#define R_GAIN_BIAS_BE4 0x260A0
+#define B_GAIN_BIAS_BW20_BE4 GENMASK(11, 6)
+#define B_GAIN_BIAS_BW40_BE4 GENMASK(17, 12)
+#define R_AWGN_DET_BE4 0x2668C
+#define B_AWGN_DET_BE4 GENMASK(17, 9)
+#define R_CSI_WGT_BE4 0x26770
+#define B_CSI_WGT_EN_BE4 BIT(0)
+#define B_CSI_WGT_IDX_BE4 GENMASK(31, 20)
#define R_CHINFO_OPT_BE4 0x267C8
#define B_CHINFO_OPT_BE4 GENMASK(14, 13)
#define R_CHINFO_NX_BE4 0x267D0
#define B_CHINFO_NX_BE4 GENMASK(16, 6)
#define R_CHINFO_ALG_BE4 0x267C8
#define B_CHINFO_ALG_BE4 GENMASK(31, 30)
+#define R_RX_AWGN02_BE4 0x2680C
+#define B_RX_AWGN11_BE4 GENMASK(23, 18)
+#define R_RX_AWGN00_BE4 0x26814
+#define B_RX_AWGN04_BE4 GENMASK(5, 0)
+#define B_RX_AWGN07_BE4 GENMASK(23, 18)
+#define R_RX_AWGN01_BE4 0x26818
+#define B_RX_AWGN09_BE4 GENMASK(5, 0)
+#define R_RXCH_BCC0_BE4 0x26824
+#define B_RXCH_MCS4_BE4 GENMASK(29, 24)
+#define R_RXCH_BCC1_BE4 0x26828
+#define B_RXCH_MCS5_BE4 GENMASK(5, 0)
+#define B_RXCH_MCS6_BE4 GENMASK(11, 6)
+#define B_RXCH_MCS7_BE4 GENMASK(17, 12)
+#define B_RXCH_MCS8_BE4 GENMASK(23, 18)
+#define B_RXCH_MCS9_BE4 GENMASK(29, 24)
+#define R_RX_LDPC02_BE4 0x26834
+#define B_RX_LDPC10_BE4 GENMASK(17, 12)
+#define B_RX_LDPC11_BE4 GENMASK(23, 18)
+#define R_RX_LDPC00_BE4 0x2683C
+#define B_RX_LDPC04_BE4 GENMASK(5, 0)
+#define B_RX_LDPC05_BE4 GENMASK(11, 6)
+#define B_RX_LDPC06_BE4 GENMASK(17, 12)
+#define B_RX_LDPC07_BE4 GENMASK(23, 18)
+#define B_RX_LDPC08_BE4 GENMASK(29, 24)
+#define R_RX_LDPC01_BE4 0x26840
+#define B_RX_LDPC09_BE4 GENMASK(5, 0)
+#define R_BSS_CLR_MAP_BE4 0x26914
+#define R_BSS_CLR_VLD_BE4 0x26920
+#define B_BSS_CLR_VLD_BE4 BIT(2)
#define R_SW_SI_DATA_BE4 0x2CF4C
#define B_SW_SI_READ_DATA_BE4 GENMASK(19, 0)
@@ -10418,6 +10680,25 @@
#define B_SW_SI_R_BUSY_BE4 BIT(25)
#define B_SW_SI_READ_DATA_DONE_BE4 BIT(26)
+#define R_RX_PATH0_TBL0_BE4 0x2E028
+#define R_RX_PATH1_TBL0_BE4 0x2E128
+
+#define R_KTBL0A_BE4 0x38104
+#define R_KTBL0B_BE4 0x38204
+#define B_KTBL0_IDX0 GENMASK(1, 0)
+#define B_KTBL0_IDX1 GENMASK(9, 8)
+#define B_KTBL0_RST BIT(31)
+#define R_KTBL1A_BE4 0x38154
+#define R_KTBL1B_BE4 0x38254
+#define B_KTBL1_TBL0 BIT(3)
+#define B_KTBL1_TBL1 BIT(5)
+
+#define R_TC_EN_BE4 0x3c200
+#define B_TC_EN_BE4 BIT(0)
+#define B_TC_TRIG_BE4 BIT(1)
+#define R_TC_VAL_BE4 0x3c208
+#define B_TC_VAL_BE4 GENMASK(7, 0)
+
/* WiFi CPU local domain */
#define R_AX_WDT_CTRL 0x0040
#define B_AX_WDT_EN BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index d6deb44a685b..84bdd39b3ceb 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -15,10 +15,10 @@
#include "txrx.h"
#include "util.h"
-#define RTW8851B_FW_FORMAT_MAX 0
+#define RTW8851B_FW_FORMAT_MAX 1
#define RTW8851B_FW_BASENAME "rtw89/rtw8851b_fw"
#define RTW8851B_MODULE_FIRMWARE \
- RTW8851B_FW_BASENAME ".bin"
+ RTW89_GEN_MODULE_FWNAME(RTW8851B_FW_BASENAME, RTW8851B_FW_FORMAT_MAX)
static const struct rtw89_hfc_ch_cfg rtw8851b_hfc_chcfg_pcie[] = {
{5, 343, grp_0}, /* ACH 0 */
@@ -52,25 +52,25 @@ static const struct rtw89_hfc_param_ini rtw8851b_hfc_param_ini_pcie[] = {
};
static const struct rtw89_hfc_ch_cfg rtw8851b_hfc_chcfg_usb[] = {
- {18, 152, grp_0}, /* ACH 0 */
- {18, 152, grp_0}, /* ACH 1 */
- {18, 152, grp_0}, /* ACH 2 */
- {18, 152, grp_0}, /* ACH 3 */
+ {18, 210, grp_0}, /* ACH 0 */
+ {18, 210, grp_0}, /* ACH 1 */
+ {18, 210, grp_0}, /* ACH 2 */
+ {18, 210, grp_0}, /* ACH 3 */
{0, 0, grp_0}, /* ACH 4 */
{0, 0, grp_0}, /* ACH 5 */
{0, 0, grp_0}, /* ACH 6 */
{0, 0, grp_0}, /* ACH 7 */
- {18, 152, grp_0}, /* B0MGQ */
- {18, 152, grp_0}, /* B0HIQ */
+ {18, 210, grp_0}, /* B0MGQ */
+ {18, 210, grp_0}, /* B0HIQ */
{0, 0, grp_0}, /* B1MGQ */
{0, 0, grp_0}, /* B1HIQ */
{0, 0, 0} /* FWCMDQ */
};
static const struct rtw89_hfc_pub_cfg rtw8851b_hfc_pubcfg_usb = {
- 152, /* Group 0 */
+ 210, /* Group 0 */
0, /* Group 1 */
- 152, /* Public Max */
+ 210, /* Public Max */
0 /* WP threshold */
};
@@ -111,10 +111,10 @@ static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = {
};
static const struct rtw89_dle_mem rtw8851b_dle_mem_usb2[] = {
- [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25,
- &rtw89_mac_size.ple_size32, &rtw89_mac_size.wde_qt25,
- &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt72,
- &rtw89_mac_size.ple_qt73},
+ [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size30,
+ &rtw89_mac_size.ple_size27, &rtw89_mac_size.wde_qt30,
+ &rtw89_mac_size.wde_qt30, &rtw89_mac_size.ple_qt61,
+ &rtw89_mac_size.ple_qt62},
[RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9,
&rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4,
&rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13,
@@ -124,10 +124,10 @@ static const struct rtw89_dle_mem rtw8851b_dle_mem_usb2[] = {
};
static const struct rtw89_dle_mem rtw8851b_dle_mem_usb3[] = {
- [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25,
- &rtw89_mac_size.ple_size33, &rtw89_mac_size.wde_qt25,
- &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt74,
- &rtw89_mac_size.ple_qt75},
+ [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size30,
+ &rtw89_mac_size.ple_size31, &rtw89_mac_size.wde_qt30,
+ &rtw89_mac_size.wde_qt30, &rtw89_mac_size.ple_qt27,
+ &rtw89_mac_size.ple_qt28},
[RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9,
&rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4,
&rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13,
@@ -2580,8 +2580,11 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.ops = &rtw8851b_chip_ops,
.mac_def = &rtw89_mac_gen_ax,
.phy_def = &rtw89_phy_gen_ax,
- .fw_basename = RTW8851B_FW_BASENAME,
- .fw_format_max = RTW8851B_FW_FORMAT_MAX,
+ .fw_def = {
+ .fw_basename = RTW8851B_FW_BASENAME,
+ .fw_format_max = RTW8851B_FW_FORMAT_MAX,
+ .fw_b_aid = 0,
+ },
.try_ce_fw = true,
.bbmcu_nr = 0,
.needed_fw_elms = 0,
@@ -2638,7 +2641,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.support_noise = false,
.ul_tb_waveform_ctrl = true,
.ul_tb_pwr_diff = false,
- .rx_freq_frome_ie = true,
+ .rx_freq_from_ie = true,
.hw_sec_hdr = false,
.hw_mgmt_tx_encrypt = false,
.hw_tkip_crypto = false,
@@ -2678,6 +2681,10 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.rf_para_ulink = rtw89_btc_8851b_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8851b_rf_dl),
.rf_para_dlink = rtw89_btc_8851b_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED),
.low_power_hci_modes = 0,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
index 959d62aefdd8..6a8d31544314 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
@@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8851b_usb_info = {
.usb3_mac_npi_config_intf_0 = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
.usb_endpoint_0 = R_AX_USB_ENDPOINT_0,
.usb_endpoint_2 = R_AX_USB_ENDPOINT_2,
+ .rx_agg_alignment = 8,
.bulkout_id = {
[RTW89_DMA_ACH0] = 3,
[RTW89_DMA_ACH1] = 4,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 5ea7a36ab5ab..1d4f1df524a1 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -12,10 +12,10 @@
#include "rtw8852a_table.h"
#include "txrx.h"
-#define RTW8852A_FW_FORMAT_MAX 0
+#define RTW8852A_FW_FORMAT_MAX 1
#define RTW8852A_FW_BASENAME "rtw89/rtw8852a_fw"
#define RTW8852A_MODULE_FIRMWARE \
- RTW8852A_FW_BASENAME ".bin"
+ RTW89_GEN_MODULE_FWNAME(RTW8852A_FW_BASENAME, RTW8852A_FW_FORMAT_MAX)
static const struct rtw89_hfc_ch_cfg rtw8852a_hfc_chcfg_pcie[] = {
{128, 1896, grp_0}, /* ACH 0 */
@@ -2179,6 +2179,57 @@ static void rtw8852a_query_ppdu(struct rtw89_dev *rtwdev,
rtw8852a_fill_freq_with_ppdu(rtwdev, phy_ppdu, status);
}
+#define DECLARE_DIG_TABLE(name) \
+static const struct rtw89_phy_dig_gain_cfg name##_table = { \
+ .table = name, \
+ .size = ARRAY_SIZE(name) \
+}
+
+static const struct rtw89_reg_def rtw89_8852a_lna_gain_g[] = {
+ {R_PATH0_LNA_ERR1, B_PATH0_LNA_ERR_G0_G_MSK},
+ {R_PATH0_LNA_ERR2, B_PATH0_LNA_ERR_G1_G_MSK},
+ {R_PATH0_LNA_ERR2, B_PATH0_LNA_ERR_G2_G_MSK},
+ {R_PATH0_LNA_ERR3, B_PATH0_LNA_ERR_G3_G_MSK},
+ {R_PATH0_LNA_ERR3, B_PATH0_LNA_ERR_G4_G_MSK},
+ {R_PATH0_LNA_ERR4, B_PATH0_LNA_ERR_G5_G_MSK},
+ {R_PATH0_LNA_ERR5, B_PATH0_LNA_ERR_G6_G_MSK},
+};
+
+DECLARE_DIG_TABLE(rtw89_8852a_lna_gain_g);
+
+static const struct rtw89_reg_def rtw89_8852a_tia_gain_g[] = {
+ {R_PATH0_TIA_ERR_G0, B_PATH0_TIA_ERR_G0_G_MSK},
+ {R_PATH0_TIA_ERR_G1, B_PATH0_TIA_ERR_G1_G_MSK},
+};
+
+DECLARE_DIG_TABLE(rtw89_8852a_tia_gain_g);
+
+static const struct rtw89_reg_def rtw89_8852a_lna_gain_a[] = {
+ {R_PATH0_LNA_ERR1, B_PATH0_LNA_ERR_G0_A_MSK},
+ {R_PATH0_LNA_ERR1, B_PATH0_LNA_ERR_G1_A_MSK},
+ {R_PATH0_LNA_ERR2, B_PATH0_LNA_ERR_G2_A_MSK},
+ {R_PATH0_LNA_ERR3, B_PATH0_LNA_ERR_G3_A_MSK},
+ {R_PATH0_LNA_ERR3, B_PATH0_LNA_ERR_G4_A_MSK},
+ {R_PATH0_LNA_ERR4, B_PATH0_LNA_ERR_G5_A_MSK},
+ {R_PATH0_LNA_ERR4, B_PATH0_LNA_ERR_G6_A_MSK},
+};
+
+DECLARE_DIG_TABLE(rtw89_8852a_lna_gain_a);
+
+static const struct rtw89_reg_def rtw89_8852a_tia_gain_a[] = {
+ {R_PATH0_TIA_ERR_G0, B_PATH0_TIA_ERR_G0_A_MSK},
+ {R_PATH0_TIA_ERR_G1, B_PATH0_TIA_ERR_G1_A_MSK},
+};
+
+DECLARE_DIG_TABLE(rtw89_8852a_tia_gain_a);
+
+static const struct rtw89_phy_dig_gain_table rtw89_8852a_phy_dig_table = {
+ .cfg_lna_g = &rtw89_8852a_lna_gain_g_table,
+ .cfg_tia_g = &rtw89_8852a_tia_gain_g_table,
+ .cfg_lna_a = &rtw89_8852a_lna_gain_a_table,
+ .cfg_tia_a = &rtw89_8852a_tia_gain_a_table
+};
+
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support rtw_wowlan_stub_8852a = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
@@ -2265,8 +2316,11 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.ops = &rtw8852a_chip_ops,
.mac_def = &rtw89_mac_gen_ax,
.phy_def = &rtw89_phy_gen_ax,
- .fw_basename = RTW8852A_FW_BASENAME,
- .fw_format_max = RTW8852A_FW_FORMAT_MAX,
+ .fw_def = {
+ .fw_basename = RTW8852A_FW_BASENAME,
+ .fw_format_max = RTW8852A_FW_FORMAT_MAX,
+ .fw_b_aid = 0,
+ },
.try_ce_fw = false,
.bbmcu_nr = 0,
.needed_fw_elms = 0,
@@ -2324,7 +2378,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.support_noise = true,
.ul_tb_waveform_ctrl = false,
.ul_tb_pwr_diff = false,
- .rx_freq_frome_ie = true,
+ .rx_freq_from_ie = true,
.hw_sec_hdr = false,
.hw_mgmt_tx_encrypt = false,
.hw_tkip_crypto = false,
@@ -2364,6 +2418,10 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.rf_para_ulink = rtw89_btc_8852a_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852a_rf_dl),
.rf_para_dlink = rtw89_btc_8852a_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852a_table.c
index 495890c180ef..ffdeb3801991 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a_table.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_table.c
@@ -50952,50 +50952,6 @@ const s8 rtw89_8852a_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM]
[2][1][RTW89_UK][46] = 32,
};
-#define DECLARE_DIG_TABLE(name) \
-static const struct rtw89_phy_dig_gain_cfg name##_table = { \
- .table = name, \
- .size = ARRAY_SIZE(name) \
-}
-
-static const struct rtw89_reg_def rtw89_8852a_lna_gain_g[] = {
- {R_PATH0_LNA_ERR1, B_PATH0_LNA_ERR_G0_G_MSK},
- {R_PATH0_LNA_ERR2, B_PATH0_LNA_ERR_G1_G_MSK},
- {R_PATH0_LNA_ERR2, B_PATH0_LNA_ERR_G2_G_MSK},
- {R_PATH0_LNA_ERR3, B_PATH0_LNA_ERR_G3_G_MSK},
- {R_PATH0_LNA_ERR3, B_PATH0_LNA_ERR_G4_G_MSK},
- {R_PATH0_LNA_ERR4, B_PATH0_LNA_ERR_G5_G_MSK},
- {R_PATH0_LNA_ERR5, B_PATH0_LNA_ERR_G6_G_MSK},
-};
-
-DECLARE_DIG_TABLE(rtw89_8852a_lna_gain_g);
-
-static const struct rtw89_reg_def rtw89_8852a_tia_gain_g[] = {
- {R_PATH0_TIA_ERR_G0, B_PATH0_TIA_ERR_G0_G_MSK},
- {R_PATH0_TIA_ERR_G1, B_PATH0_TIA_ERR_G1_G_MSK},
-};
-
-DECLARE_DIG_TABLE(rtw89_8852a_tia_gain_g);
-
-static const struct rtw89_reg_def rtw89_8852a_lna_gain_a[] = {
- {R_PATH0_LNA_ERR1, B_PATH0_LNA_ERR_G0_A_MSK},
- {R_PATH0_LNA_ERR1, B_PATH0_LNA_ERR_G1_A_MSK},
- {R_PATH0_LNA_ERR2, B_PATH0_LNA_ERR_G2_A_MSK},
- {R_PATH0_LNA_ERR3, B_PATH0_LNA_ERR_G3_A_MSK},
- {R_PATH0_LNA_ERR3, B_PATH0_LNA_ERR_G4_A_MSK},
- {R_PATH0_LNA_ERR4, B_PATH0_LNA_ERR_G5_A_MSK},
- {R_PATH0_LNA_ERR4, B_PATH0_LNA_ERR_G6_A_MSK},
-};
-
-DECLARE_DIG_TABLE(rtw89_8852a_lna_gain_a);
-
-static const struct rtw89_reg_def rtw89_8852a_tia_gain_a[] = {
- {R_PATH0_TIA_ERR_G0, B_PATH0_TIA_ERR_G0_A_MSK},
- {R_PATH0_TIA_ERR_G1, B_PATH0_TIA_ERR_G1_A_MSK},
-};
-
-DECLARE_DIG_TABLE(rtw89_8852a_tia_gain_a);
-
const struct rtw89_phy_table rtw89_8852a_phy_bb_table = {
.regs = rtw89_8852a_phy_bb_regs,
.n_regs = ARRAY_SIZE(rtw89_8852a_phy_bb_regs),
@@ -51042,13 +50998,6 @@ const struct rtw89_txpwr_track_cfg rtw89_8852a_trk_cfg = {
.delta_swingidx_2g_cck_a_p = _txpwr_track_delta_swingidx_2g_cck_a_p,
};
-const struct rtw89_phy_dig_gain_table rtw89_8852a_phy_dig_table = {
- .cfg_lna_g = &rtw89_8852a_lna_gain_g_table,
- .cfg_tia_g = &rtw89_8852a_tia_gain_g_table,
- .cfg_lna_a = &rtw89_8852a_lna_gain_a_table,
- .cfg_tia_a = &rtw89_8852a_tia_gain_a_table
-};
-
const struct rtw89_rfe_parms rtw89_8852a_dflt_parms = {
.byr_tbl = &rtw89_8852a_byr_table,
.rule_2ghz = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_table.h b/drivers/net/wireless/realtek/rtw89/rtw8852a_table.h
index 7463ae6ee3f9..58fe8575c1c9 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a_table.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_table.h
@@ -11,7 +11,6 @@ extern const struct rtw89_phy_table rtw89_8852a_phy_bb_table;
extern const struct rtw89_phy_table rtw89_8852a_phy_radioa_table;
extern const struct rtw89_phy_table rtw89_8852a_phy_radiob_table;
extern const struct rtw89_phy_table rtw89_8852a_phy_nctl_table;
-extern const struct rtw89_phy_dig_gain_table rtw89_8852a_phy_dig_table;
extern const struct rtw89_txpwr_track_cfg rtw89_8852a_trk_cfg;
extern const struct rtw89_rfe_parms rtw89_8852a_dflt_parms;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
index ccdbcc178c2a..4cced4619b7d 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
@@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852a_usb_info = {
.usb3_mac_npi_config_intf_0 = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
.usb_endpoint_0 = R_AX_USB_ENDPOINT_0,
.usb_endpoint_2 = R_AX_USB_ENDPOINT_2,
+ .rx_agg_alignment = 8,
.bulkout_id = {
[RTW89_DMA_ACH0] = 3,
[RTW89_DMA_ACH2] = 5,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index 197e3f5fb21b..5e8738bb2dc2 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -13,10 +13,10 @@
#include "rtw8852b_table.h"
#include "txrx.h"
-#define RTW8852B_FW_FORMAT_MAX 1
+#define RTW8852B_FW_FORMAT_MAX 2
#define RTW8852B_FW_BASENAME "rtw89/rtw8852b_fw"
#define RTW8852B_MODULE_FIRMWARE \
- RTW8852B_FW_BASENAME "-" __stringify(RTW8852B_FW_FORMAT_MAX) ".bin"
+ RTW89_GEN_MODULE_FWNAME(RTW8852B_FW_BASENAME, RTW8852B_FW_FORMAT_MAX)
static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_pcie[] = {
{5, 341, grp_0}, /* ACH 0 */
@@ -50,25 +50,25 @@ static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_pcie[] = {
};
static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_usb[] = {
- {18, 152, grp_0}, /* ACH 0 */
- {18, 152, grp_0}, /* ACH 1 */
- {18, 152, grp_0}, /* ACH 2 */
- {18, 152, grp_0}, /* ACH 3 */
+ {18, 210, grp_0}, /* ACH 0 */
+ {18, 210, grp_0}, /* ACH 1 */
+ {18, 210, grp_0}, /* ACH 2 */
+ {18, 210, grp_0}, /* ACH 3 */
{0, 0, grp_0}, /* ACH 4 */
{0, 0, grp_0}, /* ACH 5 */
{0, 0, grp_0}, /* ACH 6 */
{0, 0, grp_0}, /* ACH 7 */
- {18, 152, grp_0}, /* B0MGQ */
- {18, 152, grp_0}, /* B0HIQ */
+ {18, 210, grp_0}, /* B0MGQ */
+ {18, 210, grp_0}, /* B0HIQ */
{0, 0, grp_0}, /* B1MGQ */
{0, 0, grp_0}, /* B1HIQ */
{0, 0, 0} /* FWCMDQ */
};
static const struct rtw89_hfc_pub_cfg rtw8852b_hfc_pubcfg_usb = {
- 152, /* Group 0 */
+ 210, /* Group 0 */
0, /* Group 1 */
- 152, /* Public Max */
+ 210, /* Public Max */
0 /* WP threshold */
};
@@ -109,10 +109,10 @@ static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = {
};
static const struct rtw89_dle_mem rtw8852b_dle_mem_usb3[] = {
- [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25,
- &rtw89_mac_size.ple_size33, &rtw89_mac_size.wde_qt25,
- &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt74,
- &rtw89_mac_size.ple_qt75},
+ [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size30,
+ &rtw89_mac_size.ple_size31, &rtw89_mac_size.wde_qt30,
+ &rtw89_mac_size.wde_qt30, &rtw89_mac_size.ple_qt27,
+ &rtw89_mac_size.ple_qt28},
[RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9,
&rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4,
&rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13,
@@ -911,8 +911,11 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.ops = &rtw8852b_chip_ops,
.mac_def = &rtw89_mac_gen_ax,
.phy_def = &rtw89_phy_gen_ax,
- .fw_basename = RTW8852B_FW_BASENAME,
- .fw_format_max = RTW8852B_FW_FORMAT_MAX,
+ .fw_def = {
+ .fw_basename = RTW8852B_FW_BASENAME,
+ .fw_format_max = RTW8852B_FW_FORMAT_MAX,
+ .fw_b_aid = 0,
+ },
.try_ce_fw = true,
.bbmcu_nr = 0,
.needed_fw_elms = 0,
@@ -971,7 +974,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.support_noise = false,
.ul_tb_waveform_ctrl = true,
.ul_tb_pwr_diff = false,
- .rx_freq_frome_ie = true,
+ .rx_freq_from_ie = true,
.hw_sec_hdr = false,
.hw_mgmt_tx_encrypt = false,
.hw_tkip_crypto = false,
@@ -1011,6 +1014,10 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.rf_para_ulink = rtw89_btc_8852b_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852b_rf_dl),
.rf_para_dlink = rtw89_btc_8852b_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
index 92bbd6e5d699..ab4263bc8b9f 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
@@ -14,7 +14,7 @@
#define RTW8852BT_FW_FORMAT_MAX 0
#define RTW8852BT_FW_BASENAME "rtw89/rtw8852bt_fw"
#define RTW8852BT_MODULE_FIRMWARE \
- RTW8852BT_FW_BASENAME ".bin"
+ RTW89_GEN_MODULE_FWNAME(RTW8852BT_FW_BASENAME, RTW8852BT_FW_FORMAT_MAX)
static const struct rtw89_hfc_ch_cfg rtw8852bt_hfc_chcfg_pcie[] = {
{16, 742, grp_0}, /* ACH 0 */
@@ -757,8 +757,11 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
.ops = &rtw8852bt_chip_ops,
.mac_def = &rtw89_mac_gen_ax,
.phy_def = &rtw89_phy_gen_ax,
- .fw_basename = RTW8852BT_FW_BASENAME,
- .fw_format_max = RTW8852BT_FW_FORMAT_MAX,
+ .fw_def = {
+ .fw_basename = RTW8852BT_FW_BASENAME,
+ .fw_format_max = RTW8852BT_FW_FORMAT_MAX,
+ .fw_b_aid = 0,
+ },
.try_ce_fw = true,
.bbmcu_nr = 0,
.needed_fw_elms = RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_NO_6GHZ,
@@ -810,7 +813,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
.support_sar_by_ant = true,
.ul_tb_waveform_ctrl = true,
.ul_tb_pwr_diff = false,
- .rx_freq_frome_ie = true,
+ .rx_freq_from_ie = true,
.hw_sec_hdr = false,
.hw_mgmt_tx_encrypt = false,
.hw_tkip_crypto = true,
@@ -850,6 +853,10 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
.rf_para_ulink = rtw89_btc_8852bt_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852bt_rf_dl),
.rf_para_dlink = rtw89_btc_8852bt_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
index 84cd3ec971f9..37111fed276f 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
@@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852b_usb_info = {
.usb3_mac_npi_config_intf_0 = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
.usb_endpoint_0 = R_AX_USB_ENDPOINT_0,
.usb_endpoint_2 = R_AX_USB_ENDPOINT_2,
+ .rx_agg_alignment = 8,
.bulkout_id = {
[RTW89_DMA_ACH0] = 3,
[RTW89_DMA_ACH1] = 4,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index de5d343f80a5..40db7e3c0d97 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -18,7 +18,7 @@
#define RTW8852C_FW_FORMAT_MAX 2
#define RTW8852C_FW_BASENAME "rtw89/rtw8852c_fw"
#define RTW8852C_MODULE_FIRMWARE \
- RTW8852C_FW_BASENAME "-" __stringify(RTW8852C_FW_FORMAT_MAX) ".bin"
+ RTW89_GEN_MODULE_FWNAME(RTW8852C_FW_BASENAME, RTW8852C_FW_FORMAT_MAX)
static const struct rtw89_hfc_ch_cfg rtw8852c_hfc_chcfg_pcie[] = {
{13, 1614, grp_0}, /* ACH 0 */
@@ -463,7 +463,7 @@ static int rtw8852c_pwr_off_func(struct rtw89_dev *rtwdev)
else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB)
rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_EDSWR);
- rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_XTAL_OFF_A_DIE);
+ rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_XTAL_OFF_A_DIE);
rtw89_write32_set(rtwdev, R_AX_SYS_SWR_CTRL1, B_AX_SYM_CTRL_SPS_PWMFREQ);
rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0,
B_AX_REG_ZCDC_H_MASK, 0x3);
@@ -3106,8 +3106,11 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.ops = &rtw8852c_chip_ops,
.mac_def = &rtw89_mac_gen_ax,
.phy_def = &rtw89_phy_gen_ax,
- .fw_basename = RTW8852C_FW_BASENAME,
- .fw_format_max = RTW8852C_FW_FORMAT_MAX,
+ .fw_def = {
+ .fw_basename = RTW8852C_FW_BASENAME,
+ .fw_format_max = RTW8852C_FW_FORMAT_MAX,
+ .fw_b_aid = 0,
+ },
.try_ce_fw = false,
.bbmcu_nr = 0,
.needed_fw_elms = 0,
@@ -3168,7 +3171,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.support_noise = false,
.ul_tb_waveform_ctrl = false,
.ul_tb_pwr_diff = true,
- .rx_freq_frome_ie = false,
+ .rx_freq_from_ie = false,
.hw_sec_hdr = true,
.hw_mgmt_tx_encrypt = true,
.hw_tkip_crypto = true,
@@ -3208,6 +3211,10 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.rf_para_ulink = rtw89_btc_8852c_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852c_rf_dl),
.rf_para_dlink = rtw89_btc_8852c_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
index 3b9825c92a0d..092d2812a4d5 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
@@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852c_usb_info = {
.usb3_mac_npi_config_intf_0 = R_AX_USB3_MAC_NPI_CONFIG_INTF_0_V1,
.usb_endpoint_0 = R_AX_USB_ENDPOINT_0_V1,
.usb_endpoint_2 = R_AX_USB_ENDPOINT_2_V1,
+ .rx_agg_alignment = 8,
.bulkout_id = {
[RTW89_DMA_ACH0] = 3,
[RTW89_DMA_ACH2] = 5,
@@ -38,6 +39,10 @@ static const struct rtw89_driver_info rtw89_8852cu_info = {
};
static const struct usb_device_id rtw_8852cu_id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x03a6, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x056e, 0x4024, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xc832, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xc85a, 0xff, 0xff, 0xff),
@@ -54,6 +59,8 @@ static const struct usb_device_id rtw_8852cu_id_table[] = {
.driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
{ USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0102, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x37ad, 0x0103, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&rtw89_8852cu_info },
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8852cu_id_table);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index f41b66b362c4..8f6cf64271e8 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -18,7 +18,7 @@
#define RTW8922A_FW_FORMAT_MAX 4
#define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw"
#define RTW8922A_MODULE_FIRMWARE \
- RTW8922A_FW_BASENAME "-" __stringify(RTW8922A_FW_FORMAT_MAX) ".bin"
+ RTW89_GEN_MODULE_FWNAME(RTW8922A_FW_BASENAME, RTW8922A_FW_FORMAT_MAX)
#define HE_N_USER_MAX_8922A 4
@@ -492,7 +492,7 @@ static int rtw8922a_pwr_off_func(struct rtw89_dev *rtwdev)
return ret;
rtw89_write32(rtwdev, R_BE_WLLPS_CTRL, 0x0000A1B2);
- rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_XTAL_OFF_A_DIE);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_XTAL_OFF_A_DIE);
rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
rtw89_write32(rtwdev, R_BE_UDM1, 0);
@@ -2916,8 +2916,11 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
.ops = &rtw8922a_chip_ops,
.mac_def = &rtw89_mac_gen_be,
.phy_def = &rtw89_phy_gen_be,
- .fw_basename = RTW8922A_FW_BASENAME,
- .fw_format_max = RTW8922A_FW_FORMAT_MAX,
+ .fw_def = {
+ .fw_basename = RTW8922A_FW_BASENAME,
+ .fw_format_max = RTW8922A_FW_FORMAT_MAX,
+ .fw_b_aid = 0,
+ },
.try_ce_fw = false,
.bbmcu_nr = 1,
.needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS,
@@ -2972,7 +2975,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
.support_noise = false,
.ul_tb_waveform_ctrl = false,
.ul_tb_pwr_diff = false,
- .rx_freq_frome_ie = false,
+ .rx_freq_from_ie = false,
.hw_sec_hdr = true,
.hw_mgmt_tx_encrypt = true,
.hw_tkip_crypto = true,
@@ -3012,6 +3015,10 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
.rf_para_ulink = rtw89_btc_8922a_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8922a_rf_dl),
.rf_para_dlink = rtw89_btc_8922a_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
@@ -3057,6 +3064,7 @@ EXPORT_SYMBOL(rtw8922a_chip_info);
const struct rtw89_chip_variant rtw8922ae_vs_variant = {
.no_mcs_12_13 = true,
.fw_min_ver_code = RTW89_FW_VER_CODE(0, 35, 54, 0),
+ .fw_def_override = NULL,
};
EXPORT_SYMBOL(rtw8922ae_vs_variant);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
new file mode 100644
index 000000000000..e3b77cd23514
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -0,0 +1,3093 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#include "chan.h"
+#include "coex.h"
+#include "debug.h"
+#include "efuse.h"
+#include "mac.h"
+#include "phy.h"
+#include "reg.h"
+#include "rtw8922d.h"
+#include "rtw8922d_rfk.h"
+#include "sar.h"
+#include "util.h"
+
+#define RTW8922D_FW_FORMAT_MAX 0
+#define RTW8922D_FW_BASENAME "rtw89/rtw8922d_fw"
+#define RTW8922D_MODULE_FIRMWARE \
+ RTW89_GEN_MODULE_FWNAME(RTW8922D_FW_BASENAME, RTW8922D_FW_FORMAT_MAX)
+
+#define RTW8922DS_FW_FORMAT_MAX 0
+#define RTW8922DS_FW_BASENAME "rtw89/rtw8922ds_fw"
+#define RTW8922DS_MODULE_FIRMWARE \
+ RTW89_GEN_MODULE_FWNAME(RTW8922DS_FW_BASENAME, RTW8922DS_FW_FORMAT_MAX)
+
+static const struct rtw89_hfc_ch_cfg rtw8922d_hfc_chcfg_pcie[] = {
+ {2, 603, 0}, /* ACH 0 */
+ {0, 601, 0}, /* ACH 1 */
+ {2, 603, 0}, /* ACH 2 */
+ {0, 601, 0}, /* ACH 3 */
+ {2, 603, 0}, /* ACH 4 */
+ {0, 601, 0}, /* ACH 5 */
+ {2, 603, 0}, /* ACH 6 */
+ {0, 601, 0}, /* ACH 7 */
+ {2, 603, 0}, /* B0MGQ */
+ {0, 601, 0}, /* B0HIQ */
+ {2, 603, 0}, /* B1MGQ */
+ {0, 601, 0}, /* B1HIQ */
+ {0, 0, 0}, /* FWCMDQ */
+ {0, 0, 0}, /* BMC */
+ {0, 0, 0}, /* H2D */
+};
+
+static const struct rtw89_hfc_pub_cfg rtw8922d_hfc_pubcfg_pcie = {
+ 613, /* Group 0 */
+ 0, /* Group 1 */
+ 613, /* Public Max */
+ 0, /* WP threshold */
+};
+
+static const struct rtw89_hfc_param_ini rtw8922d_hfc_param_ini_pcie[] = {
+ [RTW89_QTA_SCC] = {rtw8922d_hfc_chcfg_pcie, &rtw8922d_hfc_pubcfg_pcie,
+ &rtw89_mac_size.hfc_prec_cfg_c0, RTW89_HCIFC_POH},
+ [RTW89_QTA_DBCC] = {rtw8922d_hfc_chcfg_pcie, &rtw8922d_hfc_pubcfg_pcie,
+ &rtw89_mac_size.hfc_prec_cfg_c0, RTW89_HCIFC_POH},
+ [RTW89_QTA_DLFW] = {NULL, NULL, &rtw89_mac_size.hfc_prec_cfg_c2,
+ RTW89_HCIFC_POH},
+ [RTW89_QTA_INVALID] = {NULL},
+};
+
+static const struct rtw89_dle_mem rtw8922d_dle_mem_pcie[] = {
+ [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size16_v1,
+ &rtw89_mac_size.ple_size20_v1, &rtw89_mac_size.wde_qt19_v1,
+ &rtw89_mac_size.wde_qt19_v1, &rtw89_mac_size.ple_qt42_v2,
+ &rtw89_mac_size.ple_qt43_v2, &rtw89_mac_size.ple_rsvd_qt9,
+ &rtw89_mac_size.rsvd0_size6, &rtw89_mac_size.rsvd1_size2,
+ &rtw89_mac_size.dle_input18},
+ [RTW89_QTA_DBCC] = {RTW89_QTA_DBCC, &rtw89_mac_size.wde_size16_v1,
+ &rtw89_mac_size.ple_size20_v1, &rtw89_mac_size.wde_qt19_v1,
+ &rtw89_mac_size.wde_qt19_v1, &rtw89_mac_size.ple_qt42_v2,
+ &rtw89_mac_size.ple_qt43_v2, &rtw89_mac_size.ple_rsvd_qt9,
+ &rtw89_mac_size.rsvd0_size6, &rtw89_mac_size.rsvd1_size2,
+ &rtw89_mac_size.dle_input18},
+ [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size18_v1,
+ &rtw89_mac_size.ple_size22_v1, &rtw89_mac_size.wde_qt3,
+ &rtw89_mac_size.wde_qt3, &rtw89_mac_size.ple_qt5_v2,
+ &rtw89_mac_size.ple_qt5_v2, &rtw89_mac_size.ple_rsvd_qt1,
+ &rtw89_mac_size.rsvd0_size6, &rtw89_mac_size.rsvd1_size2,
+ &rtw89_mac_size.dle_input3},
+ [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL,
+ NULL},
+};
+
+static const u32 rtw8922d_h2c_regs[RTW89_H2CREG_MAX] = {
+ R_BE_H2CREG_DATA0, R_BE_H2CREG_DATA1, R_BE_H2CREG_DATA2,
+ R_BE_H2CREG_DATA3
+};
+
+static const u32 rtw8922d_c2h_regs[RTW89_H2CREG_MAX] = {
+ R_BE_C2HREG_DATA0, R_BE_C2HREG_DATA1, R_BE_C2HREG_DATA2,
+ R_BE_C2HREG_DATA3
+};
+
+static const u32 rtw8922d_wow_wakeup_regs[RTW89_WOW_REASON_NUM] = {
+ R_BE_DBG_WOW, R_BE_DBG_WOW,
+};
+
+static const struct rtw89_page_regs rtw8922d_page_regs = {
+ .hci_fc_ctrl = R_BE_HCI_FC_CTRL,
+ .ch_page_ctrl = R_BE_CH_PAGE_CTRL,
+ .ach_page_ctrl = R_BE_CH0_PAGE_CTRL,
+ .ach_page_info = R_BE_CH0_PAGE_INFO,
+ .pub_page_info3 = R_BE_PUB_PAGE_INFO3,
+ .pub_page_ctrl1 = R_BE_PUB_PAGE_CTRL1,
+ .pub_page_ctrl2 = R_BE_PUB_PAGE_CTRL2,
+ .pub_page_info1 = R_BE_PUB_PAGE_INFO1,
+ .pub_page_info2 = R_BE_PUB_PAGE_INFO2,
+ .wp_page_ctrl1 = R_BE_WP_PAGE_CTRL1,
+ .wp_page_ctrl2 = R_BE_WP_PAGE_CTRL2,
+ .wp_page_info1 = R_BE_WP_PAGE_INFO1,
+};
+
+static const struct rtw89_reg_imr rtw8922d_imr_dmac_regs[] = {
+ {R_BE_HCI_BUF_IMR, B_BE_HCI_BUF_IMR_CLR, B_BE_HCI_BUF_IMR_SET},
+ {R_BE_DISP_HOST_IMR, B_BE_DISP_HOST_IMR_CLR_V1, B_BE_DISP_HOST_IMR_SET_V1},
+ {R_BE_DISP_CPU_IMR, B_BE_DISP_CPU_IMR_CLR_V1, B_BE_DISP_CPU_IMR_SET_V1},
+ {R_BE_DISP_OTHER_IMR, B_BE_DISP_OTHER_IMR_CLR_V1, B_BE_DISP_OTHER_IMR_SET_V1},
+ {R_BE_PKTIN_ERR_IMR, B_BE_PKTIN_ERR_IMR_CLR, B_BE_PKTIN_ERR_IMR_SET},
+ {R_BE_MLO_ERR_IDCT_IMR, B_BE_MLO_ERR_IDCT_IMR_CLR, B_BE_MLO_ERR_IDCT_IMR_SET},
+ {R_BE_MPDU_TX_ERR_IMR, B_BE_MPDU_TX_ERR_IMR_CLR, B_BE_MPDU_TX_ERR_IMR_SET},
+ {R_BE_MPDU_RX_ERR_IMR, B_BE_MPDU_RX_ERR_IMR_CLR, B_BE_MPDU_RX_ERR_IMR_SET},
+ {R_BE_SEC_ERROR_IMR, B_BE_SEC_ERROR_IMR_CLR, B_BE_SEC_ERROR_IMR_SET},
+ {R_BE_CPUIO_ERR_IMR, B_BE_CPUIO_ERR_IMR_CLR, B_BE_CPUIO_ERR_IMR_SET},
+ {R_BE_WDE_ERR_IMR, B_BE_WDE_ERR_IMR_CLR, B_BE_WDE_ERR_IMR_SET},
+ {R_BE_PLE_ERR_IMR, B_BE_PLE_ERR_IMR_CLR, B_BE_PLE_ERR_IMR_SET},
+ {R_BE_WDRLS_ERR_IMR, B_BE_WDRLS_ERR_IMR_CLR, B_BE_WDRLS_ERR_IMR_SET},
+ {R_BE_TXPKTCTL_B0_ERRFLAG_IMR, B_BE_TXPKTCTL_B0_ERRFLAG_IMR_CLR,
+ B_BE_TXPKTCTL_B0_ERRFLAG_IMR_SET},
+ {R_BE_TXPKTCTL_B1_ERRFLAG_IMR, B_BE_TXPKTCTL_B1_ERRFLAG_IMR_CLR,
+ B_BE_TXPKTCTL_B1_ERRFLAG_IMR_SET},
+ {R_BE_BBRPT_COM_ERR_IMR, B_BE_BBRPT_COM_ERR_IMR_CLR, B_BE_BBRPT_COM_ERR_IMR_SET},
+ {R_BE_BBRPT_CHINFO_ERR_IMR, B_BE_BBRPT_CHINFO_ERR_IMR_CLR,
+ B_BE_BBRPT_CHINFO_ERR_IMR_SET},
+ {R_BE_BBRPT_DFS_ERR_IMR, B_BE_BBRPT_DFS_ERR_IMR_CLR, B_BE_BBRPT_DFS_ERR_IMR_SET},
+ {R_BE_LA_ERRFLAG_IMR, B_BE_LA_ERRFLAG_IMR_CLR, B_BE_LA_ERRFLAG_IMR_SET},
+ {R_BE_CH_INFO_DBGFLAG_IMR, B_BE_CH_INFO_DBGFLAG_IMR_CLR, B_BE_CH_INFO_DBGFLAG_IMR_SET},
+ {R_BE_PLRLS_ERR_IMR_V1, B_BE_PLRLS_ERR_IMR_V1_CLR, B_BE_PLRLS_ERR_IMR_V1_SET},
+ {R_BE_HAXI_IDCT_MSK, B_BE_HAXI_IDCT_MSK_CLR, B_BE_HAXI_IDCT_MSK_SET},
+};
+
+static const struct rtw89_imr_table rtw8922d_imr_dmac_table = {
+ .regs = rtw8922d_imr_dmac_regs,
+ .n_regs = ARRAY_SIZE(rtw8922d_imr_dmac_regs),
+};
+
+static const struct rtw89_reg_imr rtw8922d_imr_cmac_regs[] = {
+ {R_BE_RESP_IMR, B_BE_RESP_IMR_CLR_V1, B_BE_RESP_IMR_SET_V1},
+ {R_BE_RESP_IMR1, B_BE_RESP_IMR1_CLR, B_BE_RESP_IMR1_SET},
+ {R_BE_RX_ERROR_FLAG_IMR, B_BE_RX_ERROR_FLAG_IMR_CLR_V1, B_BE_RX_ERROR_FLAG_IMR_SET_V1},
+ {R_BE_TX_ERROR_FLAG_IMR, B_BE_TX_ERROR_FLAG_IMR_CLR, B_BE_TX_ERROR_FLAG_IMR_SET},
+ {R_BE_RX_ERROR_FLAG_IMR_1, B_BE_TX_ERROR_FLAG_IMR_1_CLR, B_BE_TX_ERROR_FLAG_IMR_1_SET},
+ {R_BE_PTCL_IMR1, B_BE_PTCL_IMR1_CLR, B_BE_PTCL_IMR1_SET},
+ {R_BE_PTCL_IMR0, B_BE_PTCL_IMR0_CLR, B_BE_PTCL_IMR0_SET},
+ {R_BE_PTCL_IMR_2, B_BE_PTCL_IMR_2_CLR, B_BE_PTCL_IMR_2_SET},
+ {R_BE_SCHEDULE_ERR_IMR, B_BE_SCHEDULE_ERR_IMR_CLR, B_BE_SCHEDULE_ERR_IMR_SET},
+ {R_BE_C0_TXPWR_IMR, B_BE_C0_TXPWR_IMR_CLR, B_BE_C0_TXPWR_IMR_SET},
+ {R_BE_TRXPTCL_ERROR_INDICA_MASK, B_BE_TRXPTCL_ERROR_INDICA_MASK_CLR,
+ B_BE_TRXPTCL_ERROR_INDICA_MASK_SET},
+ {R_BE_RX_ERR_IMR, B_BE_RX_ERR_IMR_CLR, B_BE_RX_ERR_IMR_SET},
+ {R_BE_PHYINFO_ERR_IMR_V1, B_BE_PHYINFO_ERR_IMR_V1_CLR, B_BE_PHYINFO_ERR_IMR_V1_SET},
+};
+
+static const struct rtw89_imr_table rtw8922d_imr_cmac_table = {
+ .regs = rtw8922d_imr_cmac_regs,
+ .n_regs = ARRAY_SIZE(rtw8922d_imr_cmac_regs),
+};
+
+static const struct rtw89_rrsr_cfgs rtw8922d_rrsr_cfgs = {
+ .ref_rate = {R_BE_TRXPTCL_RESP_1, B_BE_WMAC_RESP_REF_RATE_SEL, 0},
+ .rsc = {R_BE_PTCL_RRSR1, B_BE_RSC_MASK, 2},
+};
+
+static const struct rtw89_rfkill_regs rtw8922d_rfkill_regs = {
+ .pinmux = {R_BE_GPIO8_15_FUNC_SEL,
+ B_BE_PINMUX_GPIO9_FUNC_SEL_MASK,
+ 0xf},
+ .mode = {R_BE_GPIO_EXT_CTRL + 2,
+ (B_BE_GPIO_MOD_9 | B_BE_GPIO_IO_SEL_9) >> 16,
+ 0x0},
+};
+
+static const struct rtw89_dig_regs rtw8922d_dig_regs = {
+ .seg0_pd_reg = R_SEG0R_PD_BE4,
+ .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK,
+ .pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1,
+ .bmode_pd_reg = R_BMODE_PDTH_EN_BE4,
+ .bmode_cca_rssi_limit_en = B_BMODE_PDTH_LIMIT_EN_MSK_V1,
+ .bmode_pd_lower_bound_reg = R_BMODE_PDTH_BE4,
+ .bmode_rssi_nocca_low_th_mask = B_BMODE_PDTH_LOWER_BOUND_MSK_V1,
+ .p0_lna_init = {R_PATH0_LNA_INIT_BE4, B_PATH0_LNA_INIT_IDX_BE4},
+ .p1_lna_init = {R_PATH1_LNA_INIT_BE4, B_PATH1_LNA_INIT_IDX_BE4},
+ .p0_tia_init = {R_PATH0_TIA_INIT_BE4, B_PATH0_TIA_INIT_IDX_BE4},
+ .p1_tia_init = {R_PATH1_TIA_INIT_BE4, B_PATH1_TIA_INIT_IDX_BE4},
+ .p0_rxb_init = {R_PATH0_RXIDX_INIT_BE4, B_PATH0_RXIDX_INIT_BE4},
+ .p1_rxb_init = {R_PATH1_RXIDX_INIT_BE4, B_PATH1_RXIDX_INIT_BE4},
+ .p0_p20_pagcugc_en = {R_PATH0_P20_FOLLOW_BY_PAGCUGC_BE4,
+ B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK},
+ .p0_s20_pagcugc_en = {R_PATH0_S20_FOLLOW_BY_PAGCUGC_BE4,
+ B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK},
+ .p1_p20_pagcugc_en = {R_PATH1_P20_FOLLOW_BY_PAGCUGC_BE4,
+ B_PATH1_P20_FOLLOW_BY_PAGCUGC_EN_MSK},
+ .p1_s20_pagcugc_en = {R_PATH1_S20_FOLLOW_BY_PAGCUGC_BE4,
+ B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK},
+};
+
+static const struct rtw89_edcca_regs rtw8922d_edcca_regs = {
+ .edcca_level = R_SEG0R_EDCCA_LVL_BE4,
+ .edcca_mask = B_EDCCA_LVL_MSK0,
+ .edcca_p_mask = B_EDCCA_LVL_MSK1,
+ .ppdu_level = R_SEG0R_PPDU_LVL_BE4,
+ .ppdu_mask = B_EDCCA_LVL_MSK1,
+ .p = {{
+ .rpt_a = R_EDCCA_RPT_A_BE4,
+ .rpt_b = R_EDCCA_RPT_B_BE4,
+ .rpt_sel = R_EDCCA_RPT_SEL_BE4,
+ .rpt_sel_mask = B_EDCCA_RPT_SEL_BE4_MSK,
+ }, {
+ .rpt_a = R_EDCCA_RPT_A_BE4_C1,
+ .rpt_b = R_EDCCA_RPT_A_BE4_C1,
+ .rpt_sel = R_EDCCA_RPT_SEL_BE4_C1,
+ .rpt_sel_mask = B_EDCCA_RPT_SEL_BE4_MSK,
+ }},
+ .rpt_sel_be = R_EDCCA_RPTREG_SEL_BE4,
+ .rpt_sel_be_mask = B_EDCCA_RPTREG_SEL_BE_MSK,
+ .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST_BE4,
+ .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_BE_M,
+};
+
+static const struct rtw89_efuse_block_cfg rtw8922d_efuse_blocks[] = {
+ [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310},
+ [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240},
+ [RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO] = {.offset = 0x20000, .size = 0x4800},
+ [RTW89_EFUSE_BLOCK_HCI_DIG_USB] = {.offset = 0x30000, .size = 0x890},
+ [RTW89_EFUSE_BLOCK_HCI_PHY_PCIE] = {.offset = 0x40000, .size = 0x400},
+ [RTW89_EFUSE_BLOCK_HCI_PHY_USB3] = {.offset = 0x50000, .size = 0x80},
+ [RTW89_EFUSE_BLOCK_HCI_PHY_USB2] = {.offset = 0x60000, .size = 0x50},
+ [RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10},
+};
+
+static void rtw8922d_sel_bt_rx_path(struct rtw89_dev *rtwdev, u8 val,
+ enum rtw89_rf_path rx_path)
+{
+ if (rx_path == RF_PATH_A)
+ rtw89_phy_write32_mask(rtwdev, R_SEL_GNT_BT_RX_BE4,
+ B_SEL_GNT_BT_RX_PATH0_BE4, val);
+ else if (rx_path == RF_PATH_B)
+ rtw89_phy_write32_mask(rtwdev, R_SEL_GNT_BT_RX_BE4,
+ B_SEL_GNT_BT_RX_PATH1_BE4, val);
+ else
+ rtw89_warn(rtwdev, "[%s] Not support path = %d\n", __func__, rx_path);
+}
+
+static void rtw8922d_sel_bt_rx_phy(struct rtw89_dev *rtwdev, u8 val,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_write32_idx(rtwdev, R_SEL_GNT_BT_RXPHY_BE4,
+ B_SEL_GNT_BT_RXPHY_BE4, val, phy_idx);
+}
+
+static void rtw8922d_set_gbt_bt_rx_sel(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_sel_bt_rx_path(rtwdev, 0x3, RF_PATH_A);
+ rtw8922d_sel_bt_rx_phy(rtwdev, 0x0, RTW89_PHY_0);
+ rtw8922d_sel_bt_rx_path(rtwdev, 0x3, RF_PATH_B);
+ rtw8922d_sel_bt_rx_phy(rtwdev, 0x0, RTW89_PHY_1);
+}
+
+static int rtw8922d_pwr_on_func(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 val32;
+ int ret;
+
+ if (hal->cid != RTL8922D_CID7025)
+ goto begin;
+
+ switch (hal->cv) {
+ case CHIP_CAV:
+ case CHIP_CBV:
+ rtw89_write32_set(rtwdev, R_BE_SPS_DIG_ON_CTRL1, B_BE_PWM_FORCE);
+ rtw89_write32_set(rtwdev, R_BE_SPS_ANA_ON_CTRL1, B_BE_PWM_FORCE_ANA);
+ break;
+ default:
+ break;
+ }
+
+begin:
+ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_AFSM_WLSUS_EN |
+ B_BE_AFSM_PCIE_SUS_EN);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_DIS_WLBT_PDNSUSEN_SOPC);
+ rtw89_write32_set(rtwdev, R_BE_WLLPS_CTRL, B_BE_DIS_WLBT_LPSEN_LOPC);
+ if (hal->cid != RTL8922D_CID7090)
+ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APDM_HPDN);
+ rtw89_write32_clr(rtwdev, R_BE_FWS1ISR, B_BE_FS_WL_HW_RADIO_OFF_INT);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
+
+ ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_RDY_SYSPWR,
+ 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
+ rtw89_write32_set(rtwdev, R_BE_WLRESUME_CTRL, B_BE_LPSROP_CMAC0 |
+ B_BE_LPSROP_CMAC1);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFN_ONMAC);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_APFN_ONMAC),
+ 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write8_set(rtwdev, R_BE_PLATFORM_ENABLE, B_BE_PLATFORM_EN);
+ rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN);
+
+ ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_HAXIDMA_IO_ST,
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HAXIDMA_BACKUP_RESTORE_ST),
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN);
+
+ ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_HCI_WLAN_IO_ST,
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_NORMAL_WRITE, 0x10, 0x10);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC1_1P3);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x40, 0x40);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC0_1P3);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x20, 0x20);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x04, 0x04);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x08, 0x08);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x10);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xEB, 0xFF);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xEB, 0xFF);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x01, 0x01);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x02, 0x02);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x80);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_XMD_2, 0, 0x70);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_SRAM_CTRL, 0, 0x02);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
+ rtw89_write32_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
+
+ mdelay(1);
+
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
+ rtw89_write32_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
+
+ 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 |
+ B_BE_LTR_CTL_EN);
+
+ set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags);
+
+ 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);
+
+ rtw89_write32_set(rtwdev, R_BE_CMAC_FUNC_EN,
+ B_BE_CMAC_EN | B_BE_CMAC_TXEN |
+ B_BE_CMAC_RXEN | B_BE_SIGB_EN |
+ B_BE_PHYINTF_EN | B_BE_CMAC_DMA_EN |
+ B_BE_PTCLTOP_EN | B_BE_SCHEDULER_EN |
+ B_BE_TMAC_EN | B_BE_RMAC_EN |
+ B_BE_TXTIME_EN | B_BE_RESP_PKTCTL_EN);
+
+ set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags);
+
+ rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE,
+ B_BE_FEN_BB_IP_RSTN | B_BE_FEN_BBPLAT_RSTB);
+
+ return 0;
+}
+
+static int rtw8922d_pwr_off_func(struct rtw89_dev *rtwdev)
+{
+ u32 val32;
+ int ret;
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x10, 0x10);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x08);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x04);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0, 0x01);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0, 0x01);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x80, 0x80);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x02);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x01);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
+ rtw89_write8_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN |
+ B_BE_FEN_BBPLAT_RSTB);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL,
+ B_BE_SYM_PADPDN_WL_RFC0_1P3);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x20);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL,
+ B_BE_SYM_PADPDN_WL_RFC1_1P3);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x40);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HAXIDMA_IO_ST),
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+ ret = read_poll_timeout(rtw89_read32, val32,
+ !(val32 & B_BE_HAXIDMA_BACKUP_RESTORE_ST),
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HCI_WLAN_IO_ST),
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_APFM_OFFMAC),
+ 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32(rtwdev, R_BE_WLLPS_CTRL, 0x00015002);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_XTAL_OFF_A_DIE);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
+ rtw89_write32(rtwdev, R_BE_UDM1, 0);
+
+ return 0;
+}
+
+static void rtw8922d_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
+ struct rtw8922d_efuse *map)
+{
+ const struct rtw8922d_tssi_offset_6g * const ofst_6g[] = {
+ &map->path_a_tssi_6g,
+ &map->path_b_tssi_6g,
+ };
+ const struct rtw8922d_tssi_offset * const ofst[] = {
+ &map->path_a_tssi,
+ &map->path_b_tssi,
+ };
+ struct rtw89_tssi_info *tssi = &rtwdev->tssi;
+ u8 i, j;
+
+ tssi->thermal[RF_PATH_A] = map->path_a_therm;
+ tssi->thermal[RF_PATH_B] = map->path_b_therm;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi, TSSI_CCK_CH_GROUP_NUM);
+
+ for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n",
+ i, j, tssi->tssi_cck[i][j]);
+
+ memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi,
+ TSSI_MCS_2G_CH_GROUP_NUM);
+ memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM,
+ ofst[i]->bw40_1s_tssi_5g, TSSI_MCS_5G_CH_GROUP_NUM);
+ memcpy(tssi->tssi_6g_mcs[i], ofst_6g[i]->bw40_1s_tssi_6g,
+ TSSI_MCS_6G_CH_GROUP_NUM);
+
+ for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n",
+ i, j, tssi->tssi_mcs[i][j]);
+
+ for (j = 0; j < TSSI_MCS_6G_CH_GROUP_NUM; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][EFUSE] path=%d mcs_6g[%d]=0x%x\n",
+ i, j, tssi->tssi_6g_mcs[i][j]);
+ }
+}
+
+static void
+__rtw8922d_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev,
+ s8 offset[RTW89_GAIN_OFFSET_NR],
+ const s8 *offset_default,
+ const struct rtw8922d_rx_gain *rx_gain,
+ const struct rtw8922d_rx_gain_6g *rx_gain_6g)
+{
+ int i;
+ u8 t;
+
+ offset[RTW89_GAIN_OFFSET_2G_CCK] = rx_gain->_2g_cck;
+ offset[RTW89_GAIN_OFFSET_2G_OFDM] = rx_gain->_2g_ofdm;
+ offset[RTW89_GAIN_OFFSET_5G_LOW] = rx_gain->_5g_low;
+ offset[RTW89_GAIN_OFFSET_5G_MID] = rx_gain->_5g_mid;
+ offset[RTW89_GAIN_OFFSET_5G_HIGH] = rx_gain->_5g_high;
+ offset[RTW89_GAIN_OFFSET_6G_L0] = rx_gain_6g->_6g_l0;
+ offset[RTW89_GAIN_OFFSET_6G_L1] = rx_gain_6g->_6g_l1;
+ offset[RTW89_GAIN_OFFSET_6G_M0] = rx_gain_6g->_6g_m0;
+ offset[RTW89_GAIN_OFFSET_6G_M1] = rx_gain_6g->_6g_m1;
+ offset[RTW89_GAIN_OFFSET_6G_H0] = rx_gain_6g->_6g_h0;
+ offset[RTW89_GAIN_OFFSET_6G_H1] = rx_gain_6g->_6g_h1;
+ offset[RTW89_GAIN_OFFSET_6G_UH0] = rx_gain_6g->_6g_uh0;
+ offset[RTW89_GAIN_OFFSET_6G_UH1] = rx_gain_6g->_6g_uh1;
+
+ for (i = 0; i < RTW89_GAIN_OFFSET_NR; i++) {
+ t = offset[i];
+ if (t == 0xff) {
+ if (offset_default) {
+ offset[i] = offset_default[i];
+ continue;
+ }
+ t = 0;
+ }
+
+ /* transform: sign-bit + U(7,2) to S(8,2) */
+ if (t & 0x80)
+ offset[i] = (t ^ 0x7f) + 1;
+ else
+ offset[i] = t;
+ }
+}
+
+static void rtw8922d_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev,
+ struct rtw8922d_efuse *map)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+
+ __rtw8922d_efuse_parsing_gain_offset(rtwdev, gain->offset[RF_PATH_A],
+ NULL,
+ &map->rx_gain_a, &map->rx_gain_6g_a);
+ __rtw8922d_efuse_parsing_gain_offset(rtwdev, gain->offset[RF_PATH_B],
+ NULL,
+ &map->rx_gain_b, &map->rx_gain_6g_b);
+
+ __rtw8922d_efuse_parsing_gain_offset(rtwdev, gain->offset2[RF_PATH_A],
+ gain->offset[RF_PATH_A],
+ &map->rx_gain_a_2, &map->rx_gain_6g_a_2);
+ __rtw8922d_efuse_parsing_gain_offset(rtwdev, gain->offset2[RF_PATH_B],
+ gain->offset[RF_PATH_B],
+ &map->rx_gain_b_2, &map->rx_gain_6g_b_2);
+
+ gain->offset_valid = true;
+}
+
+static int rtw8922d_read_efuse_pci_sdio(struct rtw89_dev *rtwdev, u8 *log_map)
+{
+ struct rtw89_efuse *efuse = &rtwdev->efuse;
+
+ if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE)
+ ether_addr_copy(efuse->addr, log_map + 0x4104);
+ else
+ ether_addr_copy(efuse->addr, log_map + 0x001A);
+
+ return 0;
+}
+
+static int rtw8922d_read_efuse_usb(struct rtw89_dev *rtwdev, u8 *log_map)
+{
+ struct rtw89_efuse *efuse = &rtwdev->efuse;
+
+ ether_addr_copy(efuse->addr, log_map + 0x0078);
+
+ return 0;
+}
+
+static int rtw8922d_read_efuse_rf(struct rtw89_dev *rtwdev, u8 *log_map)
+{
+ struct rtw8922d_efuse *map = (struct rtw8922d_efuse *)log_map;
+ struct rtw89_efuse *efuse = &rtwdev->efuse;
+
+ efuse->rfe_type = map->rfe_type;
+ efuse->xtal_cap = map->xtal_k;
+ efuse->country_code[0] = map->country_code[0];
+ efuse->country_code[1] = map->country_code[1];
+ efuse->bt_setting_2 = map->bt_setting_2;
+ efuse->bt_setting_3 = map->bt_setting_3;
+ rtw8922d_efuse_parsing_tssi(rtwdev, map);
+ rtw8922d_efuse_parsing_gain_offset(rtwdev, map);
+
+ return 0;
+}
+
+static int rtw8922d_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
+ enum rtw89_efuse_block block)
+{
+ switch (block) {
+ case RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO:
+ return rtw8922d_read_efuse_pci_sdio(rtwdev, log_map);
+ case RTW89_EFUSE_BLOCK_HCI_DIG_USB:
+ return rtw8922d_read_efuse_usb(rtwdev, log_map);
+ case RTW89_EFUSE_BLOCK_RF:
+ return rtw8922d_read_efuse_rf(rtwdev, log_map);
+ default:
+ return 0;
+ }
+}
+
+static void rtw8922d_phycap_parsing_vco_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 vco_trim_addr[RF_PATH_NUM_8922D] = {0x175E, 0x175F};
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ const u32 vco_check_addr = 0x1700;
+ u8 val;
+
+ val = phycap_map[vco_check_addr - addr];
+ if (val & BIT(1))
+ return;
+
+ info->pg_vco_trim = true;
+
+ info->vco_trim[0] = u8_get_bits(phycap_map[vco_trim_addr[0] - addr], GENMASK(4, 0));
+ info->vco_trim[1] = u8_get_bits(phycap_map[vco_trim_addr[1] - addr], GENMASK(4, 0));
+}
+
+static void rtw8922d_vco_trim(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+
+ if (!info->pg_vco_trim)
+ return;
+
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_VCO, RR_VCO_VAL, info->vco_trim[0]);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_VCO, RR_VCO_VAL, info->vco_trim[1]);
+}
+
+#define THM_TRIM_POSITIVE_MASK BIT(6)
+#define THM_TRIM_MAGNITUDE_MASK GENMASK(5, 0)
+#define THM_TRIM_MAX (15)
+#define THM_TRIM_MIN (-15)
+
+static void rtw8922d_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 thm_trim_addr[RF_PATH_NUM_8922D] = {0x1706, 0x1732};
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ bool pg = true;
+ u8 pg_th;
+ s8 val;
+ u8 i;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ pg_th = phycap_map[thm_trim_addr[i] - addr];
+ if (pg_th == 0xff) {
+ memset(info->thermal_trim, 0, sizeof(info->thermal_trim));
+ pg = false;
+ goto out;
+ }
+
+ val = u8_get_bits(pg_th, THM_TRIM_MAGNITUDE_MASK);
+
+ if (!(pg_th & THM_TRIM_POSITIVE_MASK))
+ val *= -1;
+
+ if (val <= THM_TRIM_MIN || val >= THM_TRIM_MAX) {
+ val = 0;
+ info->thermal_trim[i] = 0;
+ } else {
+ info->thermal_trim[i] = pg_th;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[THERMAL][TRIM] path=%d thermal_trim=0x%x (%d)\n",
+ i, pg_th, val);
+ }
+
+out:
+ info->pg_thermal_trim = pg;
+}
+
+static void rtw8922d_thermal_trim(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u8 thermal;
+ int i;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ thermal = info->pg_thermal_trim ? info->thermal_trim[i] : 0;
+ rtw89_write_rf(rtwdev, i, RR_TM, RR_TM_TRM, thermal & 0x7f);
+ }
+}
+
+static void rtw8922d_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 pabias_trim_addr[RF_PATH_NUM_8922D] = {0x1707, 0x1733};
+ static const u32 check_pa_pad_trim_addr = 0x1700;
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ bool pg = true;
+ u8 val;
+ u8 i;
+
+ val = phycap_map[check_pa_pad_trim_addr - addr];
+ if (val == 0xff) {
+ pg = false;
+ goto out;
+ }
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr];
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n",
+ i, info->pa_bias_trim[i]);
+ }
+
+out:
+ info->pg_pa_bias_trim = pg;
+}
+
+static void rtw8922d_pa_bias_trim(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u8 pabias_2g, pabias_5g;
+ u8 i;
+
+ if (!info->pg_pa_bias_trim) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PA_BIAS][TRIM] no PG, do nothing\n");
+
+ return;
+ }
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ pabias_2g = FIELD_GET(GENMASK(3, 0), info->pa_bias_trim[i]);
+ pabias_5g = FIELD_GET(GENMASK(7, 4), info->pa_bias_trim[i]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n",
+ i, pabias_2g, pabias_5g);
+
+ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG_V1, pabias_2g);
+ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA_V1, pabias_5g);
+ }
+}
+
+static void rtw8922d_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 pad_bias_trim_addr[RF_PATH_NUM_8922D] = {0x1708, 0x1734};
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ u8 i;
+
+ if (!info->pg_pa_bias_trim)
+ return;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ info->pad_bias_trim[i] = phycap_map[pad_bias_trim_addr[i] - addr];
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PAD_BIAS][TRIM] path=%d pad_bias_trim=0x%x\n",
+ i, info->pad_bias_trim[i]);
+ }
+}
+
+static void rtw8922d_pad_bias_trim(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u8 pad_bias_2g, pad_bias_5g;
+ u8 i;
+
+ if (!info->pg_pa_bias_trim) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PAD_BIAS][TRIM] no PG, do nothing\n");
+ return;
+ }
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ pad_bias_2g = u8_get_bits(info->pad_bias_trim[i], GENMASK(3, 0));
+ pad_bias_5g = u8_get_bits(info->pad_bias_trim[i], GENMASK(7, 4));
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PAD_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n",
+ i, pad_bias_2g, pad_bias_5g);
+
+ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASD_TXG_V1, pad_bias_2g);
+ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASD_TXA_V1, pad_bias_5g);
+ }
+}
+
+static int rtw8922d_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map)
+{
+ rtw8922d_phycap_parsing_vco_trim(rtwdev, phycap_map);
+ rtw8922d_phycap_parsing_thermal_trim(rtwdev, phycap_map);
+ rtw8922d_phycap_parsing_pa_bias_trim(rtwdev, phycap_map);
+ rtw8922d_phycap_parsing_pad_bias_trim(rtwdev, phycap_map);
+
+ return 0;
+}
+
+static void rtw8922d_power_trim(struct rtw89_dev *rtwdev)
+{
+ rtw8922d_vco_trim(rtwdev);
+ rtw8922d_thermal_trim(rtwdev);
+ rtw8922d_pa_bias_trim(rtwdev);
+ rtw8922d_pad_bias_trim(rtwdev);
+}
+
+static void rtw8922d_set_channel_mac(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ u8 mac_idx)
+{
+ u32 sub_carr = rtw89_mac_reg_by_idx(rtwdev, R_BE_TX_SUB_BAND_VALUE, mac_idx);
+ u32 chk_rate = rtw89_mac_reg_by_idx(rtwdev, R_BE_TXRATE_CHK, mac_idx);
+ u32 rf_mod = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_RFMOD, mac_idx);
+ u8 txsb20 = 0, txsb40 = 0, txsb80 = 0;
+ u8 rf_mod_val, chk_rate_mask, sifs;
+ u32 txsb;
+ u32 reg;
+
+ switch (chan->band_width) {
+ case RTW89_CHANNEL_WIDTH_160:
+ txsb80 = rtw89_phy_get_txsb(rtwdev, chan, RTW89_CHANNEL_WIDTH_80);
+ fallthrough;
+ case RTW89_CHANNEL_WIDTH_80:
+ txsb40 = rtw89_phy_get_txsb(rtwdev, chan, RTW89_CHANNEL_WIDTH_40);
+ fallthrough;
+ case RTW89_CHANNEL_WIDTH_40:
+ txsb20 = rtw89_phy_get_txsb(rtwdev, chan, RTW89_CHANNEL_WIDTH_20);
+ break;
+ default:
+ break;
+ }
+
+ switch (chan->band_width) {
+ case RTW89_CHANNEL_WIDTH_160:
+ rf_mod_val = BE_WMAC_RFMOD_160M;
+ txsb = u32_encode_bits(txsb20, B_BE_TXSB_20M_MASK) |
+ u32_encode_bits(txsb40, B_BE_TXSB_40M_MASK) |
+ u32_encode_bits(txsb80, B_BE_TXSB_80M_MASK);
+ break;
+ case RTW89_CHANNEL_WIDTH_80:
+ rf_mod_val = BE_WMAC_RFMOD_80M;
+ txsb = u32_encode_bits(txsb20, B_BE_TXSB_20M_MASK) |
+ u32_encode_bits(txsb40, B_BE_TXSB_40M_MASK);
+ break;
+ case RTW89_CHANNEL_WIDTH_40:
+ rf_mod_val = BE_WMAC_RFMOD_40M;
+ txsb = u32_encode_bits(txsb20, B_BE_TXSB_20M_MASK);
+ break;
+ case RTW89_CHANNEL_WIDTH_20:
+ default:
+ rf_mod_val = BE_WMAC_RFMOD_20M;
+ txsb = 0;
+ break;
+ }
+
+ if (txsb20 <= BE_PRI20_BITMAP_MAX)
+ txsb |= u32_encode_bits(BIT(txsb20), B_BE_PRI20_BITMAP_MASK);
+
+ rtw89_write8_mask(rtwdev, rf_mod, B_BE_WMAC_RFMOD_MASK, rf_mod_val);
+ rtw89_write32(rtwdev, sub_carr, txsb);
+
+ switch (chan->band_type) {
+ case RTW89_BAND_2G:
+ chk_rate_mask = B_BE_BAND_MODE;
+ break;
+ case RTW89_BAND_5G:
+ case RTW89_BAND_6G:
+ chk_rate_mask = B_BE_CHECK_CCK_EN | B_BE_RTS_LIMIT_IN_OFDM6;
+ break;
+ default:
+ rtw89_warn(rtwdev, "Invalid band_type:%d\n", chan->band_type);
+ return;
+ }
+
+ rtw89_write8_clr(rtwdev, chk_rate, B_BE_BAND_MODE | B_BE_CHECK_CCK_EN |
+ B_BE_RTS_LIMIT_IN_OFDM6);
+ rtw89_write8_set(rtwdev, chk_rate, chk_rate_mask);
+
+ switch (chan->band_width) {
+ case RTW89_CHANNEL_WIDTH_160:
+ sifs = 0x8C;
+ break;
+ case RTW89_CHANNEL_WIDTH_80:
+ sifs = 0x8A;
+ break;
+ case RTW89_CHANNEL_WIDTH_40:
+ sifs = 0x84;
+ break;
+ case RTW89_CHANNEL_WIDTH_20:
+ default:
+ sifs = 0x82;
+ }
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_MUEDCA_EN, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_SIFS_MACTXEN_TB_T1_DOT05US_MASK, sifs);
+}
+
+static const u32 rtw8922d_sco_barker_threshold[14] = {
+ 0x1fe4f, 0x1ff5e, 0x2006c, 0x2017b, 0x2028a, 0x20399, 0x204a8, 0x205b6,
+ 0x206c5, 0x207d4, 0x208e3, 0x209f2, 0x20b00, 0x20d8a
+};
+
+static const u32 rtw8922d_sco_cck_threshold[14] = {
+ 0x2bdac, 0x2bf21, 0x2c095, 0x2c209, 0x2c37e, 0x2c4f2, 0x2c666, 0x2c7db,
+ 0x2c94f, 0x2cac3, 0x2cc38, 0x2cdac, 0x2cf21, 0x2d29e
+};
+
+static int rtw8922d_ctrl_sco_cck(struct rtw89_dev *rtwdev,
+ u8 primary_ch, enum rtw89_bandwidth bw,
+ enum rtw89_phy_idx phy_idx)
+{
+ u8 ch_element;
+
+ if (primary_ch >= 14)
+ return -EINVAL;
+
+ ch_element = primary_ch - 1;
+
+ rtw89_phy_write32_idx(rtwdev, R_BK_FC0_INV_BE4, B_BK_FC0_INV_BE4,
+ rtw8922d_sco_barker_threshold[ch_element],
+ phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_CCK_FC0_INV_BE4, B_CCK_FC0_INV_BE4,
+ rtw8922d_sco_cck_threshold[ch_element],
+ phy_idx);
+
+ return 0;
+}
+
+static void rtw8922d_ctrl_ch_core(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ u16 central_freq = chan->freq;
+ u16 sco;
+
+ if (chan->band_type == RTW89_BAND_2G) {
+ rtw89_phy_write32_idx(rtwdev, R_BAND_SEL0_BE4, B_BAND_SEL0_BE4,
+ 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BAND_SEL1_BE4, B_BAND_SEL1_BE4,
+ 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_ENABLE_CCK0_BE4, B_ENABLE_CCK0_BE4,
+ 1, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, R_BAND_SEL0_BE4, B_BAND_SEL0_BE4,
+ 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BAND_SEL1_BE4, B_BAND_SEL1_BE4,
+ 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_ENABLE_CCK0_BE4, B_ENABLE_CCK0_BE4,
+ 0, phy_idx);
+ }
+
+ rtw89_phy_write32_idx(rtwdev, R_FC0_BE4, B_FC0_BE4, central_freq, phy_idx);
+
+ sco = phy_div((BIT(0) << 27) + (central_freq / 2), central_freq);
+ rtw89_phy_write32_idx(rtwdev, R_FC0_INV_BE4, B_FC0_INV_BE4, sco, phy_idx);
+}
+
+struct rtw8922d_bb_gain {
+ u32 gain_g[BB_PATH_NUM_8922D];
+ u32 gain_a[BB_PATH_NUM_8922D];
+ u32 gain_g_mask;
+ u32 gain_a_mask;
+};
+
+static const struct rtw89_reg_def rpl_comp_bw160[RTW89_BW20_SC_160M] = {
+ { .addr = 0x241E8, .mask = 0xFF00},
+ { .addr = 0x241E8, .mask = 0xFF0000},
+ { .addr = 0x241E8, .mask = 0xFF000000},
+ { .addr = 0x241EC, .mask = 0xFF},
+ { .addr = 0x241EC, .mask = 0xFF00},
+ { .addr = 0x241EC, .mask = 0xFF0000},
+ { .addr = 0x241EC, .mask = 0xFF000000},
+ { .addr = 0x241F0, .mask = 0xFF}
+};
+
+static const struct rtw89_reg_def rpl_comp_bw80[RTW89_BW20_SC_80M] = {
+ { .addr = 0x241F4, .mask = 0xFF},
+ { .addr = 0x241F4, .mask = 0xFF00},
+ { .addr = 0x241F4, .mask = 0xFF0000},
+ { .addr = 0x241F4, .mask = 0xFF000000}
+};
+
+static const struct rtw89_reg_def rpl_comp_bw40[RTW89_BW20_SC_40M] = {
+ { .addr = 0x241F0, .mask = 0xFF0000},
+ { .addr = 0x241F0, .mask = 0xFF000000}
+};
+
+static const struct rtw89_reg_def rpl_comp_bw20[RTW89_BW20_SC_20M] = {
+ { .addr = 0x241F0, .mask = 0xFF00}
+};
+
+static const struct rtw8922d_bb_gain bb_gain_lna[LNA_GAIN_NUM] = {
+ { .gain_g = {0x2409C, 0x2449C}, .gain_a = {0x2406C, 0x2446C},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF},
+ { .gain_g = {0x2409C, 0x2449C}, .gain_a = {0x2406C, 0x2446C},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000},
+ { .gain_g = {0x240A0, 0x244A0}, .gain_a = {0x24070, 0x24470},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF},
+ { .gain_g = {0x240A0, 0x244A0}, .gain_a = {0x24070, 0x24470},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000},
+ { .gain_g = {0x240A4, 0x244A4}, .gain_a = {0x24074, 0x24474},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF},
+ { .gain_g = {0x240A4, 0x244A4}, .gain_a = {0x24074, 0x24474},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000},
+ { .gain_g = {0x240A8, 0x244A8}, .gain_a = {0x24078, 0x24478},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF},
+};
+
+static const struct rtw8922d_bb_gain bb_gain_tia[TIA_GAIN_NUM] = {
+ { .gain_g = {0x24054, 0x24454}, .gain_a = {0x24054, 0x24454},
+ .gain_g_mask = 0x7FC0000, .gain_a_mask = 0x1FF},
+ { .gain_g = {0x24058, 0x24458}, .gain_a = {0x24054, 0x24454},
+ .gain_g_mask = 0x1FF, .gain_a_mask = 0x3FE00 },
+};
+
+static const struct rtw8922d_bb_gain bb_op1db_lna[LNA_GAIN_NUM] = {
+ { .gain_g = {0x240AC, 0x244AC}, .gain_a = {0x24078, 0x24478},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF000000},
+ { .gain_g = {0x240AC, 0x244AC}, .gain_a = {0x2407C, 0x2447C},
+ .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF},
+ { .gain_g = {0x240AC, 0x244AC}, .gain_a = {0x2407C, 0x2447C},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF00},
+ { .gain_g = {0x240B0, 0x244B0}, .gain_a = {0x2407C, 0x2447C},
+ .gain_g_mask = 0xFF, .gain_a_mask = 0xFF0000},
+ { .gain_g = {0x240B0, 0x244B0}, .gain_a = {0x2407C, 0x2447C},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF000000},
+ { .gain_g = {0x240B0, 0x244B0}, .gain_a = {0x24080, 0x24480},
+ .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF},
+ { .gain_g = {0x240B0, 0x244B0}, .gain_a = {0x24080, 0x24480},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF00},
+};
+
+static const struct rtw8922d_bb_gain bb_op1db_tia_lna[TIA_LNA_OP1DB_NUM] = {
+ { .gain_g = {0x240B4, 0x244B4}, .gain_a = {0x24080, 0x24480},
+ .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF000000},
+ { .gain_g = {0x240B4, 0x244B4}, .gain_a = {0x24084, 0x24484},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF},
+ { .gain_g = {0x240B8, 0x244B8}, .gain_a = {0x24084, 0x24484},
+ .gain_g_mask = 0xFF, .gain_a_mask = 0xFF00},
+ { .gain_g = {0x240B8, 0x244B8}, .gain_a = {0x24084, 0x24484},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF0000},
+ { .gain_g = {0x240B8, 0x244B8}, .gain_a = {0x24084, 0x24484},
+ .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF000000},
+ { .gain_g = {0x240B8, 0x244B8}, .gain_a = {0x24088, 0x24488},
+ .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF},
+ { .gain_g = {0x240BC, 0x244BC}, .gain_a = {0x24088, 0x24488},
+ .gain_g_mask = 0xFF, .gain_a_mask = 0xFF00},
+ { .gain_g = {0x240BC, 0x244BC}, .gain_a = {0x24088, 0x24488},
+ .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF0000},
+};
+
+static void rtw8922d_set_rpl_gain(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be;
+ u8 gain_band = rtw89_subband_to_gain_band_be(chan->subband_type);
+ u32 reg_path_ofst = 0;
+ u32 mask;
+ s32 val;
+ u32 reg;
+ int i;
+
+ if (path == RF_PATH_B)
+ reg_path_ofst = 0x400;
+
+ for (i = 0; i < RTW89_BW20_SC_160M; i++) {
+ reg = rpl_comp_bw160[i].addr | reg_path_ofst;
+ mask = rpl_comp_bw160[i].mask;
+ val = gain->rpl_ofst_160[gain_band][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+
+ for (i = 0; i < RTW89_BW20_SC_80M; i++) {
+ reg = rpl_comp_bw80[i].addr | reg_path_ofst;
+ mask = rpl_comp_bw80[i].mask;
+ val = gain->rpl_ofst_80[gain_band][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+
+ for (i = 0; i < RTW89_BW20_SC_40M; i++) {
+ reg = rpl_comp_bw40[i].addr | reg_path_ofst;
+ mask = rpl_comp_bw40[i].mask;
+ val = gain->rpl_ofst_40[gain_band][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+
+ for (i = 0; i < RTW89_BW20_SC_20M; i++) {
+ reg = rpl_comp_bw20[i].addr | reg_path_ofst;
+ mask = rpl_comp_bw20[i].mask;
+ val = gain->rpl_ofst_20[gain_band][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+}
+
+static void rtw8922d_set_lna_tia_gain(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be;
+ u8 gain_band = rtw89_subband_to_gain_band_be(chan->subband_type);
+ enum rtw89_phy_bb_bw_be bw_type;
+ u32 mask;
+ s32 val;
+ u32 reg;
+ int i;
+
+ bw_type = chan->band_width <= RTW89_CHANNEL_WIDTH_40 ?
+ RTW89_BB_BW_20_40 : RTW89_BB_BW_80_160_320;
+
+ for (i = 0; i < LNA_GAIN_NUM; i++) {
+ if (chan->band_type == RTW89_BAND_2G) {
+ reg = bb_gain_lna[i].gain_g[path];
+ mask = bb_gain_lna[i].gain_g_mask;
+ } else {
+ reg = bb_gain_lna[i].gain_a[path];
+ mask = bb_gain_lna[i].gain_a_mask;
+ }
+ val = gain->lna_gain[gain_band][bw_type][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+
+ for (i = 0; i < TIA_GAIN_NUM; i++) {
+ if (chan->band_type == RTW89_BAND_2G) {
+ reg = bb_gain_tia[i].gain_g[path];
+ mask = bb_gain_tia[i].gain_g_mask;
+ } else {
+ reg = bb_gain_tia[i].gain_a[path];
+ mask = bb_gain_tia[i].gain_a_mask;
+ }
+ val = gain->tia_gain[gain_band][bw_type][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+}
+
+static void rtw8922d_set_op1db(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be;
+ u8 gain_band = rtw89_subband_to_gain_band_be(chan->subband_type);
+ enum rtw89_phy_bb_bw_be bw_type;
+ u32 mask;
+ s32 val;
+ u32 reg;
+ int i;
+
+ bw_type = chan->band_width <= RTW89_CHANNEL_WIDTH_40 ?
+ RTW89_BB_BW_20_40 : RTW89_BB_BW_80_160_320;
+
+ for (i = 0; i < LNA_GAIN_NUM; i++) {
+ if (chan->band_type == RTW89_BAND_2G) {
+ reg = bb_op1db_lna[i].gain_g[path];
+ mask = bb_op1db_lna[i].gain_g_mask;
+ } else {
+ reg = bb_op1db_lna[i].gain_a[path];
+ mask = bb_op1db_lna[i].gain_a_mask;
+ }
+ val = gain->lna_op1db[gain_band][bw_type][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+
+ for (i = 0; i < TIA_LNA_OP1DB_NUM; i++) {
+ if (chan->band_type == RTW89_BAND_2G) {
+ reg = bb_op1db_tia_lna[i].gain_g[path];
+ mask = bb_op1db_tia_lna[i].gain_g_mask;
+ } else {
+ reg = bb_op1db_tia_lna[i].gain_a[path];
+ mask = bb_op1db_tia_lna[i].gain_a_mask;
+ }
+ val = gain->tia_lna_op1db[gain_band][bw_type][path][i];
+ rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx);
+ }
+}
+
+static void rtw8922d_set_gain(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_set_rpl_gain(rtwdev, chan, path, phy_idx);
+ rtw8922d_set_lna_tia_gain(rtwdev, chan, path, phy_idx);
+ rtw8922d_set_op1db(rtwdev, chan, path, phy_idx);
+}
+
+static s8 rtw8922d_get_rx_gain_by_chan(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path, bool is_cck)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+ enum rtw89_gain_offset band;
+ u8 fc_ch = chan->channel;
+ s8 normal_efuse = 0;
+
+ if (path > RF_PATH_B)
+ return 0;
+
+ if (is_cck) {
+ if (fc_ch >= 1 && fc_ch <= 7)
+ return gain->offset[path][RTW89_GAIN_OFFSET_2G_CCK];
+ else if (fc_ch >= 8 && fc_ch <= 14)
+ return gain->offset2[path][RTW89_GAIN_OFFSET_2G_CCK];
+
+ return 0;
+ }
+
+ band = rtw89_subband_to_gain_offset_band_of_ofdm(chan->subband_type);
+
+ if (band == RTW89_GAIN_OFFSET_2G_OFDM) {
+ if (fc_ch >= 1 && fc_ch <= 7)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 8 && fc_ch <= 14)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_5G_LOW) {
+ if (fc_ch == 50)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 36 && fc_ch <= 48)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 52 && fc_ch <= 64)
+ normal_efuse = gain->offset2[path][band];
+
+ } else if (band == RTW89_GAIN_OFFSET_5G_MID) {
+ if (fc_ch == 122)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 100 && fc_ch <= 120)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 124 && fc_ch <= 144)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_5G_HIGH) {
+ if (fc_ch == 163)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 149 && fc_ch <= 161)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 165 && fc_ch <= 177)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_6G_L0) {
+ if (fc_ch == 15)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 1 && fc_ch <= 13)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 17 && fc_ch <= 29)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_6G_L1) {
+ if (fc_ch == 47)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 33 && fc_ch <= 45)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 49 && fc_ch <= 61)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_6G_M0) {
+ if (fc_ch == 79)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 65 && fc_ch <= 77)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 81 && fc_ch <= 93)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_6G_M1) {
+ if (fc_ch == 111)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 97 && fc_ch <= 109)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 113 && fc_ch <= 125)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_6G_H0) {
+ if (fc_ch == 143)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 129 && fc_ch <= 141)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 145 && fc_ch <= 157)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_6G_H1) {
+ if (fc_ch == 175)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 161 && fc_ch <= 173)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 177 && fc_ch <= 189)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_6G_UH0) {
+ if (fc_ch == 207)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 193 && fc_ch <= 205)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 209 && fc_ch <= 221)
+ normal_efuse = gain->offset2[path][band];
+ } else if (band == RTW89_GAIN_OFFSET_6G_UH1) {
+ if (fc_ch == 239)
+ normal_efuse = (gain->offset[path][band] + gain->offset2[path][band]) >> 1;
+ else if (fc_ch >= 225 && fc_ch <= 237)
+ normal_efuse = gain->offset[path][band];
+ else if (fc_ch >= 241 && fc_ch <= 253)
+ normal_efuse = gain->offset2[path][band];
+ } else {
+ normal_efuse = gain->offset[path][band];
+ }
+
+ return normal_efuse;
+}
+
+static void rtw8922d_calc_rx_gain_normal_cck(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx,
+ struct rtw89_phy_calc_efuse_gain *calc)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+ s8 rx_gain_offset;
+
+ rx_gain_offset = -rtw8922d_get_rx_gain_by_chan(rtwdev, chan, path, true);
+
+ if (chan->band_width == RTW89_CHANNEL_WIDTH_40)
+ rx_gain_offset += (3 << 2); /* compensate RPL loss of 3dB */
+
+ calc->cck_mean_gain_bias = (rx_gain_offset & 0x3) << 1;
+ calc->cck_rpl_ofst = (rx_gain_offset >> 2) + gain->cck_rpl_base[phy_idx];
+}
+
+static void rtw8922d_set_rx_gain_normal_cck(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_phy_calc_efuse_gain calc = {};
+
+ rtw8922d_calc_rx_gain_normal_cck(rtwdev, chan, path, phy_idx, &calc);
+
+ rtw89_phy_write32_idx(rtwdev, R_GAIN_BIAS_BE4, B_GAIN_BIAS_BW20_BE4,
+ calc.cck_mean_gain_bias, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_GAIN_BIAS_BE4, B_GAIN_BIAS_BW40_BE4,
+ calc.cck_mean_gain_bias, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_CCK_RPL_OFST_BE4, B_CCK_RPL_OFST_BE4,
+ calc.cck_rpl_ofst, phy_idx);
+}
+
+static void rtw8922d_calc_rx_gain_normal_ofdm(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx,
+ struct rtw89_phy_calc_efuse_gain *calc)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+ s8 rx_gain_offset;
+
+ rx_gain_offset = rtw8922d_get_rx_gain_by_chan(rtwdev, chan, path, false);
+ calc->rssi_ofst = (rx_gain_offset + gain->ref_gain_base[phy_idx]) & 0xff;
+}
+
+static void rtw8922d_set_rx_gain_normal_ofdm(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ static const u32 rssi_ofst_addr[2] = {R_OFDM_OFST_P0_BE4, R_OFDM_OFST_P1_BE4};
+ static const u32 rssi_ofst_addr_m[2] = {B_OFDM_OFST_P0_BE4, B_OFDM_OFST_P1_BE4};
+ static const u32 rpl_bias_comp[2] = {R_OFDM_RPL_BIAS_P0_BE4, R_OFDM_RPL_BIAS_P1_BE4};
+ static const u32 rpl_bias_comp_m[2] = {B_OFDM_RPL_BIAS_P0_BE4, B_OFDM_RPL_BIAS_P1_BE4};
+ struct rtw89_phy_calc_efuse_gain calc = {};
+
+ rtw8922d_calc_rx_gain_normal_ofdm(rtwdev, chan, path, phy_idx, &calc);
+
+ rtw89_phy_write32_idx(rtwdev, rssi_ofst_addr[path], rssi_ofst_addr_m[path],
+ calc.rssi_ofst, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, rpl_bias_comp[path], rpl_bias_comp_m[path], 0, phy_idx);
+}
+
+static void rtw8922d_set_rx_gain_normal(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+
+ if (!gain->offset_valid)
+ return;
+
+ if (chan->band_type == RTW89_BAND_2G)
+ rtw8922d_set_rx_gain_normal_cck(rtwdev, chan, path, phy_idx);
+
+ rtw8922d_set_rx_gain_normal_ofdm(rtwdev, chan, path, phy_idx);
+}
+
+static void rtw8922d_calc_rx_gain_normal(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx,
+ struct rtw89_phy_calc_efuse_gain *calc)
+{
+ rtw8922d_calc_rx_gain_normal_ofdm(rtwdev, chan, path, phy_idx, calc);
+
+ if (chan->band_type != RTW89_BAND_2G)
+ return;
+
+ rtw8922d_calc_rx_gain_normal_cck(rtwdev, chan, path, phy_idx, calc);
+}
+
+static void rtw8922d_set_cck_parameters(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ u8 regd = rtw89_regd_get(rtwdev, chan->band_type);
+ u8 central_ch = chan->channel;
+
+ if (central_ch == 14) {
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF0_BE4, B_PCOEFF01_BE4, 0x3b13ff, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF2_BE4, B_PCOEFF23_BE4, 0x1c42de, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF4_BE4, B_PCOEFF45_BE4, 0xfdb0ad, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF6_BE4, B_PCOEFF67_BE4, 0xf60f6e, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF8_BE4, B_PCOEFF89_BE4, 0xfd8f92, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF10_BE4, B_PCOEFF10_BE4, 0x2d011, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF12_BE4, B_PCOEFF12_BE4, 0x1c02c, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF14_BE4, B_PCOEFF14_BE4, 0xfff00a, phy_idx);
+
+ return;
+ }
+
+ if (regd == RTW89_FCC) {
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF0_BE4, B_PCOEFF01_BE4, 0x39A3BC, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF2_BE4, B_PCOEFF23_BE4, 0x2AA339, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF4_BE4, B_PCOEFF45_BE4, 0x15B202, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF6_BE4, B_PCOEFF67_BE4, 0x0550C7, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF8_BE4, B_PCOEFF89_BE4, 0xfe0009, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF10_BE4, B_PCOEFF10_BE4, 0xfd7fd3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF12_BE4, B_PCOEFF12_BE4, 0xfeffe2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF14_BE4, B_PCOEFF14_BE4, 0xffeff8, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF0_BE4, B_PCOEFF01_BE4, 0x3d23ff, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF2_BE4, B_PCOEFF23_BE4, 0x29b354, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF4_BE4, B_PCOEFF45_BE4, 0xfc1c8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF6_BE4, B_PCOEFF67_BE4, 0xfdb053, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF8_BE4, B_PCOEFF89_BE4, 0xf86f9a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF10_BE4, B_PCOEFF10_BE4, 0xfaef92, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF12_BE4, B_PCOEFF12_BE4, 0xfe5fcc, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_PCOEFF14_BE4, B_PCOEFF14_BE4, 0xffdff5, phy_idx);
+ }
+}
+
+static void rtw8922d_ctrl_ch(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ u16 central_freq = chan->freq;
+ u8 band = chan->band_type;
+ u8 chan_idx;
+
+ if (!central_freq) {
+ rtw89_warn(rtwdev, "Invalid central_freq\n");
+ return;
+ }
+
+ rtw8922d_ctrl_ch_core(rtwdev, chan, phy_idx);
+
+ chan_idx = rtw89_encode_chan_idx(rtwdev, chan->primary_channel, band);
+ rtw89_phy_write32_idx(rtwdev, R_MAC_PIN_SEL_BE4, B_CH_IDX_SEG0, chan_idx, phy_idx);
+
+ rtw8922d_set_gain(rtwdev, chan, RF_PATH_A, phy_idx);
+ rtw8922d_set_gain(rtwdev, chan, RF_PATH_B, phy_idx);
+
+ rtw8922d_set_rx_gain_normal(rtwdev, chan, RF_PATH_A, phy_idx);
+ rtw8922d_set_rx_gain_normal(rtwdev, chan, RF_PATH_B, phy_idx);
+
+ if (band == RTW89_BAND_2G)
+ rtw8922d_set_cck_parameters(rtwdev, chan, phy_idx);
+}
+
+static void rtw8922d_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_sb, u8 bw,
+ enum rtw89_phy_idx phy_idx)
+{
+ switch (bw) {
+ default:
+ case RTW89_CHANNEL_WIDTH_20:
+ rtw89_phy_write32_idx(rtwdev, R_BW_BE4, B_BW_BE4, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BW_BE4, B_PRISB_BE4, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW_BE4, B_RXBW_BE4, 0x2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW67_BE4, B_RXBW6_BE4, 0x2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW67_BE4, B_RXBW7_BE4, 0x2, phy_idx);
+ break;
+ case RTW89_CHANNEL_WIDTH_40:
+ rtw89_phy_write32_idx(rtwdev, R_BW_BE4, B_BW_BE4, 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BW_BE4, B_PRISB_BE4, pri_sb, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW_BE4, B_RXBW_BE4, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW67_BE4, B_RXBW6_BE4, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW67_BE4, B_RXBW7_BE4, 0x3, phy_idx);
+ break;
+ case RTW89_CHANNEL_WIDTH_80:
+ rtw89_phy_write32_idx(rtwdev, R_BW_BE4, B_BW_BE4, 0x2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BW_BE4, B_PRISB_BE4, pri_sb, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW_BE4, B_RXBW_BE4, 0x4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW67_BE4, B_RXBW6_BE4, 0x4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW67_BE4, B_RXBW7_BE4, 0x4, phy_idx);
+ break;
+ case RTW89_CHANNEL_WIDTH_160:
+ rtw89_phy_write32_idx(rtwdev, R_BW_BE4, B_BW_BE4, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BW_BE4, B_PRISB_BE4, pri_sb, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW_BE4, B_RXBW_BE4, 0x5, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW67_BE4, B_RXBW6_BE4, 0x5, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBW67_BE4, B_RXBW7_BE4, 0x5, phy_idx);
+ break;
+ }
+}
+
+static const u16 spur_nbi_a[] = {6400};
+static const u16 spur_csi[] = {6400};
+
+static u32 rtw8922d_spur_freq(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan,
+ bool nbi_or_csi, enum rtw89_rf_path path)
+{
+ static const u16 cbw[RTW89_CHANNEL_WIDTH_ORDINARY_NUM] = {
+ 20, 40, 80, 160, 320,
+ };
+ u16 freq_lower, freq_upper, freq;
+ const u16 *spur_freq;
+ int spur_freq_nr, i;
+
+ if (rtwdev->hal.aid != RTL8922D_AID7060)
+ return 0;
+
+ if (nbi_or_csi && path == RF_PATH_A) {
+ spur_freq = spur_nbi_a;
+ spur_freq_nr = ARRAY_SIZE(spur_nbi_a);
+ } else if (!nbi_or_csi) {
+ spur_freq = spur_csi;
+ spur_freq_nr = ARRAY_SIZE(spur_csi);
+ } else {
+ return 0;
+ }
+
+ if (chan->band_width >= RTW89_CHANNEL_WIDTH_ORDINARY_NUM)
+ return 0;
+
+ freq_lower = chan->freq - cbw[chan->band_width] / 2;
+ freq_upper = chan->freq + cbw[chan->band_width] / 2;
+
+ for (i = 0; i < spur_freq_nr; i++) {
+ freq = spur_freq[i];
+
+ if (freq >= freq_lower && freq <= freq_upper)
+ return freq;
+ }
+
+ return 0;
+}
+
+#define CARRIER_SPACING_312_5 312500 /* 312.5 kHz */
+#define CARRIER_SPACING_78_125 78125 /* 78.125 kHz */
+#define MAX_TONE_NUM 2048
+
+static void rtw8922d_set_csi_tone_idx(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ s32 freq_diff, csi_idx, csi_tone_idx;
+ u32 spur_freq;
+
+ spur_freq = rtw8922d_spur_freq(rtwdev, chan, false, RF_PATH_AB);
+ if (spur_freq == 0) {
+ rtw89_phy_write32_idx(rtwdev, R_CSI_WGT_BE4, B_CSI_WGT_EN_BE4,
+ 0, phy_idx);
+ return;
+ }
+
+ freq_diff = (spur_freq - chan->freq) * 1000000;
+ csi_idx = s32_div_u32_round_closest(freq_diff, CARRIER_SPACING_78_125);
+ s32_div_u32_round_down(csi_idx, MAX_TONE_NUM, &csi_tone_idx);
+
+ rtw89_phy_write32_idx(rtwdev, R_CSI_WGT_BE4, B_CSI_WGT_IDX_BE4,
+ csi_tone_idx, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_CSI_WGT_BE4, B_CSI_WGT_EN_BE4, 1, phy_idx);
+}
+
+static const struct rtw89_nbi_reg_def rtw8922d_nbi_reg_def[] = {
+ [RF_PATH_A] = {
+ .notch1_idx = {0x241A0, 0xFF},
+ .notch1_frac_idx = {0x241A0, 0xC00},
+ .notch1_en = {0x241A0, 0x1000},
+ .notch2_idx = {0x241AC, 0xFF},
+ .notch2_frac_idx = {0x241AC, 0xC00},
+ .notch2_en = {0x241AC, 0x1000},
+ },
+ [RF_PATH_B] = {
+ .notch1_idx = {0x245A0, 0xFF},
+ .notch1_frac_idx = {0x245A0, 0xC00},
+ .notch1_en = {0x245A0, 0x1000},
+ .notch2_idx = {0x245AC, 0xFF},
+ .notch2_frac_idx = {0x245AC, 0xC00},
+ .notch2_en = {0x245AC, 0x1000},
+ },
+};
+
+static void rtw8922d_set_nbi_tone_idx(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_nbi_reg_def *nbi = &rtw8922d_nbi_reg_def[path];
+ s32 nbi_frac_idx, nbi_frac_tone_idx;
+ s32 nbi_idx, nbi_tone_idx;
+ bool notch2_chk = false;
+ u32 spur_freq, fc;
+ s32 freq_diff;
+
+ spur_freq = rtw8922d_spur_freq(rtwdev, chan, true, path);
+ if (spur_freq == 0) {
+ rtw89_phy_write32_idx(rtwdev, nbi->notch1_en.addr,
+ nbi->notch1_en.mask, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch2_en.addr,
+ nbi->notch2_en.mask, 0, phy_idx);
+ return;
+ }
+
+ fc = chan->freq;
+ if (chan->band_width == RTW89_CHANNEL_WIDTH_160) {
+ fc = (spur_freq > fc) ? fc + 40 : fc - 40;
+ if ((fc > spur_freq &&
+ chan->channel < chan->primary_channel) ||
+ (fc < spur_freq &&
+ chan->channel > chan->primary_channel))
+ notch2_chk = true;
+ }
+
+ freq_diff = (spur_freq - fc) * 1000000;
+ nbi_idx = s32_div_u32_round_down(freq_diff, CARRIER_SPACING_312_5,
+ &nbi_frac_idx);
+
+ if (chan->band_width == RTW89_CHANNEL_WIDTH_20) {
+ s32_div_u32_round_down(nbi_idx + 32, 64, &nbi_tone_idx);
+ } else {
+ u16 tone_para = (chan->band_width == RTW89_CHANNEL_WIDTH_40) ?
+ 128 : 256;
+
+ s32_div_u32_round_down(nbi_idx, tone_para, &nbi_tone_idx);
+ }
+ nbi_frac_tone_idx =
+ s32_div_u32_round_closest(nbi_frac_idx, CARRIER_SPACING_78_125);
+
+ if (chan->band_width == RTW89_CHANNEL_WIDTH_160 && notch2_chk) {
+ rtw89_phy_write32_idx(rtwdev, nbi->notch2_idx.addr,
+ nbi->notch2_idx.mask, nbi_tone_idx, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch2_frac_idx.addr,
+ nbi->notch2_frac_idx.mask, nbi_frac_tone_idx,
+ phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch2_en.addr,
+ nbi->notch2_en.mask, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch2_en.addr,
+ nbi->notch2_en.mask, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch1_en.addr,
+ nbi->notch1_en.mask, 0, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, nbi->notch1_idx.addr,
+ nbi->notch1_idx.mask, nbi_tone_idx, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch1_frac_idx.addr,
+ nbi->notch1_frac_idx.mask, nbi_frac_tone_idx,
+ phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch1_en.addr,
+ nbi->notch1_en.mask, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch1_en.addr,
+ nbi->notch1_en.mask, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, nbi->notch2_en.addr,
+ nbi->notch2_en.mask, 0, phy_idx);
+ }
+}
+
+static void rtw8922d_spur_elimination(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_set_csi_tone_idx(rtwdev, chan, phy_idx);
+ rtw8922d_set_nbi_tone_idx(rtwdev, chan, RF_PATH_A, phy_idx);
+ rtw8922d_set_nbi_tone_idx(rtwdev, chan, RF_PATH_B, phy_idx);
+}
+
+static const u32 bbrst_mask[2] = {B_BE_FEN_BBPLAT_RSTB, B_BE_FEN_BB1PLAT_RSTB};
+static const u32 glbrst_mask[2] = {B_BE_FEN_BB_IP_RSTN, B_BE_FEN_BB1_IP_RSTN};
+static const u32 chip_top_bitmask[2] = {0xffff, 0xffff0000};
+
+static void rtw8922d_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x0);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx], 0x0);
+ rtw89_write32_mask(rtwdev, R_BE_DMAC_SYS_CR32B, chip_top_bitmask[phy_idx], 0x74F9);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x1);
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 0, phy_idx);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx], 0x1);
+}
+
+static void rtw8922d_bb_postinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_write32_idx_clr(rtwdev, R_SHAPER_COEFF_BE4, B_SHAPER_COEFF_BE4, phy_idx);
+ rtw89_phy_write32_idx_set(rtwdev, R_SHAPER_COEFF_BE4, B_SHAPER_COEFF_BE4, phy_idx);
+}
+
+static void rtw8922d_bb_reset_en(struct rtw89_dev *rtwdev, enum rtw89_band band,
+ bool en, enum rtw89_phy_idx phy_idx)
+{
+ if (en)
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 1, phy_idx);
+ else
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 0, phy_idx);
+}
+
+static int rtw8922d_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path tx_path,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_reg2_def path_com_cr[] = {
+ {0x11A00, 0x21C86900},
+ {0x11A04, 0x00E4E433},
+ {0x11A08, 0x39390CC9},
+ {0x11A10, 0x10CC0000},
+ {0x11A14, 0x00240393},
+ {0x11A18, 0x201C8600},
+ {0x11B38, 0x39393FDB},
+ {0x11B3C, 0x00E4E4FF},
+ };
+ int ret = 0;
+ u32 reg;
+ int i;
+
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_EN_BE4, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_MA_BE4, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_MB_BE4, 0x0, phy_idx);
+
+ if (phy_idx == RTW89_PHY_1 && !rtwdev->dbcc_en)
+ return 0;
+
+ if (tx_path == RF_PATH_A) {
+ path_com_cr[1].data = 0x40031;
+ path_com_cr[2].data = 0x1000C48;
+ path_com_cr[5].data = 0x200;
+ path_com_cr[6].data = 0x1000C48;
+ path_com_cr[7].data = 0x40031;
+ } else if (tx_path == RF_PATH_B) {
+ path_com_cr[1].data = 0x40032;
+ path_com_cr[2].data = 0x1000C88;
+ path_com_cr[5].data = 0x400;
+ path_com_cr[6].data = 0x1000C88;
+ path_com_cr[7].data = 0x40032;
+ } else if (tx_path == RF_PATH_AB) {
+ path_com_cr[1].data = 0x00E4E433;
+ path_com_cr[2].data = 0x39390CC9;
+ path_com_cr[5].data = 0x201C8600;
+ path_com_cr[6].data = 0x1010CC9;
+ path_com_cr[7].data = 0x40433;
+ } else {
+ ret = -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(path_com_cr); i++) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, path_com_cr[i].addr, phy_idx);
+ rtw89_write32(rtwdev, reg, path_com_cr[i].data);
+ }
+
+ return ret;
+}
+
+static void rtw8922d_bb_reset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+}
+
+static void rtw8922d_tssi_reset(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) {
+ if (phy_idx == RTW89_PHY_0) {
+ rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB0_BE4,
+ B_TXPWR_RSTB0_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB0_BE4,
+ B_TXPWR_RSTB0_BE4, 0x1);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB1_BE4,
+ B_TXPWR_RSTB1_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB1_BE4,
+ B_TXPWR_RSTB1_BE4, 0x1);
+ }
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB0_BE4, B_TXPWR_RSTB0_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB0_BE4, B_TXPWR_RSTB0_BE4, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB1_BE4, B_TXPWR_RSTB1_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_TXPWR_RSTB1_BE4, B_TXPWR_RSTB1_BE4, 0x1);
+ }
+}
+
+static int rtw8922d_ctrl_rx_path_tmac(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path rx_path,
+ enum rtw89_phy_idx phy_idx)
+{
+ enum rtw89_rf_path_bit path;
+
+ if (rx_path == RF_PATH_A)
+ path = RF_A;
+ else if (rx_path == RF_PATH_B)
+ path = RF_B;
+ else
+ path = RF_AB;
+
+ rtw89_phy_write32_idx(rtwdev, R_ANT_RX_BE4, B_ANT_RX_BE4, path, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_ANT_RX_1RCCA_BE4, B_ANT_RX_1RCCA_BE4,
+ path, phy_idx);
+
+ if (rx_path == RF_PATH_AB) {
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC0_BE4, B_RXCH_MCS4_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS5_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS6_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS7_BE4, 7, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS8_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS9_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN04_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN07_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN01_BE4, B_RX_AWGN09_BE4, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN02_BE4, B_RX_AWGN11_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC04_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC05_BE4, 5, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC06_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC07_BE4, 5, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC08_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC01_BE4, B_RX_LDPC09_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC10_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC11_BE4, 2, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC0_BE4, B_RXCH_MCS4_BE4, 13, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS5_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS6_BE4, 6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS7_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS8_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS9_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN04_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN07_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN01_BE4, B_RX_AWGN09_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN02_BE4, B_RX_AWGN11_BE4, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC04_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC05_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC06_BE4, 6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC07_BE4, 16, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC08_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC01_BE4, B_RX_LDPC09_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC10_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC11_BE4, 7, phy_idx);
+ }
+
+ return 0;
+}
+
+static void rtw8922d_set_digital_pwr_comp(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan, u8 nss,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+#define DIGITAL_PWR_COMP_REG_NUM 22
+ static const u32 pw_comp_cr[2] = {R_RX_PATH0_TBL0_BE4, R_RX_PATH1_TBL0_BE4};
+ const __le32 (*pwr_comp_val)[2][RTW89_TX_COMP_BAND_NR]
+ [BB_PATH_NUM_8922D][DIGITAL_PWR_COMP_REG_NUM];
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ const struct rtw89_fw_element_hdr *txcomp_elm = elm_info->tx_comp;
+ const __le32 *digital_pwr_comp;
+ u32 addr, val;
+ u32 i;
+
+ if (sizeof(*pwr_comp_val) != le32_to_cpu(txcomp_elm->size)) {
+ rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
+ "incorrect power comp size %d\n",
+ le32_to_cpu(txcomp_elm->size));
+ return;
+ }
+
+ pwr_comp_val = (const void *)txcomp_elm->u.common.contents;
+ digital_pwr_comp = (*pwr_comp_val)[nss][chan->tx_comp_band][path];
+ addr = pw_comp_cr[path];
+
+ for (i = 0; i < DIGITAL_PWR_COMP_REG_NUM; i++, addr += 4) {
+ val = le32_to_cpu(digital_pwr_comp[i]);
+ rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx);
+ }
+}
+
+static void rtw8922d_digital_pwr_comp(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ const struct rtw89_chan *chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+
+ if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) {
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 0, RF_PATH_A, RTW89_PHY_0);
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan1, 0, RF_PATH_B, RTW89_PHY_1);
+ } else {
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 1, RF_PATH_A, phy_idx);
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 1, RF_PATH_B, phy_idx);
+ }
+}
+
+static int rtw8922d_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode mode,
+ bool pwr_comp)
+{
+ const struct rtw89_chan *chan1;
+ u32 reg0, reg1;
+ u8 cck_phy_idx;
+
+ if (mode == MLO_2_PLUS_0_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEBAD);
+ udelay(1);
+
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEAAD);
+ } else if (mode == MLO_0_PLUS_2_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEFFF);
+
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEEFF);
+ } else if ((mode == MLO_1_PLUS_1_1RF) || (mode == DBCC_LEGACY)) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x3AAB);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x6180);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x180);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x0);
+ }
+
+ if (pwr_comp)
+ rtw8922d_digital_pwr_comp(rtwdev, RTW89_PHY_0);
+
+ reg0 = R_BBWRAP_ELMSR_BE4;
+ reg1 = rtw89_mac_reg_by_idx(rtwdev, reg0, 1);
+
+ if (mode == MLO_2_PLUS_0_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ } else if (mode == MLO_0_PLUS_2_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ } else if ((mode == MLO_1_PLUS_1_1RF) || (mode == DBCC_LEGACY)) {
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ cck_phy_idx = chan1->band_type == RTW89_BAND_2G ?
+ RTW89_PHY_1 : RTW89_PHY_0;
+
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, cck_phy_idx);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0x3);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0x3);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ }
+
+ udelay(1);
+
+ return 0;
+}
+
+static void rtw8922d_bb_sethw(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ enum rtw89_phy_idx phy_idx;
+ u32 reg;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, RTW89_PHY_0);
+ rtw89_write32_clr(rtwdev, reg, B_BE_PWR_CTRL_SEL);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, RTW89_PHY_1);
+ rtw89_write32_clr(rtwdev, reg, B_BE_PWR_CTRL_SEL);
+
+ if (hal->cid == RTL8922D_CID7090) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_PWR_BOOST_BE4, RTW89_PHY_0);
+ rtw89_write32_set(rtwdev, reg, B_PWR_BOOST_BE4);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_PWR_BOOST_BE4, RTW89_PHY_1);
+ rtw89_write32_set(rtwdev, reg, B_PWR_BOOST_BE4);
+ }
+
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_PSDU_BE4, 0);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_NSYM_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_LSIG_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_TXINFO_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TXERRCT_EN_BE4, B_TXERRCT_EN_BE4, 0);
+ rtw89_phy_write32_mask(rtwdev, R_TXERRCT1_EN_BE4, B_TXERRCT1_EN_BE4, 0);
+ rtw89_phy_write32_idx(rtwdev, R_IMR_TX_ERROR_BE4, B_IMR_TX_ERROR_BE4, 1, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_IMR_TX_ERROR_BE4, B_IMR_TX_ERROR_BE4, 1, RTW89_PHY_1);
+
+ rtw8922d_ctrl_mlo(rtwdev, rtwdev->mlo_dbcc_mode, false);
+
+ /* read these registers after loading BB parameters */
+ for (phy_idx = RTW89_PHY_0; phy_idx < RTW89_PHY_NUM; phy_idx++) {
+ gain->ref_gain_base[phy_idx] =
+ rtw89_phy_read32_idx(rtwdev, R_OFDM_OFST_P0_BE4,
+ B_OFDM_OFST_P0_BE4, phy_idx);
+ gain->cck_rpl_base[phy_idx] =
+ rtw89_phy_read32_idx(rtwdev, R_CCK_RPL_OFST_BE4,
+ B_CCK_RPL_OFST_BE4, phy_idx);
+ }
+}
+
+static void rtw8922d_set_channel_bb(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ bool cck_en = chan->band_type == RTW89_BAND_2G;
+ u8 pri_sb = chan->pri_sb_idx;
+ u32 val;
+
+ rtw89_phy_bb_wrap_set_rfsi_ct_opt(rtwdev, phy_idx);
+ rtw8922d_ctrl_ch(rtwdev, chan, phy_idx);
+ rtw8922d_ctrl_bw(rtwdev, pri_sb, chan->band_width, phy_idx);
+ rtw89_phy_bb_wrap_set_rfsi_bandedge_ch(rtwdev, chan, phy_idx);
+
+ if (cck_en)
+ rtw8922d_ctrl_sco_cck(rtwdev, chan->primary_channel,
+ chan->band_width, phy_idx);
+
+ rtw8922d_spur_elimination(rtwdev, chan, phy_idx);
+
+ if (hal->cid == RTL8922D_CID7025) {
+ if (chan->band_width == RTW89_CHANNEL_WIDTH_160)
+ val = 0x1f9;
+ else if (chan->band_width == RTW89_CHANNEL_WIDTH_80)
+ val = 0x1f5;
+ else
+ val = 0x1e2;
+
+ rtw89_phy_write32_idx(rtwdev, R_AWGN_DET_BE4, B_AWGN_DET_BE4, val, phy_idx);
+ }
+
+ rtw8922d_tssi_reset(rtwdev, RF_PATH_AB, phy_idx);
+}
+
+static void rtw8922d_pre_set_channel_bb(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (!rtwdev->dbcc_en)
+ return;
+
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4, B_SYS_DBCC_BE4, 0x0);
+
+ if (phy_idx == RTW89_PHY_0) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEBAD);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEAAD);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEEFF);
+ }
+
+ fsleep(1);
+}
+
+static void rtw8922d_post_set_channel_bb(struct rtw89_dev *rtwdev,
+ enum rtw89_mlo_dbcc_mode mode,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (!rtwdev->dbcc_en)
+ return;
+
+ rtw8922d_ctrl_mlo(rtwdev, mode, true);
+}
+
+static void rtw8922d_set_channel(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_mac_idx mac_idx,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_set_channel_mac(rtwdev, chan, mac_idx);
+ rtw8922d_set_channel_bb(rtwdev, chan, phy_idx);
+ rtw8922d_set_channel_rf(rtwdev, chan, phy_idx);
+}
+
+static void __rtw8922d_dack_reset(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
+{
+ rtw89_phy_write32_mask(rtwdev, 0x3c000 + (path << 8), BIT(17), 0x0);
+ rtw89_phy_write32_mask(rtwdev, 0x3c000 + (path << 8), BIT(17), 0x1);
+}
+
+static void rtw8922d_dack_reset(struct rtw89_dev *rtwdev)
+{
+ __rtw8922d_dack_reset(rtwdev, RF_PATH_A);
+ __rtw8922d_dack_reset(rtwdev, RF_PATH_B);
+}
+
+static
+void rtw8922d_hal_reset(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx, enum rtw89_mac_idx mac_idx,
+ enum rtw89_band band, u32 *tx_en, bool enter)
+{
+ if (enter) {
+ rtw89_chip_stop_sch_tx(rtwdev, mac_idx, tx_en, RTW89_SCH_TX_SEL_ALL);
+ rtw89_mac_cfg_ppdu_status(rtwdev, mac_idx, false);
+ rtw8922d_dack_reset(rtwdev);
+ rtw8922d_tssi_cont_en_phyidx(rtwdev, false, phy_idx);
+ fsleep(40);
+ rtw8922d_bb_reset_en(rtwdev, band, false, phy_idx);
+ } else {
+ rtw89_mac_cfg_ppdu_status(rtwdev, mac_idx, true);
+ rtw8922d_tssi_cont_en_phyidx(rtwdev, true, phy_idx);
+ rtw8922d_bb_reset_en(rtwdev, band, true, phy_idx);
+ rtw89_chip_resume_sch_tx(rtwdev, mac_idx, *tx_en);
+ }
+}
+
+static void rtw8922d_set_channel_help(struct rtw89_dev *rtwdev, bool enter,
+ struct rtw89_channel_help_params *p,
+ const struct rtw89_chan *chan,
+ enum rtw89_mac_idx mac_idx,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (enter) {
+ rtw8922d_pre_set_channel_bb(rtwdev, phy_idx);
+ rtw8922d_pre_set_channel_rf(rtwdev, phy_idx);
+ }
+
+ rtw8922d_hal_reset(rtwdev, phy_idx, mac_idx, chan->band_type, &p->tx_en, enter);
+
+ if (!enter) {
+ rtw8922d_post_set_channel_bb(rtwdev, rtwdev->mlo_dbcc_mode, phy_idx);
+ rtw8922d_post_set_channel_rf(rtwdev, phy_idx);
+ }
+}
+
+static void rtw8922d_rfk_init(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+ struct rtw89_lck_info *lck = &rtwdev->lck;
+
+ rtwdev->is_tssi_mode[RF_PATH_A] = false;
+ rtwdev->is_tssi_mode[RF_PATH_B] = false;
+ memset(rfk_mcc, 0, sizeof(*rfk_mcc));
+ memset(lck, 0, sizeof(*lck));
+}
+
+static void __rtw8922d_rfk_init_late(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan)
+{
+ rtw8922d_rfk_mlo_ctrl(rtwdev);
+
+ rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
+ if (!test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
+ rtw89_phy_rfk_rxdck_and_wait(rtwdev, phy_idx, chan, false, 128);
+ if (phy_idx == RTW89_PHY_0)
+ rtw89_phy_rfk_dack_and_wait(rtwdev, phy_idx, chan, 58);
+}
+
+static void rtw8922d_rfk_init_late(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
+
+ __rtw8922d_rfk_init_late(rtwdev, RTW89_PHY_0, chan);
+ if (rtwdev->dbcc_en)
+ __rtw8922d_rfk_init_late(rtwdev, RTW89_PHY_1, chan);
+}
+
+static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath)
+{
+ u32 rf_mode;
+ u8 path;
+ int ret;
+
+ for (path = 0; path < RF_PATH_NUM_8922D; path++) {
+ if (!(kpath & BIT(path)))
+ continue;
+
+ ret = read_poll_timeout_atomic(rtw89_read_rf, rf_mode, rf_mode != 2,
+ 2, 5000, false, rtwdev, path, 0x00,
+ RR_MOD_MASK);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[RFK] Wait S%d to Rx mode!! (ret = %d)\n",
+ path, ret);
+ }
+}
+
+static void __rtw8922d_tssi_enable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ u8 path;
+
+ for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+ u32 addr_ofst = (phy_idx << 12) + (path << 8);
+
+ rtw89_phy_write32_mask(rtwdev, R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 + addr_ofst,
+ B_TSSI_DCK_MOV_AVG_LEN_P0_BE4, 0x4);
+ rtw89_phy_write32_clr(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+ B_USED_TSSI_TRK_ON_P0_BE4);
+ rtw89_phy_write32_set(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+ B_USED_TSSI_TRK_ON_P0_BE4);
+ rtw89_phy_write32_clr(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+ B_TSSI_EN_P0_BE4);
+ rtw89_phy_write32_mask(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+ B_TSSI_EN_P0_BE4, 0x3);
+ }
+}
+
+static void __rtw8922d_tssi_disable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ u8 path;
+
+ for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+ u32 addr_ofst = (phy_idx << 12) + (path << 8);
+
+ rtw89_phy_write32_clr(rtwdev, R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 + addr_ofst,
+ B_TSSI_DCK_MOV_AVG_LEN_P0_BE4);
+ rtw89_phy_write32_clr(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+ B_USED_TSSI_TRK_ON_P0_BE4);
+ rtw89_phy_write32_clr(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+ B_TSSI_EN_P0_BE4);
+ }
+}
+
+static void rtw8922d_rfk_tssi(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan,
+ enum rtw89_tssi_mode tssi_mode,
+ unsigned int ms)
+{
+ int ret;
+
+ ret = rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, tssi_mode, ms);
+ if (ret) {
+ rtwdev->is_tssi_mode[RF_PATH_A] = false;
+ rtwdev->is_tssi_mode[RF_PATH_B] = false;
+ } else {
+ rtwdev->is_tssi_mode[RF_PATH_A] = true;
+ rtwdev->is_tssi_mode[RF_PATH_B] = true;
+ }
+}
+
+static void rtw8922d_rfk_channel(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx);
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+ u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB, chanctx_idx);
+ u32 tx_en;
+
+ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_START);
+ rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL);
+ _wait_rx_mode(rtwdev, RF_AB);
+
+ rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
+ rtw89_phy_rfk_txgapk_and_wait(rtwdev, phy_idx, chan, 54);
+ rtw89_phy_rfk_txiqk_and_wait(rtwdev, phy_idx, chan, 45);
+ rtw89_phy_rfk_iqk_and_wait(rtwdev, phy_idx, chan, 84);
+ rtw8922d_rfk_tssi(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 20);
+ rtw89_phy_rfk_cim3k_and_wait(rtwdev, phy_idx, chan, 44);
+ rtw89_phy_rfk_dpk_and_wait(rtwdev, phy_idx, chan, 68);
+ rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, true, 32);
+
+ rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en);
+ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_STOP);
+}
+
+static void rtw8922d_rfk_band_changed(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan)
+{
+}
+
+static void rtw8922d_rfk_scan(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ bool start)
+{
+ if (start)
+ __rtw8922d_tssi_disable(rtwdev, rtwvif_link->phy_idx);
+ else
+ __rtw8922d_tssi_enable(rtwdev, rtwvif_link->phy_idx);
+}
+
+static void rtw8922d_rfk_track(struct rtw89_dev *rtwdev)
+{
+ rtw8922d_lck_track(rtwdev);
+}
+
+static const struct rtw89_reg_def rtw8922d_txpwr_ref[][3] = {
+ {{ .addr = R_TXAGC_REF_DBM_PATH0_TBL0_BE4,
+ .mask = B_TXAGC_OFDM_REF_DBM_PATH0_TBL0_BE4 },
+ { .addr = R_TXAGC_REF_DBM_PATH0_TBL0_BE4,
+ .mask = B_TXAGC_CCK_REF_DBM_PATH0_TBL0_BE4 },
+ { .addr = R_TSSI_K_OFDM_PATH0_TBL0_BE4,
+ .mask = B_TSSI_K_OFDM_PATH0_TBL0_BE4 }
+ },
+ {{ .addr = R_TXAGC_REF_DBM_PATH0_TBL1_BE4,
+ .mask = B_TXAGC_OFDM_REF_DBM_PATH0_TBL1_BE4 },
+ { .addr = R_TXAGC_REF_DBM_PATH0_TBL1_BE4,
+ .mask = B_TXAGC_CCK_REF_DBM_PATH0_TBL1_BE4 },
+ { .addr = R_TSSI_K_OFDM_PATH0_TBL1_BE4,
+ .mask = B_TSSI_K_OFDM_PATH0_TBL1_BE4 }
+ },
+};
+
+static void rtw8922d_set_txpwr_diff(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ s16 pwr_ofst = rtw89_phy_ant_gain_pwr_offset(rtwdev, chan);
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ static const u32 path_ofst[] = {0x0, 0x100};
+ const struct rtw89_reg_def *txpwr_ref;
+ s16 tssi_k_ofst = abs(pwr_ofst);
+ s16 ofst_dec[RF_PATH_NUM_8922D];
+ s16 tssi_k[RF_PATH_NUM_8922D];
+ s16 pwr_ref_ofst;
+ s16 pwr_ref = 16;
+ u8 i;
+
+ pwr_ref <<= chip->txpwr_factor_rf;
+ pwr_ref_ofst = pwr_ref - rtw89_phy_txpwr_bb_to_rf(rtwdev, abs(pwr_ofst));
+
+ ofst_dec[RF_PATH_A] = pwr_ofst > 0 ? pwr_ref : pwr_ref_ofst;
+ ofst_dec[RF_PATH_B] = pwr_ofst > 0 ? pwr_ref_ofst : pwr_ref;
+ tssi_k[RF_PATH_A] = pwr_ofst > 0 ? 0 : tssi_k_ofst;
+ tssi_k[RF_PATH_B] = pwr_ofst > 0 ? tssi_k_ofst : 0;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ txpwr_ref = rtw8922d_txpwr_ref[phy_idx];
+
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[0].addr + path_ofst[i],
+ txpwr_ref[0].mask, ofst_dec[i]);
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[1].addr + path_ofst[i],
+ txpwr_ref[1].mask, ofst_dec[i]);
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[2].addr + path_ofst[i],
+ txpwr_ref[2].mask, tssi_k[i]);
+ }
+}
+
+static void rtw8922d_set_txpwr_ref(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ s16 ref_ofdm = 0;
+ s16 ref_cck = 0;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n");
+
+ rtw8922d_set_txpwr_diff(rtwdev, chan, phy_idx);
+
+ rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL,
+ B_BE_PWR_REF_CTRL_OFDM, ref_ofdm);
+ rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL,
+ B_BE_PWR_REF_CTRL_CCK, ref_cck);
+}
+
+static void rtw8922d_set_txpwr_sar_diff(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_sar_parm sar_parm = {
+ .center_freq = chan->freq,
+ .force_path = true,
+ };
+ s16 sar_rf;
+ s8 sar_mac;
+
+ if (phy_idx != RTW89_PHY_0)
+ return;
+
+ sar_parm.path = RF_PATH_A;
+ sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
+ sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
+ rtw89_phy_write32_mask(rtwdev, R_P0_TXPWRB_BE4, B_TXPWRB_MAX_BE, sar_rf);
+
+ sar_parm.path = RF_PATH_B;
+ sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
+ sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
+ rtw89_phy_write32_mask(rtwdev, R_P1_TXPWRB_BE4, B_TXPWRB_MAX_BE, sar_rf);
+}
+
+static void rtw8922d_set_txpwr(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx);
+ rtw8922d_set_txpwr_ref(rtwdev, chan, phy_idx);
+ rtw8922d_set_txpwr_sar_diff(rtwdev, chan, phy_idx);
+}
+
+static void rtw8922d_set_txpwr_ctrl(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, phy_idx);
+
+ rtw8922d_set_txpwr_ref(rtwdev, chan, phy_idx);
+}
+
+static void rtw8922d_ctrl_trx_path(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path tx_path, u8 tx_nss,
+ enum rtw89_rf_path rx_path, u8 rx_nss)
+{
+ enum rtw89_phy_idx phy_idx;
+
+ for (phy_idx = RTW89_PHY_0; phy_idx <= RTW89_PHY_1; phy_idx++) {
+ rtw8922d_ctrl_tx_path_tmac(rtwdev, tx_path, phy_idx);
+ rtw8922d_ctrl_rx_path_tmac(rtwdev, rx_path, phy_idx);
+
+ rtw8922d_tssi_reset(rtwdev, rx_path, phy_idx);
+ }
+}
+
+static void rtw8922d_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (en) {
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A,
+ 0xf, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x80, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA10_A, 0x8080, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_LNA_IBADC_A, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B,
+ 0xf, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x80, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_LNA_IBADC_B, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x34, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A,
+ 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x1a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA10_A, 0x2a2a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_LNA_IBADC_A, 0x7a6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x26, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B,
+ 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x2a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_LNA_IBADC_B, 0x7a6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x26, phy_idx);
+ }
+}
+
+static void rtw8922d_bb_cfg_txrx_path(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
+ enum rtw89_band band = chan->band_type;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u8 ntx_path = RF_PATH_AB;
+ u8 nrx_path = RF_PATH_AB;
+ u32 tx_en0, tx_en1;
+ u8 rx_nss = 2;
+
+ if (hal->antenna_tx == RF_A)
+ ntx_path = RF_PATH_A;
+ else if (hal->antenna_tx == RF_B)
+ ntx_path = RF_PATH_B;
+
+ if (hal->antenna_rx == RF_A)
+ nrx_path = RF_PATH_A;
+ else if (hal->antenna_rx == RF_B)
+ nrx_path = RF_PATH_B;
+
+ if (nrx_path != RF_PATH_AB)
+ rx_nss = 1;
+
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_0, RTW89_MAC_0, band, &tx_en0, true);
+ if (rtwdev->dbcc_en)
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_1, RTW89_MAC_1, band,
+ &tx_en1, true);
+
+ rtw8922d_ctrl_trx_path(rtwdev, ntx_path, 2, nrx_path, rx_nss);
+
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_0, RTW89_MAC_0, band, &tx_en0, false);
+ if (rtwdev->dbcc_en)
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_1, RTW89_MAC_1, band,
+ &tx_en1, false);
+}
+
+static u8 rtw8922d_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path)
+{
+ u8 val;
+
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_EN_BE4, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_TRIG_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_TRIG_BE4, 0x1);
+
+ fsleep(100);
+
+ val = rtw89_phy_read32_mask(rtwdev, R_TC_VAL_BE4, B_TC_VAL_BE4);
+
+ return val;
+}
+
+static u32 rtw8922d_chan_to_rf18_val(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan)
+{
+ u32 val = u32_encode_bits(chan->channel, RR_CFGCH_CH);
+
+ switch (chan->band_type) {
+ case RTW89_BAND_2G:
+ default:
+ break;
+ case RTW89_BAND_5G:
+ val |= u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) |
+ u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0);
+ break;
+ case RTW89_BAND_6G:
+ val |= u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) |
+ u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0);
+ break;
+ }
+
+ switch (chan->band_width) {
+ case RTW89_CHANNEL_WIDTH_5:
+ case RTW89_CHANNEL_WIDTH_10:
+ case RTW89_CHANNEL_WIDTH_20:
+ default:
+ break;
+ case RTW89_CHANNEL_WIDTH_40:
+ val |= u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_80:
+ val |= u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_160:
+ val |= u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_320:
+ val |= u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2);
+ break;
+ }
+
+ return val;
+}
+
+static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
+{
+}
+
+static void rtw8922d_btc_init_cfg(struct rtw89_dev *rtwdev)
+{
+ /* offload to firmware */
+}
+
+static void
+rtw8922d_btc_set_wl_txpwr_ctrl(struct rtw89_dev *rtwdev, u32 txpwr_val)
+{
+ u16 ctrl_all_time = u32_get_bits(txpwr_val, GENMASK(15, 0));
+ u16 ctrl_gnt_bt = u32_get_bits(txpwr_val, GENMASK(31, 16));
+
+ switch (ctrl_all_time) {
+ case 0xffff:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_EN, 0x0);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_VAL, 0x0);
+ break;
+ default:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_VAL, ctrl_all_time);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_EN, 0x1);
+ break;
+ }
+
+ switch (ctrl_gnt_bt) {
+ case 0xffff:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_REG_CTRL,
+ B_BE_PWR_BT_EN, 0x0);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_COEX_CTRL,
+ B_BE_PWR_BT_VAL, 0x0);
+ break;
+ default:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_COEX_CTRL,
+ B_BE_PWR_BT_VAL, ctrl_gnt_bt);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_REG_CTRL,
+ B_BE_PWR_BT_EN, 0x1);
+ break;
+ }
+}
+
+static
+s8 rtw8922d_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val)
+{
+ return clamp_t(s8, val, -100, 0) + 100;
+}
+
+static const struct rtw89_btc_rf_trx_para_v9 rtw89_btc_8922d_rf_ul_v9[] = {
+ /*
+ * 0 -> original
+ * 1 -> for BT-connected ACI issue && BTG co-rx
+ * 2 ~ 4 ->reserved for shared-antenna
+ * 5 ~ 8 ->for non-shared-antenna free-run
+ */
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {2, 2}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{ 6, 6}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{13, 13}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{13, 13}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+};
+
+static const struct rtw89_btc_rf_trx_para_v9 rtw89_btc_8922d_rf_dl_v9[] = {
+ /*
+ * 0 -> original
+ * 1 -> for BT-connected ACI issue && BTG co-rx
+ * 2 ~ 4 ->reserved for shared-antenna
+ * 5 ~ 8 ->for non-shared-antenna free-run
+ */
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {2, 2}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+};
+
+static const u8 rtw89_btc_8922d_wl_rssi_thres[BTC_WL_RSSI_THMAX] = {60, 50, 40, 30};
+static const u8 rtw89_btc_8922d_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30, 20};
+
+static const struct rtw89_btc_fbtc_mreg rtw89_btc_8922d_mon_reg[] = {
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe300),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe330),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe334),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe338),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe344),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe348),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe34c),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe350),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe354),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe35c),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe370),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe380),
+};
+
+static
+void rtw8922d_btc_update_bt_cnt(struct rtw89_dev *rtwdev)
+{
+ /* Feature move to firmware */
+}
+
+static
+void rtw8922d_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state)
+{
+ /* Feature move to firmware */
+}
+
+static void rtw8922d_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level)
+{
+ /* Feature move to firmware */
+}
+
+static void rtw8922d_fill_freq_with_ppdu(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu,
+ struct ieee80211_rx_status *status)
+{
+ u8 chan_idx = phy_ppdu->chan_idx;
+ enum nl80211_band band;
+ u8 ch;
+
+ if (chan_idx == 0)
+ return;
+
+ rtw89_decode_chan_idx(rtwdev, chan_idx, &ch, &band);
+ status->freq = ieee80211_channel_to_frequency(ch, band);
+ status->band = band;
+}
+
+static void rtw8922d_query_ppdu(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu,
+ struct ieee80211_rx_status *status)
+{
+ u8 path;
+ u8 *rx_power = phy_ppdu->rssi;
+
+ if (!status->signal)
+ status->signal = RTW89_RSSI_RAW_TO_DBM(max(rx_power[RF_PATH_A],
+ rx_power[RF_PATH_B]));
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ status->chains |= BIT(path);
+ status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]);
+ }
+ if (phy_ppdu->valid)
+ rtw8922d_fill_freq_with_ppdu(rtwdev, phy_ppdu, status);
+}
+
+static void rtw8922d_convert_rpl_to_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu)
+{
+ /* Mapping to BW: 5, 10, 20, 40, 80, 160, 80_80 */
+ static const u8 bw_compensate[] = {0, 0, 0, 6, 12, 18, 0};
+ u8 *rssi = phy_ppdu->rssi;
+ u8 compensate = 0;
+ u8 i;
+
+ if (phy_ppdu->bw_idx < ARRAY_SIZE(bw_compensate))
+ compensate = bw_compensate[phy_ppdu->bw_idx];
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ if (!(phy_ppdu->rx_path_en & BIT(i))) {
+ rssi[i] = 0;
+ phy_ppdu->rpl_path[i] = 0;
+ phy_ppdu->rpl_fd[i] = 0;
+ }
+
+ if (phy_ppdu->ie != RTW89_CCK_PKT && rssi[i])
+ rssi[i] += compensate;
+
+ phy_ppdu->rpl_path[i] = rssi[i];
+ }
+}
+
+static void rtw8922d_phy_rpt_to_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_desc_info *desc_info,
+ struct ieee80211_rx_status *rx_status)
+{
+ if (desc_info->rssi <= 0x1 || (desc_info->rssi >> 2) > MAX_RSSI)
+ return;
+
+ rx_status->signal = (desc_info->rssi >> 2) - MAX_RSSI;
+}
+
+static int rtw8922d_mac_enable_bb_rf(struct rtw89_dev *rtwdev)
+{
+ return 0;
+}
+
+static int rtw8922d_mac_disable_bb_rf(struct rtw89_dev *rtwdev)
+{
+ return 0;
+}
+
+static const struct rtw89_chanctx_listener rtw8922d_chanctx_listener = {
+ .callbacks[RTW89_CHANCTX_CALLBACK_TAS] = rtw89_tas_chanctx_cb,
+};
+
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support rtw_wowlan_stub_8922d = {
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_NET_DETECT,
+ .n_patterns = RTW89_MAX_PATTERN_NUM,
+ .pattern_max_len = RTW89_MAX_PATTERN_SIZE,
+ .pattern_min_len = 1,
+ .max_nd_match_sets = RTW89_SCANOFLD_MAX_SSID,
+};
+#endif
+
+static const struct rtw89_chip_ops rtw8922d_chip_ops = {
+ .enable_bb_rf = rtw8922d_mac_enable_bb_rf,
+ .disable_bb_rf = rtw8922d_mac_disable_bb_rf,
+ .bb_preinit = rtw8922d_bb_preinit,
+ .bb_postinit = rtw8922d_bb_postinit,
+ .bb_reset = rtw8922d_bb_reset,
+ .bb_sethw = rtw8922d_bb_sethw,
+ .read_rf = rtw89_phy_read_rf_v3,
+ .write_rf = rtw89_phy_write_rf_v3,
+ .set_channel = rtw8922d_set_channel,
+ .set_channel_help = rtw8922d_set_channel_help,
+ .read_efuse = rtw8922d_read_efuse,
+ .read_phycap = rtw8922d_read_phycap,
+ .fem_setup = NULL,
+ .rfe_gpio = NULL,
+ .rfk_hw_init = rtw8922d_rfk_hw_init,
+ .rfk_init = rtw8922d_rfk_init,
+ .rfk_init_late = rtw8922d_rfk_init_late,
+ .rfk_channel = rtw8922d_rfk_channel,
+ .rfk_band_changed = rtw8922d_rfk_band_changed,
+ .rfk_scan = rtw8922d_rfk_scan,
+ .rfk_track = rtw8922d_rfk_track,
+ .power_trim = rtw8922d_power_trim,
+ .set_txpwr = rtw8922d_set_txpwr,
+ .set_txpwr_ctrl = rtw8922d_set_txpwr_ctrl,
+ .init_txpwr_unit = NULL,
+ .get_thermal = rtw8922d_get_thermal,
+ .chan_to_rf18_val = rtw8922d_chan_to_rf18_val,
+ .ctrl_btg_bt_rx = rtw8922d_set_gbt_bt_rx_sel,
+ .query_ppdu = rtw8922d_query_ppdu,
+ .convert_rpl_to_rssi = rtw8922d_convert_rpl_to_rssi,
+ .phy_rpt_to_rssi = rtw8922d_phy_rpt_to_rssi,
+ .ctrl_nbtg_bt_tx = rtw8922d_ctrl_nbtg_bt_tx,
+ .cfg_txrx_path = rtw8922d_bb_cfg_txrx_path,
+ .set_txpwr_ul_tb_offset = NULL,
+ .digital_pwr_comp = rtw8922d_digital_pwr_comp,
+ .calc_rx_gain_normal = rtw8922d_calc_rx_gain_normal,
+ .pwr_on_func = rtw8922d_pwr_on_func,
+ .pwr_off_func = rtw8922d_pwr_off_func,
+ .query_rxdesc = rtw89_core_query_rxdesc_v3,
+ .fill_txdesc = rtw89_core_fill_txdesc_v3,
+ .fill_txdesc_fwcmd = rtw89_core_fill_txdesc_fwcmd_v2,
+ .get_ch_dma = {rtw89_core_get_ch_dma_v1,
+ NULL,
+ NULL,},
+ .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path_v2,
+ .mac_cfg_gnt = rtw89_mac_cfg_gnt_v3,
+ .stop_sch_tx = rtw89_mac_stop_sch_tx_v2,
+ .resume_sch_tx = rtw89_mac_resume_sch_tx_v2,
+ .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v3,
+ .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl_be,
+ .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_be,
+ .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_be,
+ .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl_be,
+ .h2c_punctured_cmac_tbl = rtw89_fw_h2c_punctured_cmac_tbl_be,
+ .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v3,
+ .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_v1,
+
+ .btc_set_rfe = rtw8922d_btc_set_rfe,
+ .btc_init_cfg = rtw8922d_btc_init_cfg,
+ .btc_set_wl_pri = NULL,
+ .btc_set_wl_txpwr_ctrl = rtw8922d_btc_set_wl_txpwr_ctrl,
+ .btc_get_bt_rssi = rtw8922d_btc_get_bt_rssi,
+ .btc_update_bt_cnt = rtw8922d_btc_update_bt_cnt,
+ .btc_wl_s1_standby = rtw8922d_btc_wl_s1_standby,
+ .btc_set_wl_rx_gain = rtw8922d_btc_set_wl_rx_gain,
+ .btc_set_policy = rtw89_btc_set_policy_v1,
+};
+
+const struct rtw89_chip_info rtw8922d_chip_info = {
+ .chip_id = RTL8922D,
+ .chip_gen = RTW89_CHIP_BE,
+ .ops = &rtw8922d_chip_ops,
+ .mac_def = &rtw89_mac_gen_be,
+ .phy_def = &rtw89_phy_gen_be_v1,
+ .fw_def = {
+ .fw_basename = RTW8922D_FW_BASENAME,
+ .fw_format_max = RTW8922D_FW_FORMAT_MAX,
+ .fw_b_aid = RTL8922D_AID7102,
+ },
+ .try_ce_fw = false,
+ .bbmcu_nr = 0,
+ .needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_V1,
+ .fw_blacklist = &rtw89_fw_blacklist_default,
+ .fifo_size = 393216,
+ .small_fifo_size = false,
+ .dle_scc_rsvd_size = 0,
+ .max_amsdu_limit = 11000,
+ .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991,
+ .max_eht_mpdu_cap = IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991,
+ .max_tx_agg_num = 128,
+ .max_rx_agg_num = 256,
+ .dis_2g_40m_ul_ofdma = false,
+ .rsvd_ple_ofst = 0x5f800,
+ .hfc_param_ini = {rtw8922d_hfc_param_ini_pcie, NULL, NULL},
+ .dle_mem = {rtw8922d_dle_mem_pcie, NULL, NULL, NULL},
+ .wde_qempty_acq_grpnum = 8,
+ .wde_qempty_mgq_grpsel = 8,
+ .rf_base_addr = {0x3e000, 0x3f000},
+ .thermal_th = {0xac, 0xad},
+ .pwr_on_seq = NULL,
+ .pwr_off_seq = NULL,
+ .bb_table = NULL,
+ .bb_gain_table = NULL,
+ .rf_table = {},
+ .nctl_table = NULL,
+ .nctl_post_table = &rtw8922d_nctl_post_defs_tbl,
+ .dflt_parms = NULL, /* load parm from fw */
+ .rfe_parms_conf = NULL, /* load parm from fw */
+ .chanctx_listener = &rtw8922d_chanctx_listener,
+ .txpwr_factor_bb = 3,
+ .txpwr_factor_rf = 2,
+ .txpwr_factor_mac = 1,
+ .dig_table = NULL,
+ .dig_regs = &rtw8922d_dig_regs,
+ .tssi_dbw_table = NULL,
+ .support_macid_num = 64,
+ .support_link_num = 2,
+ .support_chanctx_num = 2,
+ .support_rnr = true,
+ .support_bands = BIT(NL80211_BAND_2GHZ) |
+ BIT(NL80211_BAND_5GHZ) |
+ BIT(NL80211_BAND_6GHZ),
+ .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
+ .support_unii4 = true,
+ .support_ant_gain = false,
+ .support_tas = false,
+ .support_sar_by_ant = true,
+ .support_noise = false,
+ .ul_tb_waveform_ctrl = false,
+ .ul_tb_pwr_diff = false,
+ .rx_freq_frome_ie = false,
+ .hw_sec_hdr = true,
+ .hw_mgmt_tx_encrypt = true,
+ .hw_tkip_crypto = true,
+ .hw_mlo_bmc_crypto = true,
+ .rf_path_num = 2,
+ .tx_nss = 2,
+ .rx_nss = 2,
+ .acam_num = 128,
+ .bcam_num = 16,
+ .scam_num = 32,
+ .bacam_num = 24,
+ .bacam_dynamic_num = 8,
+ .bacam_ver = RTW89_BACAM_V1,
+ .addrcam_ver = 1,
+ .ppdu_max_usr = 16,
+ .sec_ctrl_efuse_size = 4,
+ .physical_efuse_size = 0x1300,
+ .logical_efuse_size = 0x70000,
+ .limit_efuse_size = 0x40000,
+ .dav_phy_efuse_size = 0,
+ .dav_log_efuse_size = 0,
+ .efuse_blocks = rtw8922d_efuse_blocks,
+ .phycap_addr = 0x1700,
+ .phycap_size = 0x60,
+ .para_ver = 0x3ff,
+ .wlcx_desired = 0x09150000,
+ .scbd = 0x1,
+ .mailbox = 0x1,
+
+ .afh_guard_ch = 6,
+ .wl_rssi_thres = rtw89_btc_8922d_wl_rssi_thres,
+ .bt_rssi_thres = rtw89_btc_8922d_bt_rssi_thres,
+ .rssi_tol = 2,
+ .mon_reg_num = ARRAY_SIZE(rtw89_btc_8922d_mon_reg),
+ .mon_reg = rtw89_btc_8922d_mon_reg,
+ .rf_para_ulink_v9 = rtw89_btc_8922d_rf_ul_v9,
+ .rf_para_dlink_v9 = rtw89_btc_8922d_rf_dl_v9,
+ .rf_para_ulink_num_v9 = ARRAY_SIZE(rtw89_btc_8922d_rf_ul_v9),
+ .rf_para_dlink_num_v9 = ARRAY_SIZE(rtw89_btc_8922d_rf_dl_v9),
+ .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
+ BIT(RTW89_PS_MODE_CLK_GATED) |
+ BIT(RTW89_PS_MODE_PWR_GATED),
+ .low_power_hci_modes = 0,
+ .h2c_cctl_func_id = H2C_FUNC_MAC_CCTLINFO_UD_G7,
+ .hci_func_en_addr = R_BE_HCI_FUNC_EN,
+ .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v3),
+ .txwd_body_size = sizeof(struct rtw89_txwd_body_v2),
+ .txwd_info_size = sizeof(struct rtw89_txwd_info_v2),
+ .h2c_ctrl_reg = R_BE_H2CREG_CTRL,
+ .h2c_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_H2C_DEQ_CNT_MASK >> 8},
+ .h2c_regs = rtw8922d_h2c_regs,
+ .c2h_ctrl_reg = R_BE_C2HREG_CTRL,
+ .c2h_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8},
+ .c2h_regs = rtw8922d_c2h_regs,
+ .page_regs = &rtw8922d_page_regs,
+ .wow_reason_reg = rtw8922d_wow_wakeup_regs,
+ .cfo_src_fd = true,
+ .cfo_hw_comp = true,
+ .dcfo_comp = NULL,
+ .dcfo_comp_sft = 0,
+ .nhm_report = NULL,
+ .nhm_th = NULL,
+ .imr_info = NULL,
+ .imr_dmac_table = &rtw8922d_imr_dmac_table,
+ .imr_cmac_table = &rtw8922d_imr_cmac_table,
+ .rrsr_cfgs = &rtw8922d_rrsr_cfgs,
+ .bss_clr_vld = {R_BSS_CLR_VLD_BE4, B_BSS_CLR_VLD_BE4},
+ .bss_clr_map_reg = R_BSS_CLR_MAP_BE4,
+ .rfkill_init = &rtw8922d_rfkill_regs,
+ .rfkill_get = {R_BE_GPIO_EXT_CTRL, B_BE_GPIO_IN_9},
+ .btc_sb = {{{R_BE_SCOREBOARD_0, R_BE_SCOREBOARD_0_BT_DATA},
+ {R_BE_SCOREBOARD_1, R_BE_SCOREBOARD_1_BT_DATA}}},
+ .dma_ch_mask = BIT(RTW89_DMA_ACH1) | BIT(RTW89_DMA_ACH3) |
+ BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH7) |
+ BIT(RTW89_DMA_B0HI) | BIT(RTW89_DMA_B1HI),
+ .edcca_regs = &rtw8922d_edcca_regs,
+#ifdef CONFIG_PM
+ .wowlan_stub = &rtw_wowlan_stub_8922d,
+#endif
+ .xtal_info = NULL,
+ .default_quirks = BIT(RTW89_QUIRK_THERMAL_PROT_120C),
+};
+EXPORT_SYMBOL(rtw8922d_chip_info);
+
+static const struct rtw89_fw_def rtw8922de_vs_fw_def = {
+ .fw_basename = RTW8922DS_FW_BASENAME,
+ .fw_format_max = RTW8922DS_FW_FORMAT_MAX,
+ .fw_b_aid = RTL8922D_AID7060,
+};
+
+const struct rtw89_chip_variant rtw8922de_vs_variant = {
+ .no_mcs_12_13 = true,
+ .fw_min_ver_code = RTW89_FW_VER_CODE(0, 0, 0, 0),
+ .fw_def_override = &rtw8922de_vs_fw_def,
+};
+EXPORT_SYMBOL(rtw8922de_vs_variant);
+
+MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
+MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11be wireless 8922D driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.h b/drivers/net/wireless/realtek/rtw89/rtw8922d.h
new file mode 100644
index 000000000000..22a7d1cc244f
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#ifndef __RTW89_8922D_H__
+#define __RTW89_8922D_H__
+
+#include "core.h"
+
+#define RF_PATH_NUM_8922D 2
+#define BB_PATH_NUM_8922D 2
+
+struct rtw8922d_tssi_offset {
+ u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM];
+ u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM];
+ u8 rsvd[7];
+ u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM];
+ u8 bw_diff_5g[10];
+} __packed;
+
+struct rtw8922d_tssi_offset_6g {
+ u8 bw40_1s_tssi_6g[TSSI_MCS_6G_CH_GROUP_NUM];
+ u8 rsvd[0xa];
+} __packed;
+
+struct rtw8922d_rx_gain {
+ u8 _2g_ofdm;
+ u8 _2g_cck;
+ u8 _5g_low;
+ u8 _5g_mid;
+ u8 _5g_high;
+} __packed;
+
+struct rtw8922d_rx_gain_6g {
+ u8 _6g_l0;
+ u8 _6g_l1;
+ u8 _6g_m0;
+ u8 _6g_m1;
+ u8 _6g_h0;
+ u8 _6g_h1;
+ u8 _6g_uh0;
+ u8 _6g_uh1;
+} __packed;
+
+struct rtw8922d_efuse {
+ u8 country_code[2];
+ u8 rsvd[0xe];
+ struct rtw8922d_tssi_offset path_a_tssi;
+ struct rtw8922d_tssi_offset path_b_tssi;
+ u8 rsvd1[0x54];
+ u8 channel_plan;
+ u8 xtal_k;
+ u8 rsvd2[0x7];
+ u8 board_info;
+ u8 rsvd3[0x8];
+ u8 rfe_type;
+ u8 rsvd4[2];
+ u8 bt_setting_2;
+ u8 bt_setting_3;
+ u8 rsvd4_2;
+ u8 path_a_therm;
+ u8 path_b_therm;
+ u8 rsvd5[0x2];
+ struct rtw8922d_rx_gain rx_gain_a;
+ struct rtw8922d_rx_gain rx_gain_b;
+ u8 rsvd6[0x18];
+ struct rtw8922d_rx_gain rx_gain_a_2;
+ struct rtw8922d_rx_gain rx_gain_b_2;
+ struct rtw8922d_tssi_offset_6g path_a_tssi_6g;
+ struct rtw8922d_tssi_offset_6g path_b_tssi_6g;
+ struct rtw8922d_tssi_offset_6g path_c_tssi_6g;
+ struct rtw8922d_tssi_offset_6g path_d_tssi_6g;
+ struct rtw8922d_rx_gain_6g rx_gain_6g_a;
+ struct rtw8922d_rx_gain_6g rx_gain_6g_b;
+ u8 rsvd7[0x5a];
+ struct rtw8922d_rx_gain_6g rx_gain_6g_a_2;
+ struct rtw8922d_rx_gain_6g rx_gain_6g_b_2;
+} __packed;
+
+extern const struct rtw89_chip_info rtw8922d_chip_info;
+extern const struct rtw89_chip_variant rtw8922de_vs_variant;
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
new file mode 100644
index 000000000000..4e6a8e88a71e
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#include "chan.h"
+#include "debug.h"
+#include "phy.h"
+#include "reg.h"
+#include "rtw8922d.h"
+#include "rtw8922d_rfk.h"
+
+static const struct rtw89_reg5_def rtw8922d_nctl_post_defs[] = {
+ RTW89_DECL_RFK_WM(0x20c7c, 0x00e00000, 0x1),
+};
+
+RTW89_DECLARE_RFK_TBL(rtw8922d_nctl_post_defs);
+
+static void rtw8922d_tssi_cont_en(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_rf_path path, u8 phy_idx)
+{
+ static const u32 tssi_trk_man[2] = {R_TSSI_EN_P0_BE4,
+ R_TSSI_EN_P0_BE4 + 0x100};
+
+ if (en)
+ rtw89_phy_write32_idx(rtwdev, tssi_trk_man[path],
+ B_TSSI_CONT_EN, 0, phy_idx);
+ else
+ rtw89_phy_write32_idx(rtwdev, tssi_trk_man[path],
+ B_TSSI_CONT_EN, 1, phy_idx);
+}
+
+void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx)
+{
+ if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) {
+ if (phy_idx == RTW89_PHY_0)
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_A, phy_idx);
+ else
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_B, phy_idx);
+ } else {
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_A, phy_idx);
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_B, phy_idx);
+ }
+}
+
+static
+void rtw8922d_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy,
+ const struct rtw89_chan *chan)
+{
+ u8 synpath;
+ u32 rf18;
+
+ synpath = rtw89_phy_get_syn_sel(rtwdev, phy);
+ rf18 = rtw89_chip_chan_to_rf18_val(rtwdev, chan);
+
+ rtw89_write_rf(rtwdev, synpath, RR_RSV1, RFREG_MASK, 0x0);
+ rtw89_write_rf(rtwdev, synpath, RR_MOD, RFREG_MASK, 0x30000);
+ rtw89_write_rf(rtwdev, synpath, RR_CFGCH, RFREG_MASK, rf18);
+ fsleep(400);
+ rtw89_write_rf(rtwdev, synpath, RR_RSV1, RFREG_MASK, 0x1);
+ rtw89_write_rf(rtwdev, synpath, RR_CFGCH_V1, RFREG_MASK, rf18);
+}
+
+void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_ctl_band_ch_bw(rtwdev, phy_idx, chan);
+}
+
+enum _rf_syn_pow {
+ RF_SYN_ON_OFF,
+ RF_SYN_OFF_ON,
+ RF_SYN_ALLON,
+ RF_SYN_ALLOFF,
+};
+
+static void rtw8922d_set_syn01(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "SYN config=%d\n", syn);
+
+ if (syn == RF_SYN_ALLON) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x1);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_ON_OFF) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_OFF_ON) {
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_ALLOFF) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0);
+ }
+}
+
+static void rtw8922d_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx)
+{
+ bool mlo_linking = false;
+
+ if (idx > 2) {
+ rtw89_warn(rtwdev, "[DBCC][ERROR]indx is out of limit!! index(%d)", idx);
+ return;
+ }
+
+ if (mlo_linking) {
+ if (kpath & RF_A) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_SW_SEL, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT_V1, RR_SW_SEL, 0x0);
+ }
+
+ if (kpath & RF_B) {
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_SW_SEL, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT_V1, RR_SW_SEL, 0x0);
+ }
+
+ return;
+ }
+
+ if (kpath & RF_A) {
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_RST, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_IDX0, idx);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_IDX1, idx);
+
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_TXG_SEL, 0x4 | idx);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT_V1, RR_TXG_SEL, 0x4 | idx);
+
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1A_BE4, B_KTBL1_TBL0, idx & BIT(0));
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1A_BE4, B_KTBL1_TBL1, (idx & BIT(1)) >> 1);
+ }
+
+ if (kpath & RF_B) {
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_RST, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_IDX0, idx);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_IDX1, idx);
+
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_TXG_SEL, 0x4 | idx);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT_V1, RR_TXG_SEL, 0x4 | idx);
+
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1B_BE4, B_KTBL1_TBL0, idx & BIT(0));
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1B_BE4, B_KTBL1_TBL1, (idx & BIT(1)) >> 1);
+ }
+}
+
+static u8 rtw8922d_chlk_reload_sel_tbl(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 void rtw8922d_chlk_reload(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan0, *chan1;
+ u8 s0_tbl, s1_tbl;
+
+ switch (rtwdev->mlo_dbcc_mode) {
+ default:
+ case MLO_2_PLUS_0_1RF:
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = chan0;
+ break;
+ case MLO_0_PLUS_2_1RF:
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ chan0 = chan1;
+ break;
+ case MLO_1_PLUS_1_1RF:
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ break;
+ }
+
+ s0_tbl = rtw8922d_chlk_reload_sel_tbl(rtwdev, chan0, 0);
+ s1_tbl = rtw8922d_chlk_reload_sel_tbl(rtwdev, chan1, 1);
+
+ rtw8922d_chlk_ktbl_sel(rtwdev, RF_A, s0_tbl);
+ rtw8922d_chlk_ktbl_sel(rtwdev, RF_B, s1_tbl);
+}
+
+static enum _rf_syn_pow rtw8922d_get_syn_pow(struct rtw89_dev *rtwdev)
+{
+ switch (rtwdev->mlo_dbcc_mode) {
+ case MLO_0_PLUS_2_1RF:
+ return RF_SYN_OFF_ON;
+ case MLO_0_PLUS_2_2RF:
+ case MLO_1_PLUS_1_2RF:
+ case MLO_2_PLUS_0_1RF:
+ case MLO_2_PLUS_0_2RF:
+ case MLO_2_PLUS_2_2RF:
+ case MLO_DBCC_NOT_SUPPORT:
+ default:
+ return RF_SYN_ON_OFF;
+ case MLO_1_PLUS_1_1RF:
+ case DBCC_LEGACY:
+ return RF_SYN_ALLON;
+ }
+}
+
+void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev)
+{
+ enum _rf_syn_pow syn_pow = rtw8922d_get_syn_pow(rtwdev);
+
+ if (!rtwdev->dbcc_en)
+ goto set_rfk_reload;
+
+ rtw8922d_set_syn01(rtwdev, syn_pow);
+
+set_rfk_reload:
+ rtw8922d_chlk_reload(rtwdev);
+}
+
+static void rtw8922d_x4k_setting(struct rtw89_dev *rtwdev)
+{
+ u32 val;
+
+ val = rtw89_read_rf(rtwdev, RF_PATH_A, 0xB9, 0xF000);
+ rtw89_write_rf(rtwdev, RF_PATH_A, 0xB9, 0xF000, val);
+ val = rtw89_read_rf(rtwdev, RF_PATH_B, 0xB9, 0xF000);
+ rtw89_write_rf(rtwdev, RF_PATH_B, 0xB9, 0xF000, val);
+
+ rtw89_write_rf(rtwdev, RF_PATH_A, 0xC2, BIT(19), 0x1);
+ rtw89_write_rf(rtwdev, RF_PATH_B, 0xC2, BIT(19), 0x1);
+}
+
+void rtw8922d_rfk_hw_init(struct rtw89_dev *rtwdev)
+{
+ rtw8922d_x4k_setting(rtwdev);
+}
+
+void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ bool mlo_1_1;
+
+ if (!rtwdev->dbcc_en)
+ return;
+
+ mlo_1_1 = rtw89_is_mlo_1_1(rtwdev);
+ if (mlo_1_1)
+ rtw8922d_set_syn01(rtwdev, RF_SYN_ALLON);
+ else if (phy_idx == RTW89_PHY_0)
+ rtw8922d_set_syn01(rtwdev, RF_SYN_ON_OFF);
+ else
+ rtw8922d_set_syn01(rtwdev, RF_SYN_OFF_ON);
+
+ fsleep(1000);
+}
+
+void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_rfk_mlo_ctrl(rtwdev);
+}
+
+static u8 _get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
+{
+ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1);
+ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x0);
+ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1);
+
+ fsleep(200);
+
+ return rtw89_read_rf(rtwdev, path, RR_TM, RR_TM_VAL_V1);
+}
+
+static void _lck_keep_thermal(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_lck_info *lck = &rtwdev->lck;
+ int path;
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ lck->thermal[path] = _get_thermal(rtwdev, path);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
+ "[LCK] path=%d thermal=0x%x", path, lck->thermal[path]);
+ }
+}
+
+static void _lck(struct rtw89_dev *rtwdev)
+{
+ enum _rf_syn_pow syn_pow = rtw8922d_get_syn_pow(rtwdev);
+ u8 path_mask = 0;
+ u32 tmp18, tmp5;
+ int path;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "[LCK] DO LCK\n");
+
+ if (syn_pow == RF_SYN_ALLON)
+ path_mask = BIT(RF_PATH_A) | BIT(RF_PATH_B);
+ else if (syn_pow == RF_SYN_ON_OFF)
+ path_mask = BIT(RF_PATH_A);
+ else if (syn_pow == RF_SYN_OFF_ON)
+ path_mask = BIT(RF_PATH_B);
+ else
+ return;
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ if (!(path_mask & BIT(path)))
+ continue;
+
+ tmp18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, MASKDWORD);
+ tmp5 = rtw89_read_rf(rtwdev, path, RR_RSV1, MASKDWORD);
+
+ rtw89_write_rf(rtwdev, path, RR_MOD, MASKDWORD, 0x10000);
+ rtw89_write_rf(rtwdev, path, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, path, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1);
+ rtw89_write_rf(rtwdev, path, RR_CFGCH, MASKDWORD, tmp18);
+ rtw89_write_rf(rtwdev, path, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0);
+
+ fsleep(400);
+
+ rtw89_write_rf(rtwdev, path, RR_RSV1, MASKDWORD, tmp5);
+ }
+
+ _lck_keep_thermal(rtwdev);
+}
+
+#define RTW8922D_LCK_TH 16
+void rtw8922d_lck_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_lck_info *lck = &rtwdev->lck;
+ u8 cur_thermal;
+ int delta;
+ int path;
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ cur_thermal = _get_thermal(rtwdev, path);
+ delta = abs((int)cur_thermal - lck->thermal[path]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
+ "[LCK] path=%d current thermal=0x%x delta=0x%x\n",
+ path, cur_thermal, delta);
+
+ if (delta >= RTW8922D_LCK_TH) {
+ _lck(rtwdev);
+ return;
+ }
+ }
+}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
new file mode 100644
index 000000000000..c5bbe0eb972a
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#ifndef __RTW89_8922D_RFK_H__
+#define __RTW89_8922D_RFK_H__
+
+#include "core.h"
+
+extern const struct rtw89_rfk_tbl rtw8922d_nctl_post_defs_tbl;
+
+void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx);
+void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx);
+void rtw8922d_rfk_hw_init(struct rtw89_dev *rtwdev);
+void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev);
+void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
+void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
+void rtw8922d_lck_track(struct rtw89_dev *rtwdev);
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922de.c b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
new file mode 100644
index 000000000000..f144e7fc76de
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "pci.h"
+#include "reg.h"
+#include "rtw8922d.h"
+
+static const struct rtw89_pci_info rtw8922d_pci_info = {
+ .gen_def = &rtw89_pci_gen_be,
+ .isr_def = &rtw89_pci_isr_be_v1,
+ .txbd_trunc_mode = MAC_AX_BD_TRUNC,
+ .rxbd_trunc_mode = MAC_AX_BD_TRUNC,
+ .rxbd_mode = MAC_AX_RXBD_PKT,
+ .tag_mode = MAC_AX_TAG_MULTI,
+ .tx_burst = MAC_AX_TX_BURST_V1_256B,
+ .rx_burst = MAC_AX_RX_BURST_V1_128B,
+ .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS,
+ .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS,
+ .multi_tag_num = MAC_AX_TAG_NUM_8,
+ .lbc_en = MAC_AX_PCIE_ENABLE,
+ .lbc_tmr = MAC_AX_LBC_TMR_2MS,
+ .autok_en = MAC_AX_PCIE_DISABLE,
+ .io_rcy_en = MAC_AX_PCIE_ENABLE,
+ .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF,
+ .rx_ring_eq_is_full = true,
+ .check_rx_tag = true,
+ .no_rxbd_fs = true,
+ .group_bd_addr = true,
+ .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt_v1),
+
+ .init_cfg_reg = R_BE_HAXI_INIT_CFG1,
+ .txhci_en_bit = B_BE_TXDMA_EN,
+ .rxhci_en_bit = B_BE_RXDMA_EN,
+ .rxbd_mode_bit = B_BE_RXQ_RXBD_MODE_MASK,
+ .exp_ctrl_reg = R_BE_HAXI_EXP_CTRL_V1,
+ .max_tag_num_mask = B_BE_MAX_TAG_NUM_MASK,
+ .rxbd_rwptr_clr_reg = R_BE_RXBD_RWPTR_CLR1_V1,
+ .txbd_rwptr_clr2_reg = R_BE_TXBD_RWPTR_CLR1,
+ .dma_io_stop = {R_BE_HAXI_INIT_CFG1, B_BE_STOP_AXI_MST},
+ .dma_stop1 = {R_BE_HAXI_DMA_STOP1, B_BE_TX_STOP1_MASK_V1},
+ .dma_stop2 = {0},
+ .dma_busy1 = {R_BE_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK_BE_V1},
+ .dma_busy2_reg = 0,
+ .dma_busy3_reg = R_BE_HAXI_DMA_BUSY1,
+
+ .rpwm_addr = R_BE_PCIE_HRPWM,
+ .cpwm_addr = R_BE_PCIE_CRPWM,
+ .mit_addr = R_BE_PCIE_MIT_CH_EN,
+ .wp_sel_addr = R_BE_WP_ADDR_H_SEL0_3_V1,
+ .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH1) | BIT(RTW89_TXCH_ACH3) |
+ BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH7) |
+ BIT(RTW89_TXCH_CH9) | BIT(RTW89_TXCH_CH11),
+ .bd_idx_addr_low_power = NULL,
+ .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be_v1,
+ .bd_ram_table = NULL,
+
+ .ltr_set = rtw89_pci_ltr_set_v2,
+ .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1,
+ .parse_rpp = rtw89_pci_parse_rpp_v1,
+ .config_intr_mask = rtw89_pci_config_intr_mask_v3,
+ .enable_intr = rtw89_pci_enable_intr_v3,
+ .disable_intr = rtw89_pci_disable_intr_v3,
+ .recognize_intrs = rtw89_pci_recognize_intrs_v3,
+
+ .ssid_quirks = NULL,
+};
+
+static const struct rtw89_driver_info rtw89_8922de_vs_info = {
+ .chip = &rtw8922d_chip_info,
+ .variant = &rtw8922de_vs_variant,
+ .quirks = NULL,
+ .bus = {
+ .pci = &rtw8922d_pci_info,
+ },
+};
+
+static const struct rtw89_driver_info rtw89_8922de_info = {
+ .chip = &rtw8922d_chip_info,
+ .variant = NULL,
+ .quirks = NULL,
+ .bus = {
+ .pci = &rtw8922d_pci_info,
+ },
+};
+
+static const struct pci_device_id rtw89_8922de_id_table[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x892D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_vs_info,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x882D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_vs_info,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x895D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_info,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(pci, rtw89_8922de_id_table);
+
+static struct pci_driver rtw89_8922de_driver = {
+ .name = "rtw89_8922de",
+ .id_table = rtw89_8922de_id_table,
+ .probe = rtw89_pci_probe,
+ .remove = rtw89_pci_remove,
+ .driver.pm = &rtw89_pm_ops_be,
+ .err_handler = &rtw89_pci_err_handler,
+};
+module_pci_driver(rtw89_8922de_driver);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11be wireless 8922DE/8922DE-VS driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c
index f91e66133b30..a507ce1fcd63 100644
--- a/drivers/net/wireless/realtek/rtw89/ser.c
+++ b/drivers/net/wireless/realtek/rtw89/ser.c
@@ -498,6 +498,7 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt)
switch (evt) {
case SER_EV_STATE_IN:
wiphy_lock(wiphy);
+ ser->sw_cnt.l1++;
wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work);
wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work);
wiphy_unlock(wiphy);
@@ -588,7 +589,7 @@ static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf,
start_page = start_addr / mem_page_size;
residue = start_addr % mem_page_size;
- base_addr = mac->mem_base_addrs[sel];
+ base_addr = rtw89_mac_mem_base_addrs(rtwdev, sel);
base_addr += start_page * mem_page_size;
while (cnt < len) {
@@ -730,6 +731,7 @@ static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt)
switch (evt) {
case SER_EV_STATE_IN:
wiphy_lock(rtwdev->hw->wiphy);
+ ser->sw_cnt.l2++;
ser_l2_reset_st_pre_hdl(ser);
wiphy_unlock(rtwdev->hw->wiphy);
diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
index da1b7ce8089e..767a95f759b1 100644
--- a/drivers/net/wireless/realtek/rtw89/usb.c
+++ b/drivers/net/wireless/realtek/rtw89/usb.c
@@ -161,16 +161,24 @@ static u32
rtw89_usb_ops_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
u8 txch)
{
+ struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
+ int inflight;
+
if (txch == RTW89_TXCH_CH12)
return 1;
- return 42; /* TODO some kind of calculation? */
+ inflight = atomic_read(&rtwusb->tx_inflight[txch]);
+ if (inflight >= RTW89_USB_MAX_TX_URBS_PER_CH)
+ return 0;
+
+ return RTW89_USB_MAX_TX_URBS_PER_CH - inflight;
}
static void rtw89_usb_write_port_complete(struct urb *urb)
{
struct rtw89_usb_tx_ctrl_block *txcb = urb->context;
struct rtw89_dev *rtwdev = txcb->rtwdev;
+ struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
struct ieee80211_tx_info *info;
struct rtw89_txwd_body *txdesc;
struct sk_buff *skb;
@@ -229,6 +237,8 @@ static void rtw89_usb_write_port_complete(struct urb *urb)
break;
}
+ atomic_dec(&rtwusb->tx_inflight[txcb->txch]);
+
kfree(txcb);
}
@@ -306,9 +316,13 @@ static void rtw89_usb_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
skb_queue_tail(&txcb->tx_ack_queue, skb);
+ atomic_inc(&rtwusb->tx_inflight[txch]);
+
ret = rtw89_usb_write_port(rtwdev, txch, skb->data, skb->len,
txcb);
if (ret) {
+ atomic_dec(&rtwusb->tx_inflight[txch]);
+
if (ret != -ENODEV)
rtw89_err(rtwdev, "write port txch %d failed: %d\n",
txch, ret);
@@ -408,11 +422,14 @@ static int rtw89_usb_ops_tx_write(struct rtw89_dev *rtwdev,
static void rtw89_usb_rx_handler(struct work_struct *work)
{
struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_work);
+ const struct rtw89_usb_info *info = rtwusb->info;
struct rtw89_dev *rtwdev = rtwusb->rtwdev;
struct rtw89_rx_desc_info desc_info;
+ s32 aligned_offset, remaining;
struct sk_buff *rx_skb;
struct sk_buff *skb;
u32 pkt_offset;
+ u8 *pkt_ptr;
int limit;
for (limit = 0; limit < 200; limit++) {
@@ -425,23 +442,38 @@ static void rtw89_usb_rx_handler(struct work_struct *work)
goto free_or_reuse;
}
- memset(&desc_info, 0, sizeof(desc_info));
- rtw89_chip_query_rxdesc(rtwdev, &desc_info, rx_skb->data, 0);
+ pkt_ptr = rx_skb->data;
+ remaining = rx_skb->len;
- skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
- if (!skb) {
- rtw89_debug(rtwdev, RTW89_DBG_HCI,
- "failed to allocate RX skb of size %u\n",
- desc_info.pkt_size);
- goto free_or_reuse;
- }
+ do {
+ memset(&desc_info, 0, sizeof(desc_info));
+ rtw89_chip_query_rxdesc(rtwdev, &desc_info, pkt_ptr, 0);
- pkt_offset = desc_info.offset + desc_info.rxd_len;
+ pkt_offset = desc_info.offset + desc_info.rxd_len;
+ if (remaining < (pkt_offset + desc_info.pkt_size)) {
+ rtw89_debug(rtwdev, RTW89_DBG_HCI,
+ "Failed to get remaining RX pkt %u > %u\n",
+ pkt_offset + desc_info.pkt_size, remaining);
+ goto free_or_reuse;
+ }
+
+ skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
+ if (!skb) {
+ rtw89_debug(rtwdev, RTW89_DBG_HCI,
+ "failed to allocate RX skb of size %u\n",
+ desc_info.pkt_size);
+ goto free_or_reuse;
+ }
- skb_put_data(skb, rx_skb->data + pkt_offset,
- desc_info.pkt_size);
+ skb_put_data(skb, pkt_ptr + pkt_offset, desc_info.pkt_size);
+ rtw89_core_rx(rtwdev, &desc_info, skb);
- rtw89_core_rx(rtwdev, &desc_info, skb);
+ /* next frame */
+ pkt_offset += desc_info.pkt_size;
+ aligned_offset = ALIGN(pkt_offset, info->rx_agg_alignment);
+ pkt_ptr += aligned_offset;
+ remaining -= aligned_offset;
+ } while (remaining > 0);
free_or_reuse:
if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM)
@@ -666,8 +698,10 @@ static void rtw89_usb_init_tx(struct rtw89_dev *rtwdev)
struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
int i;
- for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
+ for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) {
skb_queue_head_init(&rtwusb->tx_queue[i]);
+ atomic_set(&rtwusb->tx_inflight[i], 0);
+ }
}
static void rtw89_usb_deinit_tx(struct rtw89_dev *rtwdev)
@@ -745,6 +779,44 @@ static int rtw89_usb_ops_mac_pre_deinit(struct rtw89_dev *rtwdev)
return 0; /* Nothing to do. */
}
+static void rtw89_usb_rx_agg_cfg_v1(struct rtw89_dev *rtwdev)
+{
+ const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
+ FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 0) |
+ FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
+ FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_4K, 5);
+
+ rtw89_write32(rtwdev, R_AX_RXAGG_0, rxagg_0);
+}
+
+static void rtw89_usb_rx_agg_cfg_v2(struct rtw89_dev *rtwdev)
+{
+ const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
+ FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 255) |
+ FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
+ FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_1K, 20);
+
+ rtw89_write32(rtwdev, R_AX_RXAGG_0_V1, rxagg_0);
+ rtw89_write32(rtwdev, R_AX_RXAGG_1_V1, 0x1F);
+}
+
+static void rtw89_usb_rx_agg_cfg(struct rtw89_dev *rtwdev)
+{
+ switch (rtwdev->chip->chip_id) {
+ case RTL8851B:
+ case RTL8852A:
+ case RTL8852B:
+ rtw89_usb_rx_agg_cfg_v1(rtwdev);
+ break;
+ case RTL8852C:
+ rtw89_usb_rx_agg_cfg_v2(rtwdev);
+ break;
+ default:
+ rtw89_warn(rtwdev, "%s: USB RX agg not support\n", __func__);
+ return;
+ }
+}
+
static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
{
struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
@@ -773,6 +845,8 @@ static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
rtw89_write8(rtwdev, info->usb_endpoint_2 + 1, NUMP);
}
+ rtw89_usb_rx_agg_cfg(rtwdev);
+
return 0;
}
@@ -935,7 +1009,7 @@ static int rtw89_usb_intf_init(struct rtw89_dev *rtwdev,
if (!rtwusb->vendor_req_buf)
return -ENOMEM;
- rtwusb->udev = usb_get_dev(interface_to_usbdev(intf));
+ rtwusb->udev = interface_to_usbdev(intf);
usb_set_intfdata(intf, rtwdev->hw);
@@ -949,7 +1023,6 @@ static void rtw89_usb_intf_deinit(struct rtw89_dev *rtwdev,
{
struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
- usb_put_dev(rtwusb->udev);
kfree(rtwusb->vendor_req_buf);
usb_set_intfdata(intf, NULL);
}
diff --git a/drivers/net/wireless/realtek/rtw89/usb.h b/drivers/net/wireless/realtek/rtw89/usb.h
index 203ec8e993e9..507f61f58ed9 100644
--- a/drivers/net/wireless/realtek/rtw89/usb.h
+++ b/drivers/net/wireless/realtek/rtw89/usb.h
@@ -20,6 +20,19 @@
#define RTW89_MAX_ENDPOINT_NUM 9
#define RTW89_MAX_BULKOUT_NUM 7
+#define R_AX_RXAGG_0_V1 0x6000
+#define B_AX_RXAGG_0_EN BIT(31)
+#define B_AX_RXAGG_0_NUM_TH GENMASK(23, 16)
+#define B_AX_RXAGG_0_TIME_32US_TH GENMASK(15, 8)
+#define B_AX_RXAGG_0_BUF_SZ_1K GENMASK(7, 0)
+
+#define R_AX_RXAGG_1_V1 0x6004
+
+#define R_AX_RXAGG_0 0x8900
+#define B_AX_RXAGG_0_BUF_SZ_4K GENMASK(7, 0)
+
+#define RTW89_USB_MAX_TX_URBS_PER_CH 128
+
struct rtw89_usb_info {
u32 usb_host_request_2;
u32 usb_wlan0_1;
@@ -27,6 +40,7 @@ struct rtw89_usb_info {
u32 usb3_mac_npi_config_intf_0;
u32 usb_endpoint_0;
u32 usb_endpoint_2;
+ u8 rx_agg_alignment;
u8 bulkout_id[RTW89_DMA_CH_NUM];
};
@@ -63,6 +77,7 @@ struct rtw89_usb {
struct usb_anchor tx_submitted;
struct sk_buff_head tx_queue[RTW89_TXCH_NUM];
+ atomic_t tx_inflight[RTW89_TXCH_NUM];
};
static inline struct rtw89_usb *rtw89_usb_priv(struct rtw89_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw89/util.h b/drivers/net/wireless/realtek/rtw89/util.h
index bd08495301e4..c16e7a7f8bc9 100644
--- a/drivers/net/wireless/realtek/rtw89/util.h
+++ b/drivers/net/wireless/realtek/rtw89/util.h
@@ -6,6 +6,13 @@
#include "core.h"
+#define RTW89_KEY_PN_0 GENMASK_ULL(7, 0)
+#define RTW89_KEY_PN_1 GENMASK_ULL(15, 8)
+#define RTW89_KEY_PN_2 GENMASK_ULL(23, 16)
+#define RTW89_KEY_PN_3 GENMASK_ULL(31, 24)
+#define RTW89_KEY_PN_4 GENMASK_ULL(39, 32)
+#define RTW89_KEY_PN_5 GENMASK_ULL(47, 40)
+
#define rtw89_iterate_vifs_bh(rtwdev, iterator, data) \
ieee80211_iterate_active_interfaces_atomic((rtwdev)->hw, \
IEEE80211_IFACE_ITER_NORMAL, iterator, data)
@@ -73,6 +80,16 @@ static inline void ether_addr_copy_mask(u8 *dst, const u8 *src, u8 mask)
}
}
+static inline void ccmp_hdr2pn(s64 *pn, const u8 *hdr)
+{
+ *pn = u64_encode_bits(hdr[0], RTW89_KEY_PN_0) |
+ u64_encode_bits(hdr[1], RTW89_KEY_PN_1) |
+ u64_encode_bits(hdr[4], RTW89_KEY_PN_2) |
+ u64_encode_bits(hdr[5], RTW89_KEY_PN_3) |
+ u64_encode_bits(hdr[6], RTW89_KEY_PN_4) |
+ u64_encode_bits(hdr[7], RTW89_KEY_PN_5);
+}
+
s32 rtw89_linear_to_db_quarter(u64 val);
s32 rtw89_linear_to_db(u64 val);
u64 rtw89_db_quarter_to_linear(s32 db);
diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
index 368e08826f1e..8dadd8df4fc6 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.c
+++ b/drivers/net/wireless/realtek/rtw89/wow.c
@@ -1741,6 +1741,8 @@ static int rtw89_wow_disable(struct rtw89_dev *rtwdev)
rtw89_wow_leave_ps(rtwdev, false);
+ rtw89_core_tid_rx_stats_reset(rtwdev);
+
ret = rtw89_wow_fw_stop(rtwdev);
if (ret) {
rtw89_err(rtwdev, "wow: failed to swap to normal fw\n");
diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h
index 71e07f482174..d7e67632efeb 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.h
+++ b/drivers/net/wireless/realtek/rtw89/wow.h
@@ -8,13 +8,6 @@
#define RTW89_KEY_TKIP_PN_IV16 GENMASK_ULL(15, 0)
#define RTW89_KEY_TKIP_PN_IV32 GENMASK_ULL(47, 16)
-#define RTW89_KEY_PN_0 GENMASK_ULL(7, 0)
-#define RTW89_KEY_PN_1 GENMASK_ULL(15, 8)
-#define RTW89_KEY_PN_2 GENMASK_ULL(23, 16)
-#define RTW89_KEY_PN_3 GENMASK_ULL(31, 24)
-#define RTW89_KEY_PN_4 GENMASK_ULL(39, 32)
-#define RTW89_KEY_PN_5 GENMASK_ULL(47, 40)
-
#define RTW89_IGTK_IPN_0 GENMASK_ULL(7, 0)
#define RTW89_IGTK_IPN_1 GENMASK_ULL(15, 8)
#define RTW89_IGTK_IPN_2 GENMASK_ULL(23, 16)
diff --git a/include/linux/ieee80211-nan.h b/include/linux/ieee80211-nan.h
index ebf28ea651f9..455033955e54 100644
--- a/include/linux/ieee80211-nan.h
+++ b/include/linux/ieee80211-nan.h
@@ -37,4 +37,41 @@
#define NAN_DEV_CAPA_NDPE_SUPPORTED 0x08
#define NAN_DEV_CAPA_S3_SUPPORTED 0x10
+/* NAN attributes, as defined in Wi-Fi Aware (TM) specification 4.0 Table 42 */
+#define NAN_ATTR_MASTER_INDICATION 0x00
+#define NAN_ATTR_CLUSTER_INFO 0x01
+
+struct ieee80211_nan_attr {
+ u8 attr;
+ __le16 length;
+ u8 data[];
+} __packed;
+
+struct ieee80211_nan_master_indication {
+ u8 master_pref;
+ u8 random_factor;
+} __packed;
+
+struct ieee80211_nan_anchor_master_info {
+ union {
+ __le64 master_rank;
+ struct {
+ u8 master_addr[ETH_ALEN];
+ u8 random_factor;
+ u8 master_pref;
+ } __packed;
+ } __packed;
+ u8 hop_count;
+ __le32 ambtt;
+} __packed;
+
+#define for_each_nan_attr(_attr, _data, _datalen) \
+ for (_attr = (const struct ieee80211_nan_attr *)(_data); \
+ (const u8 *)(_data) + (_datalen) - (const u8 *)_attr >= \
+ (int)sizeof(*_attr) && \
+ (const u8 *)(_data) + (_datalen) - (const u8 *)_attr >= \
+ (int)sizeof(*_attr) + le16_to_cpu(_attr->length); \
+ _attr = (const struct ieee80211_nan_attr *) \
+ (_attr->data + le16_to_cpu(_attr->length)))
+
#endif /* LINUX_IEEE80211_NAN_H */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index b5d649db123f..23f9df9be837 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1921,6 +1921,11 @@ enum ieee80211_radio_measurement_actioncode {
#define PMK_MAX_LEN 64
#define SAE_PASSWORD_MAX_LEN 128
+#define MICHAEL_MIC_LEN 8
+
+void michael_mic(const u8 *key, struct ieee80211_hdr *hdr,
+ const u8 *data, size_t data_len, u8 *mic);
+
/* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */
enum ieee80211_pub_actioncode {
WLAN_PUB_ACTION_20_40_BSS_COEX = 0,
@@ -2240,6 +2245,7 @@ struct ieee80211_multiple_bssid_configuration {
#define WLAN_OUI_WFA 0x506f9a
#define WLAN_OUI_TYPE_WFA_P2P 9
+#define WLAN_OUI_TYPE_WFA_NAN 0x13
#define WLAN_OUI_TYPE_WFA_DPP 0x1A
#define WLAN_OUI_MICROSOFT 0x0050f2
#define WLAN_OUI_TYPE_MICROSOFT_WPA 1
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 72395895dc0e..40cb20d9309c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -365,6 +365,7 @@ struct ieee80211_vif_chanctx_switch {
* @BSS_CHANGED_MLD_VALID_LINKS: MLD valid links status changed.
* @BSS_CHANGED_MLD_TTLM: negotiated TID to link mapping was changed
* @BSS_CHANGED_TPE: transmit power envelope changed
+ * @BSS_CHANGED_NAN_LOCAL_SCHED: NAN local schedule changed (NAN mode only)
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -402,6 +403,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_MLD_VALID_LINKS = BIT_ULL(33),
BSS_CHANGED_MLD_TTLM = BIT_ULL(34),
BSS_CHANGED_TPE = BIT_ULL(35),
+ BSS_CHANGED_NAN_LOCAL_SCHED = BIT_ULL(36),
/* when adding here, make sure to change ieee80211_reconfig */
};
@@ -866,6 +868,74 @@ struct ieee80211_bss_conf {
u8 s1g_long_beacon_period;
};
+#define IEEE80211_NAN_MAX_CHANNELS 3
+
+/**
+ * struct ieee80211_nan_channel - NAN channel information
+ *
+ * @chanreq: channel request for this NAN channel. Even though this chanreq::ap
+ * is irrelevant for NAN, still store it for convenience - some functions
+ * require it as an argument.
+ * @needed_rx_chains: number of RX chains needed for this NAN channel
+ * @chanctx_conf: chanctx_conf assigned to this NAN channel.
+ * If a local channel is being ULWed (because we needed this chanctx for
+ * something else), the local NAN channel that used this chanctx,
+ * will have this pointer set to %NULL.
+ * A peer NAN channel should never have this pointer set to %NULL.
+ * @channel_entry: the Channel Entry blob as defined in Wi-Fi Aware
+ * (TM) 4.0 specification Table 100 (Channel Entry format for the NAN
+ * Availability attribute).
+ */
+struct ieee80211_nan_channel {
+ struct ieee80211_chan_req chanreq;
+ u8 needed_rx_chains;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ u8 channel_entry[6];
+};
+
+/**
+ * struct ieee80211_nan_peer_map - NAN peer schedule map
+ *
+ * This stores a single map from a peer's schedule. Each peer can have
+ * multiple maps.
+ *
+ * @map_id: the map ID from the peer schedule, %CFG80211_NAN_INVALID_MAP_ID
+ * if unused
+ * @slots: mapping of time slots to channel configurations in the schedule's
+ * channels array
+ */
+struct ieee80211_nan_peer_map {
+ u8 map_id;
+ struct ieee80211_nan_channel *slots[CFG80211_NAN_SCHED_NUM_TIME_SLOTS];
+};
+
+/**
+ * struct ieee80211_nan_peer_sched - NAN peer schedule
+ *
+ * This stores the complete schedule from a peer. Contains peer-level
+ * parameters and an array of schedule maps.
+ *
+ * @seq_id: the sequence ID from the peer schedule
+ * @committed_dw: committed DW as published by the peer
+ * @max_chan_switch: maximum channel switch time in microseconds
+ * @init_ulw: initial ULWs as published by the peer (copied)
+ * @ulw_size: number of bytes in @init_ulw
+ * @maps: array of peer schedule maps. Invalid slots have map_id set to
+ * %CFG80211_NAN_INVALID_MAP_ID.
+ * @n_channels: number of valid channel entries in @channels
+ * @channels: flexible array of negotiated peer channels for this schedule
+ */
+struct ieee80211_nan_peer_sched {
+ u8 seq_id;
+ u16 committed_dw;
+ u16 max_chan_switch;
+ const u8 *init_ulw;
+ u16 ulw_size;
+ struct ieee80211_nan_peer_map maps[CFG80211_NAN_MAX_PEER_MAPS];
+ u8 n_channels;
+ struct ieee80211_nan_channel channels[] __counted_by(n_channels);
+};
+
/**
* enum mac80211_tx_info_flags - flags to describe transmission information/status
*
@@ -1917,6 +1987,8 @@ enum ieee80211_offload_flags {
IEEE80211_OFFLOAD_DECAP_ENABLED = BIT(2),
};
+#define IEEE80211_NAN_AVAIL_BLOB_MAX_LEN 54
+
/**
* struct ieee80211_eml_params - EHT Operating mode notification parameters
*
@@ -1943,6 +2015,32 @@ struct ieee80211_eml_params {
};
/**
+ * struct ieee80211_nan_sched_cfg - NAN schedule configuration
+ * @channels: array of NAN channels. A channel entry is in use if
+ * channels[i].chanreq.oper.chan is not NULL.
+ * @schedule: NAN local schedule - mapping of each 16TU time slot to
+ * the NAN channel on which the radio will operate. NULL if unscheduled.
+ * @avail_blob: NAN Availability attribute blob.
+ * @avail_blob_len: length of the @avail_blob in bytes.
+ * @deferred: indicates that the driver should notify peers before applying the
+ * new NAN schedule, and apply the new schedule the second NAN Slot
+ * boundary after it notified the peers, as defined in Wi-Fi Aware (TM) 4.0
+ * specification, section 5.2.2.
+ * The driver must call ieee80211_nan_sched_update_done() after the
+ * schedule has been applied.
+ * If a HW restart happened while a deferred schedule update was pending,
+ * mac80211 will reconfigure the deferred schedule (and wait for the driver
+ * to notify that the schedule has been applied).
+ */
+struct ieee80211_nan_sched_cfg {
+ struct ieee80211_nan_channel channels[IEEE80211_NAN_MAX_CHANNELS];
+ struct ieee80211_nan_channel *schedule[CFG80211_NAN_SCHED_NUM_TIME_SLOTS];
+ u8 avail_blob[IEEE80211_NAN_AVAIL_BLOB_MAX_LEN];
+ u16 avail_blob_len;
+ bool deferred;
+};
+
+/**
* struct ieee80211_vif_cfg - interface configuration
* @assoc: association status
* @ibss_joined: indicates whether this station is part of an IBSS or not
@@ -1970,6 +2068,7 @@ struct ieee80211_eml_params {
* your driver/device needs to do.
* @ap_addr: AP MLD address, or BSSID for non-MLO connections
* (station mode only)
+ * @nan_sched: NAN schedule parameters. &struct ieee80211_nan_sched_cfg
*/
struct ieee80211_vif_cfg {
/* association related data */
@@ -1988,6 +2087,8 @@ struct ieee80211_vif_cfg {
bool s1g;
bool idle;
u8 ap_addr[ETH_ALEN] __aligned(2);
+ /* Protected by the wiphy mutex */
+ struct ieee80211_nan_sched_cfg nan_sched;
};
#define IEEE80211_TTLM_NUM_TIDS 8
@@ -2074,6 +2175,7 @@ enum ieee80211_neg_ttlm_res {
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void \*).
* @txq: the multicast data TX queue
+ * @txq_mgmt: the mgmt frame TX queue, currently only exists for NAN devices
* @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
* &enum ieee80211_offload_flags.
*/
@@ -2092,6 +2194,7 @@ struct ieee80211_vif {
u8 hw_queue[IEEE80211_NUM_ACS];
struct ieee80211_txq *txq;
+ struct ieee80211_txq *txq_mgmt;
netdev_features_t netdev_features;
u32 driver_flags;
@@ -2477,11 +2580,15 @@ struct ieee80211_sta_aggregates {
* @uhr_cap: UHR capabilities of this STA
* @s1g_cap: S1G capabilities of this STA
* @agg: per-link data for multi-link aggregation
- * @bandwidth: current bandwidth the station can receive with
+ * @bandwidth: current bandwidth the station can receive with.
+ * This is the minimum between the peer's capabilities and our own
+ * operating channel width; Invalid for NAN since that is operating on
+ * multiple channels.
* @rx_nss: in HT/VHT, the maximum number of spatial streams the
* station can receive at the moment, changed by operating mode
* notifications and capabilities. The value is only valid after
- * the station moves to associated state.
+ * the station moves to associated state. Invalid for NAN since it
+ * operates on multiple configurations of rx_nss.
* @txpwr: the station tx power configuration
*
*/
@@ -2563,6 +2670,8 @@ struct ieee80211_link_sta {
* @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.
+ * @nmi: For NDI stations, pointer to the NMI station of the peer.
+ * @nan_sched: NAN peer schedule for this station. Valid only for NMI stations.
*/
struct ieee80211_sta {
u8 addr[ETH_ALEN] __aligned(2);
@@ -2591,6 +2700,11 @@ struct ieee80211_sta {
struct ieee80211_link_sta deflink;
struct ieee80211_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
+ struct ieee80211_sta __rcu *nmi;
+
+ /* should only be accessed with the wiphy mutex held */
+ struct ieee80211_nan_peer_sched *nan_sched;
+
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
};
@@ -2824,6 +2938,8 @@ struct ieee80211_txq {
* station has a unique address, i.e. each station entry can be identified
* by just its MAC address; this prevents, for example, the same station
* from connecting to two virtual AP interfaces at the same time.
+ * Note that this doesn't apply for NAN, in which the peer's NMI address
+ * can be equal to its NDI address.
*
* @IEEE80211_HW_SUPPORTS_REORDERING_BUFFER: Hardware (or driver) manages the
* reordering buffer internally, guaranteeing mac80211 receives frames in
@@ -4490,6 +4606,12 @@ struct ieee80211_prep_tx_info {
* @del_nan_func: Remove a NAN function. The driver must call
* ieee80211_nan_func_terminated() with
* NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal.
+ * @nan_peer_sched_changed: Notifies the driver that the peer NAN schedule
+ * has changed. The new schedule is available via sta->nan_sched.
+ * Note that the channel_entry blob might not match the actual chandef
+ * since the bandwidth of the chandef is the minimum of the local and peer
+ * bandwidth. It is the driver responsibility to remove the peer schedule
+ * when the NMI station is removed.
* @can_aggregate_in_amsdu: Called in order to determine if HW supports
* aggregating two specific frames in the same A-MSDU. The relation
* between the skbs should be symmetric and transitive. Note that while
@@ -4895,6 +5017,8 @@ struct ieee80211_ops {
void (*del_nan_func)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u8 instance_id);
+ int (*nan_peer_sched_changed)(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta);
bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw,
struct sk_buff *head,
struct sk_buff *skb);
@@ -7392,6 +7516,24 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
int ieee80211_ave_rssi(struct ieee80211_vif *vif, int link_id);
/**
+ * ieee80211_calculate_rx_timestamp - calculate timestamp in frame
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @status: RX status
+ * @mpdu_len: total MPDU length (including FCS)
+ * @mpdu_offset: offset into MPDU to calculate timestamp at
+ *
+ * This function calculates the RX timestamp at the given MPDU offset, taking
+ * into account what the RX timestamp was. An offset of 0 will just normalize
+ * the timestamp to TSF at beginning of MPDU reception.
+ *
+ * Returns: the calculated timestamp
+ */
+u64 ieee80211_calculate_rx_timestamp(struct ieee80211_hw *hw,
+ struct ieee80211_rx_status *status,
+ unsigned int mpdu_len,
+ unsigned int mpdu_offset);
+
+/**
* ieee80211_report_wowlan_wakeup - report WoWLAN wakeup
* @vif: virtual interface
* @wakeup: wakeup reason(s)
@@ -7737,6 +7879,17 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif,
gfp_t gfp);
/**
+ * ieee80211_nan_sched_update_done - notify that NAN schedule update is done
+ *
+ * This function is called by the driver to notify mac80211 that the NAN
+ * schedule update has been applied.
+ * Must be called with wiphy mutex held. May sleep.
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ */
+void ieee80211_nan_sched_update_done(struct ieee80211_vif *vif);
+
+/**
* ieee80211_calc_rx_airtime - calculate estimated transmission airtime for RX.
*
* This function calculates the estimated airtime usage of a frame based on the
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index b0e392eb7753..20c3135b73ea 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -18,7 +18,6 @@ mac80211-y := \
iface.o \
link.o \
rate.o \
- michael.o \
tkip.o \
aes_cmac.o \
aes_gmac.o \
@@ -36,7 +35,7 @@ mac80211-y := \
tdls.o \
ocb.o \
airtime.o \
- eht.o uhr.o
+ eht.o uhr.o nan.o
mac80211-$(CONFIG_MAC80211_LEDS) += led.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 01d927b88264..4833b46770b6 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -641,7 +641,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_AP &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_NAN_DATA)
return -EINVAL;
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b6163dcc7e92..7b77d57c9f96 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -281,10 +281,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
if (params->use_4addr == ifmgd->use_4addr)
return 0;
- /* FIXME: no support for 4-addr MLO yet */
- if (ieee80211_vif_is_mld(&sdata->vif))
- return -EOPNOTSUPP;
-
sdata->u.mgd.use_4addr = params->use_4addr;
if (!ifmgd->associated)
return 0;
@@ -502,12 +498,15 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;
- spin_lock_bh(&sdata->u.nan.func_lock);
+ if (WARN_ON(wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE))
+ return -EOPNOTSUPP;
+
+ spin_lock_bh(&sdata->u.nan.de.func_lock);
- ret = idr_alloc(&sdata->u.nan.function_inst_ids,
+ ret = idr_alloc(&sdata->u.nan.de.function_inst_ids,
nan_func, 1, sdata->local->hw.max_nan_de_entries + 1,
GFP_ATOMIC);
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
if (ret < 0)
return ret;
@@ -518,10 +517,10 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
ret = drv_add_nan_func(sdata->local, sdata, nan_func);
if (ret) {
- spin_lock_bh(&sdata->u.nan.func_lock);
- idr_remove(&sdata->u.nan.function_inst_ids,
+ spin_lock_bh(&sdata->u.nan.de.func_lock);
+ idr_remove(&sdata->u.nan.de.function_inst_ids,
nan_func->instance_id);
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
}
return ret;
@@ -534,9 +533,9 @@ ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_func *func;
int id;
- lockdep_assert_held(&sdata->u.nan.func_lock);
+ lockdep_assert_held(&sdata->u.nan.de.func_lock);
- idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) {
+ idr_for_each_entry(&sdata->u.nan.de.function_inst_ids, func, id) {
if (func->cookie == cookie)
return func;
}
@@ -555,13 +554,16 @@ static void ieee80211_del_nan_func(struct wiphy *wiphy,
!ieee80211_sdata_running(sdata))
return;
- spin_lock_bh(&sdata->u.nan.func_lock);
+ if (WARN_ON(wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE))
+ return;
+
+ spin_lock_bh(&sdata->u.nan.de.func_lock);
func = ieee80211_find_nan_func_by_cookie(sdata, cookie);
if (func)
instance_id = func->instance_id;
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
if (instance_id)
drv_del_nan_func(sdata->local, sdata, instance_id);
@@ -696,6 +698,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_NAN:
+ case NL80211_IFTYPE_NAN_DATA:
/* Keys without a station are used for TX only */
if (sta && test_sta_flag(sta, WLAN_STA_MFP))
key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
@@ -712,13 +716,11 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev,
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_P2P_DEVICE:
- case NL80211_IFTYPE_NAN:
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_OCB:
- case NL80211_IFTYPE_NAN_DATA:
/* shouldn't happen */
WARN_ON_ONCE(1);
break;
@@ -2071,7 +2073,7 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
enum sta_link_apply_mode mode,
struct link_station_parameters *params)
{
- struct ieee80211_supported_band *sband;
+ struct ieee80211_supported_band *sband = NULL;
struct ieee80211_sub_if_data *sdata = sta->sdata;
u32 link_id = params->link_id < 0 ? 0 : params->link_id;
struct ieee80211_link_data *link =
@@ -2079,6 +2081,9 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
struct link_sta_info *link_sta =
rcu_dereference_protected(sta->link[link_id],
lockdep_is_held(&local->hw.wiphy->mtx));
+ const struct ieee80211_sta_ht_cap *own_ht_cap;
+ const struct ieee80211_sta_vht_cap *own_vht_cap;
+ const struct ieee80211_sta_he_cap *own_he_cap;
bool changes = params->link_mac ||
params->txpwr_set ||
params->supported_rates_len ||
@@ -2108,10 +2113,27 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
if (!link || !link_sta)
return -EINVAL;
- sband = ieee80211_get_link_sband(link);
- if (!sband)
+ /*
+ * We should not have any changes in NDI station, its capabilities are
+ * copied from the NMI sta
+ */
+ if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN_DATA))
return -EINVAL;
+ if (sdata->vif.type == NL80211_IFTYPE_NAN) {
+ own_ht_cap = &local->hw.wiphy->nan_capa.phy.ht;
+ own_vht_cap = &local->hw.wiphy->nan_capa.phy.vht;
+ own_he_cap = &local->hw.wiphy->nan_capa.phy.he;
+ } else {
+ sband = ieee80211_get_link_sband(link);
+ if (!sband)
+ return -EINVAL;
+
+ own_ht_cap = &sband->ht_cap;
+ own_vht_cap = &sband->vht_cap;
+ own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif);
+ }
+
if (params->link_mac) {
if (mode == STA_LINK_MODE_NEW) {
memcpy(link_sta->addr, params->link_mac, ETH_ALEN);
@@ -2133,6 +2155,27 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
return ret;
}
+ if (sdata->vif.type == NL80211_IFTYPE_NAN) {
+ static const u8 all_ofdm_rates[] = {
+ 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
+ };
+
+ /* Set the same supported_rates for all bands */
+ for (int i = 0; i < NUM_NL80211_BANDS; i++) {
+ struct ieee80211_supported_band *tmp =
+ sdata->local->hw.wiphy->bands[i];
+
+ if ((i != NL80211_BAND_2GHZ && i != NL80211_BAND_5GHZ) ||
+ !tmp)
+ continue;
+
+ if (!ieee80211_parse_bitrates(tmp, all_ofdm_rates,
+ sizeof(all_ofdm_rates),
+ &link_sta->pub->supp_rates[i]))
+ return -EINVAL;
+ }
+ }
+
if (params->supported_rates &&
params->supported_rates_len &&
!ieee80211_parse_bitrates(sband, params->supported_rates,
@@ -2141,22 +2184,24 @@ static int sta_link_apply_parameters(struct ieee80211_local *local,
return -EINVAL;
if (params->ht_capa)
- ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, &sband->ht_cap,
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, own_ht_cap,
params->ht_capa, link_sta);
/* VHT can override some HT caps such as the A-MSDU max length */
if (params->vht_capa)
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
- &sband->vht_cap,
+ own_vht_cap,
params->vht_capa, NULL,
link_sta);
if (params->he_capa)
- ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband,
- (void *)params->he_capa,
- params->he_capa_len,
- (void *)params->he_6ghz_capa,
- link_sta);
+ _ieee80211_he_cap_ie_to_sta_he_cap(sdata,
+ own_he_cap,
+ (void *)params->he_capa,
+ params->he_capa_len,
+ (sband && sband->band == NL80211_BAND_6GHZ) ?
+ (void *)params->he_6ghz_capa : NULL,
+ link_sta);
if (params->he_capa && params->eht_capa)
ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
@@ -2343,6 +2388,32 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (params->airtime_weight)
sta->airtime_weight = params->airtime_weight;
+ if (params->nmi_mac) {
+ struct ieee80211_sub_if_data *nmi =
+ rcu_dereference_wiphy(local->hw.wiphy,
+ sdata->u.nan_data.nmi);
+ struct sta_info *nmi_sta;
+
+ if (WARN_ON(!nmi))
+ return -EINVAL;
+
+ nmi_sta = sta_info_get(nmi, params->nmi_mac);
+ if (!nmi_sta)
+ return -ENOENT;
+ rcu_assign_pointer(sta->sta.nmi, &nmi_sta->sta);
+
+ /* For NAN_DATA stations, copy capabilities from the NMI station */
+ if (!nmi_sta->deflink.pub->ht_cap.ht_supported)
+ return -EINVAL;
+
+ sta->deflink.pub->ht_cap = nmi_sta->deflink.pub->ht_cap;
+ sta->deflink.pub->vht_cap = nmi_sta->deflink.pub->vht_cap;
+ sta->deflink.pub->he_cap = nmi_sta->deflink.pub->he_cap;
+ memcpy(&sta->deflink.pub->supp_rates,
+ &nmi_sta->deflink.pub->supp_rates,
+ sizeof(sta->deflink.pub->supp_rates));
+ }
+
/* set the STA state after all sta info from usermode has been set */
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
@@ -2427,7 +2498,15 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct wireless_dev *wdev,
test_sta_flag(sta, WLAN_STA_ASSOC))
rate_control_rate_init_all_links(sta);
- return sta_info_insert(sta);
+ err = sta_info_insert(sta);
+
+ /*
+ * ieee80211_nan_update_ndi_carrier was called from sta_apply_parameters,
+ * but then we did not have the STA in the list.
+ */
+ if (!err && sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
+ ieee80211_nan_update_ndi_carrier(sta->sdata);
+ return err;
}
static int ieee80211_del_station(struct wiphy *wiphy, struct wireless_dev *wdev,
@@ -2444,6 +2523,65 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct wireless_dev *wdev,
return 0;
}
+static int ieee80211_set_sta_4addr(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta)
+{
+ struct ieee80211_vif *vif = &sdata->vif;
+ struct wiphy *wiphy = local->hw.wiphy;
+ struct ieee80211_sub_if_data *master;
+ struct ieee80211_bss_conf *link_conf;
+ struct wireless_dev *wdev;
+ unsigned long master_iter;
+ int link_id;
+ int err;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+ if (sdata->u.vlan.sta)
+ return -EBUSY;
+
+ wdev = &sdata->wdev;
+ master = container_of(sdata->bss,
+ struct ieee80211_sub_if_data,
+ u.ap);
+
+ if (sta->sta.valid_links) {
+ u16 sta_links = sta->sta.valid_links;
+ u16 new_links = master->vif.valid_links & sta_links;
+ u16 orig_links = wdev->valid_links;
+
+ wdev->valid_links = new_links;
+
+ err = ieee80211_vif_set_links(sdata, new_links, 0);
+ if (err) {
+ wdev->valid_links = orig_links;
+ return err;
+ }
+
+ master_iter = master->vif.valid_links;
+
+ for_each_set_bit(link_id, &master_iter,
+ IEEE80211_MLD_MAX_NUM_LINKS) {
+ if (!(sta_links & BIT(link_id))) {
+ eth_zero_addr(wdev->links[link_id].addr);
+ } else {
+ link_conf = wiphy_dereference(wiphy,
+ vif->link_conf[link_id]);
+
+ ether_addr_copy(wdev->links[link_id].addr,
+ link_conf->bssid);
+ }
+ }
+ }
+
+ rcu_assign_pointer(sdata->u.vlan.sta, sta);
+ __ieee80211_check_fast_rx_iface(sdata);
+ drv_sta_set_4addr(local, sta->sdata, &sta->sta, true);
+
+ return 0;
+}
+
static int ieee80211_change_station(struct wiphy *wiphy,
struct wireless_dev *wdev, const u8 *mac,
struct station_parameters *params)
@@ -2488,6 +2626,12 @@ static int ieee80211_change_station(struct wiphy *wiphy,
else
statype = CFG80211_STA_AP_CLIENT_UNASSOC;
break;
+ case NL80211_IFTYPE_NAN:
+ statype = CFG80211_STA_NAN_MGMT;
+ break;
+ case NL80211_IFTYPE_NAN_DATA:
+ statype = CFG80211_STA_NAN_DATA;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -2500,12 +2644,10 @@ static int ieee80211_change_station(struct wiphy *wiphy,
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (params->vlan->ieee80211_ptr->use_4addr) {
- if (vlansdata->u.vlan.sta)
- return -EBUSY;
+ err = ieee80211_set_sta_4addr(local, vlansdata, sta);
+ if (err)
+ return err;
- rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
- __ieee80211_check_fast_rx_iface(vlansdata);
- drv_sta_set_4addr(local, sta->sdata, &sta->sta, true);
}
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
@@ -2526,6 +2668,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
}
}
+ /* NAN capabilties should not change */
+ if (statype == CFG80211_STA_NAN_DATA &&
+ sta->deflink.pub->ht_cap.ht_supported &&
+ (params->link_sta_params.ht_capa ||
+ params->link_sta_params.vht_capa ||
+ params->link_sta_params.he_capa))
+ return -EINVAL;
+
err = sta_apply_parameters(local, sta, params);
if (err)
return err;
@@ -4888,18 +5038,22 @@ void ieee80211_nan_func_terminated(struct ieee80211_vif *vif,
if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
return;
- spin_lock_bh(&sdata->u.nan.func_lock);
+ if (WARN_ON(sdata->local->hw.wiphy->nan_capa.flags &
+ WIPHY_NAN_FLAGS_USERSPACE_DE))
+ return;
+
+ spin_lock_bh(&sdata->u.nan.de.func_lock);
- func = idr_find(&sdata->u.nan.function_inst_ids, inst_id);
+ func = idr_find(&sdata->u.nan.de.function_inst_ids, inst_id);
if (WARN_ON(!func)) {
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
return;
}
cookie = func->cookie;
- idr_remove(&sdata->u.nan.function_inst_ids, inst_id);
+ idr_remove(&sdata->u.nan.de.function_inst_ids, inst_id);
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
cfg80211_free_nan_func(func);
@@ -4918,16 +5072,20 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif,
if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
return;
- spin_lock_bh(&sdata->u.nan.func_lock);
+ if (WARN_ON(sdata->local->hw.wiphy->nan_capa.flags &
+ WIPHY_NAN_FLAGS_USERSPACE_DE))
+ return;
+
+ spin_lock_bh(&sdata->u.nan.de.func_lock);
- func = idr_find(&sdata->u.nan.function_inst_ids, match->inst_id);
+ func = idr_find(&sdata->u.nan.de.function_inst_ids, match->inst_id);
if (WARN_ON(!func)) {
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
return;
}
match->cookie = func->cookie;
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
cfg80211_nan_match(ieee80211_vif_to_wdev(vif), match, gfp);
}
@@ -5423,9 +5581,6 @@ static int ieee80211_add_intf_link(struct wiphy *wiphy,
lockdep_assert_wiphy(sdata->local->hw.wiphy);
- if (wdev->use_4addr)
- return -EOPNOTSUPP;
-
return ieee80211_vif_set_links(sdata, wdev->valid_links, 0);
}
@@ -5580,6 +5735,30 @@ ieee80211_set_epcs(struct wiphy *wiphy, struct net_device *dev, bool enable)
return ieee80211_mgd_set_epcs(sdata, enable);
}
+static int
+ieee80211_set_local_nan_sched(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_local_sched *sched)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+ lockdep_assert_wiphy(wiphy);
+
+ return ieee80211_nan_set_local_sched(sdata, sched);
+}
+
+static int
+ieee80211_set_peer_nan_sched(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct cfg80211_nan_peer_sched *sched)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+ lockdep_assert_wiphy(sdata->local->hw.wiphy);
+
+ return ieee80211_nan_set_peer_sched(sdata, sched);
+}
+
const struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -5696,4 +5875,6 @@ const struct cfg80211_ops mac80211_config_ops = {
.get_radio_mask = ieee80211_get_radio_mask,
.assoc_ml_reconf = ieee80211_assoc_ml_reconf,
.set_epcs = ieee80211_set_epcs,
+ .nan_set_local_sched = ieee80211_set_local_nan_sched,
+ .nan_set_peer_sched = ieee80211_set_peer_nan_sched,
};
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index dd99fdc1ea9d..fda692316f08 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -16,6 +16,8 @@ struct ieee80211_chanctx_user_iter {
struct ieee80211_chan_req *chanreq;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_link_data *link;
+ struct ieee80211_nan_channel *nan_channel;
+ int nan_channel_next_idx;
enum nl80211_iftype iftype;
bool reserved, radar_required, done;
enum {
@@ -31,20 +33,38 @@ enum ieee80211_chanctx_iter_type {
CHANCTX_ITER_ASSIGNED,
};
-static void ieee80211_chanctx_user_iter_next(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx,
- struct ieee80211_chanctx_user_iter *iter,
- enum ieee80211_chanctx_iter_type type,
- bool start)
+static bool
+ieee80211_chanctx_user_iter_next_nan_channel(struct ieee80211_chanctx *ctx,
+ struct ieee80211_chanctx_user_iter *iter)
{
- lockdep_assert_wiphy(local->hw.wiphy);
+ /* Start from the next index after current position */
+ for (int i = iter->nan_channel_next_idx;
+ i < ARRAY_SIZE(iter->sdata->vif.cfg.nan_sched.channels); i++) {
+ struct ieee80211_nan_channel *nan_channel =
+ &iter->sdata->vif.cfg.nan_sched.channels[i];
- if (start) {
- memset(iter, 0, sizeof(*iter));
- goto next_interface;
+ if (!nan_channel->chanreq.oper.chan)
+ continue;
+
+ if (nan_channel->chanctx_conf != &ctx->conf)
+ continue;
+
+ iter->nan_channel = nan_channel;
+ iter->nan_channel_next_idx = i + 1;
+ iter->chanreq = &nan_channel->chanreq;
+ iter->link = NULL;
+ iter->reserved = false;
+ iter->radar_required = false;
+ return true;
}
+ return false;
+}
-next_link:
+static bool
+ieee80211_chanctx_user_iter_next_link(struct ieee80211_chanctx *ctx,
+ struct ieee80211_chanctx_user_iter *iter,
+ enum ieee80211_chanctx_iter_type type)
+{
for (int link_id = iter->link ? iter->link->link_id : 0;
link_id < ARRAY_SIZE(iter->sdata->link);
link_id++) {
@@ -64,7 +84,7 @@ next_link:
iter->reserved = false;
iter->radar_required = link->radar_required;
iter->chanreq = &link->conf->chanreq;
- return;
+ return true;
}
fallthrough;
case CHANCTX_ITER_POS_RESERVED:
@@ -77,7 +97,7 @@ next_link:
link->reserved_radar_required;
iter->chanreq = &link->reserved;
- return;
+ return true;
}
fallthrough;
case CHANCTX_ITER_POS_DONE:
@@ -85,6 +105,33 @@ next_link:
continue;
}
}
+ return false;
+}
+
+static void
+ieee80211_chanctx_user_iter_next(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx,
+ struct ieee80211_chanctx_user_iter *iter,
+ enum ieee80211_chanctx_iter_type type,
+ bool start)
+{
+ bool found;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+ if (start) {
+ memset(iter, 0, sizeof(*iter));
+ goto next_interface;
+ }
+
+next_user:
+ if (iter->iftype == NL80211_IFTYPE_NAN)
+ found = ieee80211_chanctx_user_iter_next_nan_channel(ctx, iter);
+ else
+ found = ieee80211_chanctx_user_iter_next_link(ctx, iter, type);
+
+ if (found)
+ return;
next_interface:
/* next (or first) interface */
@@ -97,10 +144,18 @@ next_interface:
if (iter->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
continue;
+ /* NAN channels don't reserve channel context */
+ if (iter->sdata->vif.type == NL80211_IFTYPE_NAN &&
+ type == CHANCTX_ITER_RESERVED)
+ continue;
+
+ iter->nan_channel = NULL;
iter->link = NULL;
- iter->per_link = CHANCTX_ITER_POS_ASSIGNED;
iter->iftype = iter->sdata->vif.type;
- goto next_link;
+ iter->chanreq = NULL;
+ iter->per_link = CHANCTX_ITER_POS_ASSIGNED;
+ iter->nan_channel_next_idx = 0;
+ goto next_user;
}
iter->done = true;
@@ -133,8 +188,8 @@ next_interface:
CHANCTX_ITER_ALL, \
false))
-static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx)
+int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx)
{
struct ieee80211_chanctx_user_iter iter;
int num = 0;
@@ -321,7 +376,7 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
lockdep_assert_wiphy(local->hw.wiphy);
for_each_chanctx_user_assigned(local, ctx, &iter) {
- if (iter.link->reserved_chanctx)
+ if (iter.link && iter.link->reserved_chanctx)
continue;
comp_def = ieee80211_chanreq_compatible(iter.chanreq,
@@ -480,7 +535,6 @@ ieee80211_get_width_of_link(struct ieee80211_link_data *link)
case NL80211_IFTYPE_AP_VLAN:
return ieee80211_get_max_required_bw(link);
case NL80211_IFTYPE_P2P_DEVICE:
- case NL80211_IFTYPE_NAN:
break;
case NL80211_IFTYPE_MONITOR:
WARN_ON_ONCE(!ieee80211_hw_check(&local->hw,
@@ -495,6 +549,7 @@ ieee80211_get_width_of_link(struct ieee80211_link_data *link)
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_NAN:
case NL80211_IFTYPE_NAN_DATA:
WARN_ON_ONCE(1);
break;
@@ -505,6 +560,18 @@ ieee80211_get_width_of_link(struct ieee80211_link_data *link)
}
static enum nl80211_chan_width
+ieee80211_get_width_of_chanctx_user(struct ieee80211_chanctx_user_iter *iter)
+{
+ if (iter->link)
+ return ieee80211_get_width_of_link(iter->link);
+
+ if (WARN_ON_ONCE(!iter->nan_channel || iter->reserved))
+ return NL80211_CHAN_WIDTH_20_NOHT;
+
+ return iter->nan_channel->chanreq.oper.width;
+}
+
+static enum nl80211_chan_width
ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx,
struct ieee80211_link_data *rsvd_for,
@@ -521,7 +588,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
/* When this is true we only care about the reserving links */
if (check_reserved) {
for_each_chanctx_user_reserved(local, ctx, &iter) {
- width = ieee80211_get_width_of_link(iter.link);
+ width = ieee80211_get_width_of_chanctx_user(&iter);
max_bw = max(max_bw, width);
}
goto check_monitor;
@@ -529,7 +596,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
/* Consider all assigned links */
for_each_chanctx_user_assigned(local, ctx, &iter) {
- width = ieee80211_get_width_of_link(iter.link);
+ width = ieee80211_get_width_of_chanctx_user(&iter);
max_bw = max(max_bw, width);
}
@@ -943,7 +1010,10 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
kfree(ctx);
return ERR_PTR(err);
}
- /* We ignored a driver error, see _ieee80211_set_active_links */
+ /*
+ * We ignored a driver error, see _ieee80211_set_active_links and/or
+ * ieee80211_nan_set_local_sched
+ */
WARN_ON_ONCE(err && !local->in_reconfig);
list_add_rcu(&ctx->list, &local->chanctx_list);
@@ -964,9 +1034,9 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local,
ieee80211_remove_wbrf(local, &ctx->conf.def);
}
-static void ieee80211_free_chanctx(struct ieee80211_local *local,
- struct ieee80211_chanctx *ctx,
- bool skip_idle_recalc)
+void ieee80211_free_chanctx(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx,
+ bool skip_idle_recalc)
{
lockdep_assert_wiphy(local->hw.wiphy);
@@ -1161,6 +1231,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
+ case NL80211_IFTYPE_NAN:
break;
default:
continue;
@@ -1171,6 +1242,15 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
break;
}
+ if (iter.nan_channel) {
+ rx_chains_dynamic = rx_chains_static =
+ iter.nan_channel->needed_rx_chains;
+ break;
+ }
+
+ if (!iter.link)
+ continue;
+
switch (iter.link->smps_mode) {
default:
WARN_ONCE(1, "Invalid SMPS mode %d\n",
@@ -1241,6 +1321,10 @@ __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
struct ieee80211_bss_conf *vlan_conf;
+ if (vlan->vif.valid_links &&
+ !(vlan->vif.valid_links & BIT(link_id)))
+ continue;
+
vlan_conf = wiphy_dereference(local->hw.wiphy,
vlan->vif.link_conf[link_id]);
if (WARN_ON(!vlan_conf))
@@ -1484,6 +1568,10 @@ ieee80211_link_update_chanreq(struct ieee80211_link_data *link,
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
struct ieee80211_bss_conf *vlan_conf;
+ if (vlan->vif.valid_links &&
+ !(vlan->vif.valid_links & BIT(link_id)))
+ continue;
+
vlan_conf = wiphy_dereference(sdata->local->hw.wiphy,
vlan->vif.link_conf[link_id]);
if (WARN_ON(!vlan_conf))
@@ -1779,7 +1867,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
for_each_chanctx_user_assigned(local, ctx->replace_ctx, &iter) {
n_assigned++;
- if (iter.link->reserved_chanctx) {
+ if (iter.link && iter.link->reserved_chanctx) {
n_reserved++;
if (iter.link->reserved_ready)
n_ready++;
@@ -2035,7 +2123,7 @@ void __ieee80211_link_release_channel(struct ieee80211_link_data *link,
ieee80211_vif_use_reserved_switch(local);
}
-static struct ieee80211_chanctx *
+struct ieee80211_chanctx *
ieee80211_find_or_create_chanctx(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_chan_req *chanreq,
enum ieee80211_chanctx_mode mode,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 51bf3c7822a7..f1c0b87fddd5 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1793,4 +1793,25 @@ static inline int drv_set_eml_op_mode(struct ieee80211_sub_if_data *sdata,
return ret;
}
+static inline int
+drv_nan_peer_sched_changed(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta)
+{
+ int ret;
+
+ might_sleep();
+ lockdep_assert_wiphy(local->hw.wiphy);
+ check_sdata_in_driver(sdata);
+
+ if (!local->ops->nan_peer_sched_changed)
+ return -EOPNOTSUPP;
+
+ trace_drv_nan_peer_sched_changed(local, sdata, &sta->sta);
+ ret = local->ops->nan_peer_sched_changed(&local->hw, &sta->sta);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/he.c b/net/mac80211/he.c
index 93e0342cff4f..a3e16a5bec22 100644
--- a/net/mac80211/he.c
+++ b/net/mac80211/he.c
@@ -127,6 +127,10 @@ _ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
if (!he_cap_ie || !own_he_cap_ptr || !own_he_cap_ptr->has_he)
return;
+ /* NDI station are using the capabilities from the NMI station */
+ if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_NAN_DATA))
+ return;
+
own_he_cap = *own_he_cap_ptr;
/* Make sure size is OK */
@@ -156,7 +160,8 @@ _ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
he_cap->has_he = true;
link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta);
- link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
+ if (sdata->vif.type != NL80211_IFTYPE_NAN)
+ link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
if (he_6ghz_capa)
ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 410e2354f33a..97719298e038 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -154,6 +154,10 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
if (!ht_cap_ie || !own_cap_ptr->ht_supported)
goto apply;
+ /* NDI station are using the capabilities from the NMI station */
+ if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_NAN_DATA))
+ return 0;
+
ht_cap.ht_supported = true;
own_cap = *own_cap_ptr;
@@ -254,10 +258,17 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
rcu_read_lock();
link_conf = rcu_dereference(sdata->vif.link_conf[link_sta->link_id]);
- if (WARN_ON(!link_conf))
+ if (WARN_ON(!link_conf)) {
width = NL80211_CHAN_WIDTH_20_NOHT;
- else
+ } else if (sdata->vif.type == NL80211_IFTYPE_NAN ||
+ sdata->vif.type == NL80211_IFTYPE_NAN_DATA) {
+ /* In NAN, link_sta->bandwidth is invalid since NAN operates on
+ * multiple channels. Just take the maximum.
+ */
+ width = NL80211_CHAN_WIDTH_320;
+ } else {
width = link_conf->chanreq.oper.width;
+ }
switch (width) {
default:
@@ -285,7 +296,9 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
- sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+ sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ sta->sdata->vif.type == NL80211_IFTYPE_NAN ||
+ sta->sdata->vif.type == NL80211_IFTYPE_NAN_DATA) {
enum ieee80211_smps_mode smps_mode;
switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 1e1ab25d9d8d..97292ff51475 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1127,7 +1127,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (ieee80211_have_rx_timestamp(rx_status)) {
/* time when timestamp field was received */
rx_timestamp =
- ieee80211_calculate_rx_timestamp(local, rx_status,
+ ieee80211_calculate_rx_timestamp(&local->hw, rx_status,
len + FCS_LEN, 24);
} else {
/*
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index bacb49ad2817..2a693406294b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -987,16 +987,33 @@ struct ieee80211_if_mntr {
*
* @conf: current NAN configuration
* @started: true iff NAN is started
- * @func_lock: lock for @func_inst_ids
- * @function_inst_ids: a bitmap of available instance_id's
+ * @de: Discovery Engine state (only valid if !WIPHY_NAN_FLAGS_USERSPACE_DE)
+ * @de.func_lock: lock for @de.function_inst_ids
+ * @de.function_inst_ids: a bitmap of available instance_id's
+ * @removed_channels: bitmap of channels that should be removed from the NAN
+ * schedule once the deferred schedule update is completed.
*/
struct ieee80211_if_nan {
struct cfg80211_nan_conf conf;
bool started;
- /* protects function_inst_ids */
- spinlock_t func_lock;
- struct idr function_inst_ids;
+ struct {
+ /* protects function_inst_ids */
+ spinlock_t func_lock;
+ struct idr function_inst_ids;
+ } de;
+
+ DECLARE_BITMAP(removed_channels, IEEE80211_NAN_MAX_CHANNELS);
+};
+
+/**
+ * struct ieee80211_if_nan_data - NAN data path state
+ *
+ * @nmi: pointer to the NAN management interface sdata. Used for data path,
+ * hence RCU.
+ */
+struct ieee80211_if_nan_data {
+ struct ieee80211_sub_if_data __rcu *nmi;
};
struct ieee80211_link_data_managed {
@@ -1197,6 +1214,7 @@ struct ieee80211_sub_if_data {
struct ieee80211_if_ocb ocb;
struct ieee80211_if_mntr mntr;
struct ieee80211_if_nan nan;
+ struct ieee80211_if_nan_data nan_data;
} u;
struct ieee80211_link_data deflink;
@@ -1922,10 +1940,6 @@ ieee80211_vif_get_num_mcast_if(struct ieee80211_sub_if_data *sdata)
return -1;
}
-u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
- struct ieee80211_rx_status *status,
- unsigned int mpdu_len,
- unsigned int mpdu_offset);
int ieee80211_hw_config(struct ieee80211_local *local, int radio_idx,
u32 changed);
int ieee80211_hw_conf_chan(struct ieee80211_local *local);
@@ -2025,6 +2039,14 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata,
u64 *changed);
+/* NAN code */
+int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_nan_local_sched *sched);
+int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_nan_peer_sched *sched);
+void ieee80211_nan_free_peer_sched(struct ieee80211_nan_peer_sched *sched);
+void ieee80211_nan_update_ndi_carrier(struct ieee80211_sub_if_data *ndi_sdata);
+
/* scan/BSS handling */
void ieee80211_scan_work(struct wiphy *wiphy, struct wiphy_work *work);
int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
@@ -2813,7 +2835,17 @@ int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx);
u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev);
void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx);
-
+struct ieee80211_chanctx *
+ieee80211_find_or_create_chanctx(struct ieee80211_sub_if_data *sdata,
+ const struct ieee80211_chan_req *chanreq,
+ enum ieee80211_chanctx_mode mode,
+ bool assign_on_failure,
+ bool *reused_ctx);
+void ieee80211_free_chanctx(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx,
+ bool skip_idle_recalc);
+int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
+ struct ieee80211_chanctx *ctx);
/* TDLS */
int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, int link_id,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 125897717a4c..95b779c4d627 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -362,6 +362,17 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
return -EBUSY;
/*
+ * A NAN DATA interface is correlated to the NAN
+ * (management) one
+ */
+ if (iftype == NL80211_IFTYPE_NAN_DATA &&
+ nsdata->vif.type == NL80211_IFTYPE_NAN) {
+ if (!nsdata->u.nan.started)
+ return -EINVAL;
+ rcu_assign_pointer(sdata->u.nan_data.nmi, nsdata);
+ }
+
+ /*
* Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution
* cannot work properly if both are in the same IBSS.
@@ -398,13 +409,6 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
nsdata->vif.type))
return -ENOTUNIQ;
- /* No support for VLAN with MLO yet */
- if (iftype == NL80211_IFTYPE_AP_VLAN &&
- sdata->wdev.use_4addr &&
- nsdata->vif.type == NL80211_IFTYPE_AP &&
- nsdata->vif.valid_links)
- return -EOPNOTSUPP;
-
/*
* can only add VLANs to enabled APs
*/
@@ -475,6 +479,7 @@ static int ieee80211_open(struct net_device *dev)
static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down)
{
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_sub_if_data *iter;
unsigned long flags;
struct sk_buff_head freeq;
struct sk_buff *skb, *tmp;
@@ -523,12 +528,14 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
* (because if we remove a STA after ops->remove_interface()
* the driver will have removed the vif info already!)
*
- * For AP_VLANs stations may exist since there's nothing else that
- * would have removed them, but in other modes there shouldn't
- * be any stations.
+ * For AP_VLANs, NAN and NAN_DATA stations may exist since there's
+ * nothing else that would have removed them, but in other modes there
+ * shouldn't be any stations.
*/
flushed = sta_info_flush(sdata, -1);
- WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN && flushed > 0);
+ WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_NAN &&
+ sdata->vif.type != NL80211_IFTYPE_NAN_DATA && flushed > 0);
/* don't count this interface for allmulti while it is down */
if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
@@ -621,17 +628,30 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
}
break;
case NL80211_IFTYPE_NAN:
+ /* Check if any open NAN_DATA interfaces */
+ list_for_each_entry(iter, &local->interfaces, list) {
+ WARN_ON(iter->vif.type == NL80211_IFTYPE_NAN_DATA &&
+ ieee80211_sdata_running(iter));
+ }
+
/* clean all the functions */
- spin_lock_bh(&sdata->u.nan.func_lock);
+ if (!(local->hw.wiphy->nan_capa.flags &
+ WIPHY_NAN_FLAGS_USERSPACE_DE)) {
+ spin_lock_bh(&sdata->u.nan.de.func_lock);
+
+ idr_for_each_entry(&sdata->u.nan.de.function_inst_ids,
+ func, i) {
+ idr_remove(&sdata->u.nan.de.function_inst_ids, i);
+ cfg80211_free_nan_func(func);
+ }
+ idr_destroy(&sdata->u.nan.de.function_inst_ids);
- idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) {
- idr_remove(&sdata->u.nan.function_inst_ids, i);
- cfg80211_free_nan_func(func);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
}
- idr_destroy(&sdata->u.nan.function_inst_ids);
-
- spin_unlock_bh(&sdata->u.nan.func_lock);
break;
+ case NL80211_IFTYPE_NAN_DATA:
+ RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
+ fallthrough;
default:
wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
/*
@@ -682,6 +702,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
if (sdata->vif.txq)
ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq));
+ if (sdata->vif.txq_mgmt)
+ ieee80211_txq_purge(sdata->local,
+ to_txq_info(sdata->vif.txq_mgmt));
+
sdata->bss = NULL;
if (local->open_count == 0)
@@ -878,6 +902,14 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
ieee80211_vif_clear_links(sdata);
ieee80211_link_stop(&sdata->deflink);
+
+ if (sdata->vif.type == NL80211_IFTYPE_NAN) {
+ struct ieee80211_nan_sched_cfg *nan_sched =
+ &sdata->vif.cfg.nan_sched;
+
+ for (int i = 0; i < ARRAY_SIZE(nan_sched->channels); i++)
+ WARN_ON(nan_sched->channels[i].chanreq.oper.chan);
+ }
}
static void ieee80211_uninit(struct net_device *dev)
@@ -1368,9 +1400,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_OCB:
case NL80211_IFTYPE_NAN:
- case NL80211_IFTYPE_NAN_DATA:
/* no special treatment */
break;
+ case NL80211_IFTYPE_NAN_DATA:
+ if (WARN_ON(!rcu_access_pointer(sdata->u.nan_data.nmi)))
+ return -ENOLINK;
+ break;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
@@ -1388,8 +1423,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
res = drv_start(local);
if (res) {
/*
- * no need to worry about AP_VLAN cleanup since in that
- * case we can't have open_count == 0
+ * no need to worry about AP_VLAN/NAN_DATA cleanup since
+ * in that case we can't have open_count == 0
*/
return res;
}
@@ -1508,6 +1543,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_OCB:
+ case NL80211_IFTYPE_NAN_DATA:
netif_carrier_off(dev);
break;
case NL80211_IFTYPE_P2P_DEVICE:
@@ -1554,6 +1590,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
err_stop:
if (!local->open_count)
drv_stop(local, false);
+ if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
+ RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
list_del(&sdata->u.vlan.list);
/* Might not be initialized yet, but it is harmless */
@@ -1938,8 +1976,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
MONITOR_FLAG_OTHER_BSS;
break;
case NL80211_IFTYPE_NAN:
- idr_init(&sdata->u.nan.function_inst_ids);
- spin_lock_init(&sdata->u.nan.func_lock);
+ if (!(sdata->local->hw.wiphy->nan_capa.flags &
+ WIPHY_NAN_FLAGS_USERSPACE_DE)) {
+ idr_init(&sdata->u.nan.de.function_inst_ids);
+ spin_lock_init(&sdata->u.nan.de.func_lock);
+ }
sdata->vif.bss_conf.bssid = sdata->vif.addr;
break;
case NL80211_IFTYPE_AP_VLAN:
@@ -2223,10 +2264,16 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
lockdep_assert_wiphy(local->hw.wiphy);
if (type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN) {
+ int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
+ sizeof(void *));
struct wireless_dev *wdev;
+ int txq_size = 0;
+
+ if (type == NL80211_IFTYPE_NAN)
+ txq_size = sizeof(struct txq_info) +
+ local->hw.txq_data_size;
- sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size,
- GFP_KERNEL);
+ sdata = kzalloc(size + txq_size, GFP_KERNEL);
if (!sdata)
return -ENOMEM;
wdev = &sdata->wdev;
@@ -2236,6 +2283,16 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ieee80211_assign_perm_addr(local, wdev->address, type);
memcpy(sdata->vif.addr, wdev->address, ETH_ALEN);
ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
+
+ /*
+ * Add a management TXQ for NAN devices which includes frames
+ * that will only be transmitted during discovery windows (DWs)
+ */
+ if (type == NL80211_IFTYPE_NAN) {
+ txqi = (struct txq_info *)((unsigned long)sdata + size);
+ ieee80211_txq_init(sdata, NULL, txqi,
+ IEEE80211_NUM_TIDS);
+ }
} else {
int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
sizeof(void *));
@@ -2386,6 +2443,10 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
if (sdata->vif.txq)
ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq));
+ if (sdata->vif.txq_mgmt)
+ ieee80211_txq_purge(sdata->local,
+ to_txq_info(sdata->vif.txq_mgmt));
+
synchronize_rcu();
cfg80211_unregister_wdev(&sdata->wdev);
diff --git a/net/mac80211/link.c b/net/mac80211/link.c
index 03bfca27d205..93e290dd783f 100644
--- a/net/mac80211/link.c
+++ b/net/mac80211/link.c
@@ -14,26 +14,38 @@
static void ieee80211_update_apvlan_links(struct ieee80211_sub_if_data *sdata)
{
+ unsigned long rem = ~sdata->vif.valid_links &
+ GENMASK(IEEE80211_MLD_MAX_NUM_LINKS - 1, 0);
+ struct ieee80211_local *local = sdata->local;
+ unsigned long add = sdata->vif.valid_links;
+ struct wiphy *wiphy = local->hw.wiphy;
struct ieee80211_sub_if_data *vlan;
struct ieee80211_link_data *link;
- u16 ap_bss_links = sdata->vif.valid_links;
- u16 new_links, vlan_links;
- unsigned long add;
+ struct sta_info *sta;
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
int link_id;
- /* No support for 4addr with MLO yet */
- if (vlan->wdev.use_4addr)
- return;
+ if (vlan->wdev.use_4addr) {
+ sta = wiphy_dereference(wiphy,
+ vlan->u.vlan.sta);
+ if (sta)
+ add = add & sta->sta.valid_links;
+ }
- vlan_links = vlan->vif.valid_links;
+ if (add == vlan->vif.valid_links)
+ continue;
- new_links = ap_bss_links;
+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+ vlan->wdev.valid_links |= BIT(link_id);
+ ether_addr_copy(vlan->wdev.links[link_id].addr,
+ sdata->wdev.links[link_id].addr);
+ }
- add = new_links & ~vlan_links;
- if (!add)
- continue;
+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+ vlan->wdev.valid_links &= ~BIT(link_id);
+ eth_zero_addr(vlan->wdev.links[link_id].addr);
+ }
ieee80211_vif_set_links(vlan, add, 0);
@@ -96,8 +108,13 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
ap_bss = container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap);
- ap_bss_conf = sdata_dereference(ap_bss->vif.link_conf[link_id],
- ap_bss);
+
+ if (deflink)
+ ap_bss_conf = &ap_bss->vif.bss_conf;
+ else
+ ap_bss_conf = sdata_dereference(ap_bss->vif.link_conf[link_id],
+ ap_bss);
+
memcpy(link_conf, ap_bss_conf, sizeof(*link_conf));
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index d1bb6353908d..f47dd58770ad 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1157,7 +1157,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (WARN_ON(local->hw.wiphy->interface_modes &
BIT(NL80211_IFTYPE_NAN) &&
- (!local->ops->start_nan || !local->ops->stop_nan)))
+ ((!local->ops->start_nan || !local->ops->stop_nan) ||
+ (local->hw.wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE &&
+ (local->ops->add_nan_func || local->ops->del_nan_func)))))
return -EINVAL;
if (hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO) {
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c
index 3a66b4cefca7..24a68eef7db8 100644
--- a/net/mac80211/mesh_sync.c
+++ b/net/mac80211/mesh_sync.c
@@ -103,7 +103,7 @@ mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype,
* section.
*/
if (ieee80211_have_rx_timestamp(rx_status))
- t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
+ t_r = ieee80211_calculate_rx_timestamp(&local->hw, rx_status,
len + FCS_LEN, 24);
else
t_r = drv_get_tsf(local, sdata);
diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h
deleted file mode 100644
index a7fdb8e84615..000000000000
--- a/net/mac80211/michael.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Michael MIC implementation - optimized for TKIP MIC operations
- * Copyright 2002-2003, Instant802 Networks, Inc.
- */
-
-#ifndef MICHAEL_H
-#define MICHAEL_H
-
-#include <linux/types.h>
-#include <linux/ieee80211.h>
-
-#define MICHAEL_MIC_LEN 8
-
-struct michael_mic_ctx {
- u32 l, r;
-};
-
-void michael_mic(const u8 *key, struct ieee80211_hdr *hdr,
- const u8 *data, size_t data_len, u8 *mic);
-
-#endif /* MICHAEL_H */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7fc5616cb244..160ae65a5c64 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2514,9 +2514,9 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local,
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
nullfunc->frame_control = fc;
- memcpy(nullfunc->addr1, sdata->deflink.u.mgd.bssid, ETH_ALEN);
+ memcpy(nullfunc->addr1, sdata->vif.cfg.ap_addr, ETH_ALEN);
memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
- memcpy(nullfunc->addr3, sdata->deflink.u.mgd.bssid, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->vif.cfg.ap_addr, ETH_ALEN);
memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@@ -6085,7 +6085,8 @@ ieee80211_determine_our_sta_mode(struct ieee80211_sub_if_data *sdata,
if (is_5ghz &&
!(vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+ IEEE80211_VHT_CAP_EXT_NSS_BW_MASK))) {
conn->bw_limit = IEEE80211_CONN_BW_LIMIT_80;
mlme_link_id_dbg(sdata, link_id,
"no VHT 160 MHz capability on 5 GHz, limiting to 80 MHz");
@@ -9858,10 +9859,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
size += req->links[i].elems_len;
- /* FIXME: no support for 4-addr MLO yet */
- if (sdata->u.mgd.use_4addr && req->link_id >= 0)
- return -EOPNOTSUPP;
-
assoc_data = kzalloc(size, GFP_KERNEL);
if (!assoc_data)
return -ENOMEM;
diff --git a/net/mac80211/nan.c b/net/mac80211/nan.c
new file mode 100644
index 000000000000..4e262b624521
--- /dev/null
+++ b/net/mac80211/nan.c
@@ -0,0 +1,710 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * NAN mode implementation
+ * Copyright(c) 2025-2026 Intel Corporation
+ */
+#include <net/mac80211.h>
+
+#include "ieee80211_i.h"
+#include "driver-ops.h"
+#include "sta_info.h"
+
+static void
+ieee80211_nan_init_channel(struct ieee80211_nan_channel *nan_channel,
+ struct cfg80211_nan_channel *cfg_nan_channel)
+{
+ memset(nan_channel, 0, sizeof(*nan_channel));
+
+ nan_channel->chanreq.oper = cfg_nan_channel->chandef;
+ memcpy(nan_channel->channel_entry, cfg_nan_channel->channel_entry,
+ sizeof(nan_channel->channel_entry));
+ nan_channel->needed_rx_chains = cfg_nan_channel->rx_nss;
+}
+
+static void
+ieee80211_nan_update_channel(struct ieee80211_local *local,
+ struct ieee80211_nan_channel *nan_channel,
+ struct cfg80211_nan_channel *cfg_nan_channel,
+ bool deferred)
+{
+ struct ieee80211_chanctx_conf *conf;
+ bool reducing_nss;
+
+ if (WARN_ON(!cfg80211_chandef_identical(&nan_channel->chanreq.oper,
+ &cfg_nan_channel->chandef)))
+ return;
+
+ if (WARN_ON(memcmp(nan_channel->channel_entry,
+ cfg_nan_channel->channel_entry,
+ sizeof(nan_channel->channel_entry))))
+ return;
+
+ if (nan_channel->needed_rx_chains == cfg_nan_channel->rx_nss)
+ return;
+
+ reducing_nss = nan_channel->needed_rx_chains > cfg_nan_channel->rx_nss;
+ nan_channel->needed_rx_chains = cfg_nan_channel->rx_nss;
+
+ conf = nan_channel->chanctx_conf;
+
+ /*
+ * If we are adding NSSs, we need to be ready before notifying the peer,
+ * if we are reducing NSSs, we need to wait until the peer is notified.
+ */
+ if (!conf || (deferred && reducing_nss))
+ return;
+
+ ieee80211_recalc_smps_chanctx(local, container_of(conf,
+ struct ieee80211_chanctx,
+ conf));
+}
+
+static int
+ieee80211_nan_use_chanctx(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_nan_channel *nan_channel,
+ bool assign_on_failure)
+{
+ struct ieee80211_chanctx *ctx;
+ bool reused_ctx;
+
+ if (!nan_channel->chanreq.oper.chan)
+ return -EINVAL;
+
+ if (ieee80211_check_combinations(sdata, &nan_channel->chanreq.oper,
+ IEEE80211_CHANCTX_SHARED, 0, -1))
+ return -EBUSY;
+
+ ctx = ieee80211_find_or_create_chanctx(sdata, &nan_channel->chanreq,
+ IEEE80211_CHANCTX_SHARED,
+ assign_on_failure,
+ &reused_ctx);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ nan_channel->chanctx_conf = &ctx->conf;
+
+ /*
+ * In case an existing channel context is being used, we marked it as
+ * will_be_used, now that it is assigned - clear this indication
+ */
+ if (reused_ctx) {
+ WARN_ON(!ctx->will_be_used);
+ ctx->will_be_used = false;
+ }
+ ieee80211_recalc_chanctx_min_def(sdata->local, ctx);
+ ieee80211_recalc_smps_chanctx(sdata->local, ctx);
+
+ return 0;
+}
+
+static void
+ieee80211_nan_update_peer_channels(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_chanctx_conf *removed_conf)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+ list_for_each_entry(sta, &local->sta_list, list) {
+ struct ieee80211_nan_peer_sched *peer_sched;
+ int write_idx = 0;
+ bool updated = false;
+
+ if (sta->sdata != sdata)
+ continue;
+
+ peer_sched = sta->sta.nan_sched;
+ if (!peer_sched)
+ continue;
+
+ /* NULL out map slots for channels being removed */
+ for (int i = 0; i < peer_sched->n_channels; i++) {
+ if (peer_sched->channels[i].chanctx_conf != removed_conf)
+ continue;
+
+ for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) {
+ struct ieee80211_nan_peer_map *map =
+ &peer_sched->maps[m];
+
+ if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
+ continue;
+
+ for (int s = 0; s < ARRAY_SIZE(map->slots); s++)
+ if (map->slots[s] == &peer_sched->channels[i])
+ map->slots[s] = NULL;
+ }
+ }
+
+ /* Compact channels array, removing those with removed_conf */
+ for (int i = 0; i < peer_sched->n_channels; i++) {
+ if (peer_sched->channels[i].chanctx_conf == removed_conf) {
+ updated = true;
+ continue;
+ }
+
+ if (write_idx != i) {
+ /* Update map pointers before moving */
+ for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) {
+ struct ieee80211_nan_peer_map *map =
+ &peer_sched->maps[m];
+
+ if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
+ continue;
+
+ for (int s = 0; s < ARRAY_SIZE(map->slots); s++)
+ if (map->slots[s] == &peer_sched->channels[i])
+ map->slots[s] = &peer_sched->channels[write_idx];
+ }
+
+ peer_sched->channels[write_idx] = peer_sched->channels[i];
+ }
+ write_idx++;
+ }
+
+ /* Clear any remaining entries at the end */
+ for (int i = write_idx; i < peer_sched->n_channels; i++)
+ memset(&peer_sched->channels[i], 0, sizeof(peer_sched->channels[i]));
+
+ peer_sched->n_channels = write_idx;
+
+ if (updated)
+ drv_nan_peer_sched_changed(local, sdata, sta);
+ }
+}
+
+static void
+ieee80211_nan_remove_channel(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_nan_channel *nan_channel)
+{
+ struct ieee80211_chanctx_conf *conf;
+ struct ieee80211_chanctx *ctx;
+ struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
+
+ if (WARN_ON(!nan_channel))
+ return;
+
+ lockdep_assert_wiphy(sdata->local->hw.wiphy);
+
+ if (!nan_channel->chanreq.oper.chan)
+ return;
+
+ for (int slot = 0; slot < ARRAY_SIZE(sched_cfg->schedule); slot++)
+ if (sched_cfg->schedule[slot] == nan_channel)
+ sched_cfg->schedule[slot] = NULL;
+
+ conf = nan_channel->chanctx_conf;
+
+ /* If any peer nan schedule uses this chanctx, update them */
+ if (conf)
+ ieee80211_nan_update_peer_channels(sdata, conf);
+
+ memset(nan_channel, 0, sizeof(*nan_channel));
+
+ /* Update the driver before (possibly) releasing the channel context */
+ drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);
+
+ /* Channel might not have a chanctx if it was ULWed */
+ if (!conf)
+ return;
+
+ ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+ if (ieee80211_chanctx_num_assigned(sdata->local, ctx) > 0) {
+ ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
+ ieee80211_recalc_smps_chanctx(sdata->local, ctx);
+ ieee80211_recalc_chanctx_min_def(sdata->local, ctx);
+ }
+
+ if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
+ ieee80211_free_chanctx(sdata->local, ctx, false);
+}
+
+static void
+ieee80211_nan_update_all_ndi_carriers(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+ /* Iterate all interfaces and update carrier for NDI interfaces */
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(sdata) ||
+ sdata->vif.type != NL80211_IFTYPE_NAN_DATA)
+ continue;
+
+ ieee80211_nan_update_ndi_carrier(sdata);
+ }
+}
+
+static struct ieee80211_nan_channel *
+ieee80211_nan_find_free_channel(struct ieee80211_nan_sched_cfg *sched_cfg)
+{
+ for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) {
+ if (!sched_cfg->channels[i].chanreq.oper.chan)
+ return &sched_cfg->channels[i];
+ }
+
+ return NULL;
+}
+
+int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_nan_local_sched *sched)
+{
+ struct ieee80211_nan_channel *sched_idx_to_chan[IEEE80211_NAN_MAX_CHANNELS] = {};
+ struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
+ struct ieee80211_nan_sched_cfg backup_sched;
+ int ret;
+
+ if (sched->n_channels > IEEE80211_NAN_MAX_CHANNELS)
+ return -EOPNOTSUPP;
+
+ if (sched->nan_avail_blob_len > IEEE80211_NAN_AVAIL_BLOB_MAX_LEN)
+ return -EINVAL;
+
+ /*
+ * If a deferred schedule update is pending completion, new updates are
+ * not allowed. Only allow to configure an empty schedule so NAN can be
+ * stopped in the middle of a deferred update. This is fine because
+ * empty schedule means the local NAN device will not be available for
+ * peers anymore so there is no need to update peers about a new
+ * schedule.
+ */
+ if (WARN_ON(sched_cfg->deferred && sched->n_channels))
+ return -EBUSY;
+
+ bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
+
+ memcpy(backup_sched.schedule, sched_cfg->schedule,
+ sizeof(backup_sched.schedule));
+ memcpy(backup_sched.channels, sched_cfg->channels,
+ sizeof(backup_sched.channels));
+ memcpy(backup_sched.avail_blob, sched_cfg->avail_blob,
+ sizeof(backup_sched.avail_blob));
+ backup_sched.avail_blob_len = sched_cfg->avail_blob_len;
+
+ memcpy(sched_cfg->avail_blob, sched->nan_avail_blob,
+ sched->nan_avail_blob_len);
+ sched_cfg->avail_blob_len = sched->nan_avail_blob_len;
+
+ /*
+ * Remove channels that are no longer in the new schedule to free up
+ * resources before adding new channels. For deferred schedule, channels
+ * will be removed when the schedule is applied.
+ * Create a mapping from sched index to sched_cfg channel
+ */
+ for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) {
+ bool still_needed = false;
+
+ if (!sched_cfg->channels[i].chanreq.oper.chan)
+ continue;
+
+ for (int j = 0; j < sched->n_channels; j++) {
+ if (cfg80211_chandef_identical(&sched_cfg->channels[i].chanreq.oper,
+ &sched->nan_channels[j].chandef)) {
+ sched_idx_to_chan[j] =
+ &sched_cfg->channels[i];
+ still_needed = true;
+ break;
+ }
+ }
+
+ if (!still_needed) {
+ __set_bit(i, sdata->u.nan.removed_channels);
+ if (!sched->deferred)
+ ieee80211_nan_remove_channel(sdata,
+ &sched_cfg->channels[i]);
+ }
+ }
+
+ for (int i = 0; i < sched->n_channels; i++) {
+ struct ieee80211_nan_channel *chan = sched_idx_to_chan[i];
+
+ if (chan) {
+ ieee80211_nan_update_channel(sdata->local, chan,
+ &sched->nan_channels[i],
+ sched->deferred);
+ } else {
+ chan = ieee80211_nan_find_free_channel(sched_cfg);
+ if (WARN_ON(!chan)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ sched_idx_to_chan[i] = chan;
+ ieee80211_nan_init_channel(chan,
+ &sched->nan_channels[i]);
+
+ ret = ieee80211_nan_use_chanctx(sdata, chan, false);
+ if (ret) {
+ memset(chan, 0, sizeof(*chan));
+ goto err;
+ }
+ }
+ }
+
+ for (int s = 0; s < ARRAY_SIZE(sched_cfg->schedule); s++) {
+ if (sched->schedule[s] < ARRAY_SIZE(sched_idx_to_chan))
+ sched_cfg->schedule[s] =
+ sched_idx_to_chan[sched->schedule[s]];
+ else
+ sched_cfg->schedule[s] = NULL;
+ }
+
+ sched_cfg->deferred = sched->deferred;
+
+ drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);
+
+ /*
+ * For deferred update, don't update NDI carriers yet as the new
+ * schedule is not yet applied so common slots don't change. The NDI
+ * carrier will be updated once the driver notifies the new schedule is
+ * applied.
+ */
+ if (sched_cfg->deferred)
+ return 0;
+
+ ieee80211_nan_update_all_ndi_carriers(sdata->local);
+ bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
+
+ return 0;
+err:
+ /* Remove newly added channels */
+ for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) {
+ struct cfg80211_chan_def *chan_def =
+ &sched_cfg->channels[i].chanreq.oper;
+
+ if (!chan_def->chan)
+ continue;
+
+ if (!cfg80211_chandef_identical(&backup_sched.channels[i].chanreq.oper,
+ chan_def))
+ ieee80211_nan_remove_channel(sdata,
+ &sched_cfg->channels[i]);
+ }
+
+ /* Re-add all backed up channels */
+ for (int i = 0; i < ARRAY_SIZE(backup_sched.channels); i++) {
+ struct ieee80211_nan_channel *chan = &sched_cfg->channels[i];
+
+ *chan = backup_sched.channels[i];
+
+ /*
+ * For deferred update, no channels were removed and the channel
+ * context didn't change, so nothing else to do.
+ */
+ if (!chan->chanctx_conf || sched->deferred)
+ continue;
+
+ if (test_bit(i, sdata->u.nan.removed_channels)) {
+ /* Clear the stale chanctx pointer */
+ chan->chanctx_conf = NULL;
+ /*
+ * We removed the newly added channels so we don't lack
+ * resources. So the only reason that this would fail
+ * is a FW error which we ignore. Therefore, this
+ * should never fail.
+ */
+ WARN_ON(ieee80211_nan_use_chanctx(sdata, chan, true));
+ } else {
+ struct ieee80211_chanctx_conf *conf = chan->chanctx_conf;
+
+ /* FIXME: detect no-op? */
+ /* Channel was not removed but may have been updated */
+ ieee80211_recalc_smps_chanctx(sdata->local,
+ container_of(conf,
+ struct ieee80211_chanctx,
+ conf));
+ }
+ }
+
+ memcpy(sched_cfg->schedule, backup_sched.schedule,
+ sizeof(backup_sched.schedule));
+ memcpy(sched_cfg->avail_blob, backup_sched.avail_blob,
+ sizeof(backup_sched.avail_blob));
+ sched_cfg->avail_blob_len = backup_sched.avail_blob_len;
+ sched_cfg->deferred = false;
+ bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
+
+ drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);
+ ieee80211_nan_update_all_ndi_carriers(sdata->local);
+ return ret;
+}
+
+void ieee80211_nan_sched_update_done(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_nan_sched_cfg *sched_cfg = &vif->cfg.nan_sched;
+ unsigned int i;
+
+ lockdep_assert_wiphy(sdata->local->hw.wiphy);
+
+ if (WARN_ON(!sched_cfg->deferred))
+ return;
+
+ ieee80211_nan_update_all_ndi_carriers(sdata->local);
+
+ /*
+ * Clear the deferred flag before removing channels. Removing channels
+ * will trigger another schedule update to the driver, and there is no
+ * need for this update to be deferred since removed channels are not
+ * part of the schedule anymore, so no need to notify peers about
+ * removing them.
+ */
+ sched_cfg->deferred = false;
+
+ for (i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) {
+ struct ieee80211_nan_channel *chan = &sched_cfg->channels[i];
+ struct ieee80211_chanctx_conf *conf = chan->chanctx_conf;
+
+ if (!chan->chanreq.oper.chan)
+ continue;
+
+ if (test_bit(i, sdata->u.nan.removed_channels))
+ ieee80211_nan_remove_channel(sdata, chan);
+ else if (conf)
+ /*
+ * We might have called this already for some channels,
+ * but this knows to handle a no-op.
+ */
+ ieee80211_recalc_smps_chanctx(sdata->local,
+ container_of(conf,
+ struct ieee80211_chanctx,
+ conf));
+ }
+
+ bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
+ cfg80211_nan_sched_update_done(ieee80211_vif_to_wdev(vif), true,
+ GFP_KERNEL);
+}
+EXPORT_SYMBOL(ieee80211_nan_sched_update_done);
+
+void ieee80211_nan_free_peer_sched(struct ieee80211_nan_peer_sched *sched)
+{
+ if (!sched)
+ return;
+
+ kfree(sched->init_ulw);
+ kfree(sched);
+}
+
+static int
+ieee80211_nan_init_peer_channel(struct ieee80211_sub_if_data *sdata,
+ const struct sta_info *sta,
+ const struct cfg80211_nan_channel *cfg_chan,
+ struct ieee80211_nan_channel *new_chan)
+{
+ struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
+
+ /* Find compatible local channel */
+ for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++) {
+ struct ieee80211_nan_channel *local_chan =
+ &sched_cfg->channels[j];
+ const struct cfg80211_chan_def *compat;
+
+ if (!local_chan->chanreq.oper.chan)
+ continue;
+
+ compat = cfg80211_chandef_compatible(&local_chan->chanreq.oper,
+ &cfg_chan->chandef);
+ if (!compat)
+ continue;
+
+ /* compat is the wider chandef, and we want the narrower one */
+ new_chan->chanreq.oper = compat == &local_chan->chanreq.oper ?
+ cfg_chan->chandef : local_chan->chanreq.oper;
+ new_chan->needed_rx_chains = min(local_chan->needed_rx_chains,
+ cfg_chan->rx_nss);
+ new_chan->chanctx_conf = local_chan->chanctx_conf;
+
+ break;
+ }
+
+ /*
+ * nl80211 already validated that each peer channel is compatible
+ * with at least one local channel, so this should never happen.
+ */
+ if (WARN_ON(!new_chan->chanreq.oper.chan))
+ return -EINVAL;
+
+ memcpy(new_chan->channel_entry, cfg_chan->channel_entry,
+ sizeof(new_chan->channel_entry));
+
+ return 0;
+}
+
+static void
+ieee80211_nan_init_peer_map(struct ieee80211_nan_peer_sched *peer_sched,
+ const struct cfg80211_nan_peer_map *cfg_map,
+ struct ieee80211_nan_peer_map *new_map)
+{
+ new_map->map_id = cfg_map->map_id;
+
+ if (new_map->map_id == CFG80211_NAN_INVALID_MAP_ID)
+ return;
+
+ /* Set up the slots array */
+ for (int slot = 0; slot < ARRAY_SIZE(new_map->slots); slot++) {
+ u8 chan_idx = cfg_map->schedule[slot];
+
+ if (chan_idx < peer_sched->n_channels)
+ new_map->slots[slot] = &peer_sched->channels[chan_idx];
+ }
+}
+
+/*
+ * Check if the local schedule and a peer schedule have at least one common
+ * slot - a slot where both schedules are active on compatible channels.
+ */
+static bool
+ieee80211_nan_has_common_slots(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_nan_peer_sched *peer_sched)
+{
+ for (int slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; slot++) {
+ struct ieee80211_nan_channel *local_chan =
+ sdata->vif.cfg.nan_sched.schedule[slot];
+
+ if (!local_chan || !local_chan->chanctx_conf)
+ continue;
+
+ /* Check all peer maps for this slot */
+ for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) {
+ struct ieee80211_nan_peer_map *map = &peer_sched->maps[m];
+ struct ieee80211_nan_channel *peer_chan;
+
+ if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
+ continue;
+
+ peer_chan = map->slots[slot];
+ if (!peer_chan)
+ continue;
+
+ if (local_chan->chanctx_conf == peer_chan->chanctx_conf)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ieee80211_nan_update_ndi_carrier(struct ieee80211_sub_if_data *ndi_sdata)
+{
+ struct ieee80211_local *local = ndi_sdata->local;
+ struct ieee80211_sub_if_data *nmi_sdata;
+ struct sta_info *sta;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+ if (WARN_ON(ndi_sdata->vif.type != NL80211_IFTYPE_NAN_DATA ||
+ !ndi_sdata->dev) || !ieee80211_sdata_running(ndi_sdata))
+ return;
+
+ nmi_sdata = wiphy_dereference(local->hw.wiphy, ndi_sdata->u.nan_data.nmi);
+ if (WARN_ON(!nmi_sdata))
+ return;
+
+ list_for_each_entry(sta, &local->sta_list, list) {
+ struct ieee80211_sta *nmi_sta;
+
+ if (sta->sdata != ndi_sdata ||
+ !test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ continue;
+
+ nmi_sta = wiphy_dereference(local->hw.wiphy, sta->sta.nmi);
+ if (WARN_ON(!nmi_sta) || !nmi_sta->nan_sched)
+ continue;
+
+ if (ieee80211_nan_has_common_slots(nmi_sdata, nmi_sta->nan_sched)) {
+ netif_carrier_on(ndi_sdata->dev);
+ return;
+ }
+ }
+
+ netif_carrier_off(ndi_sdata->dev);
+}
+
+static void
+ieee80211_nan_update_peer_ndis_carrier(struct ieee80211_local *local,
+ struct sta_info *nmi_sta)
+{
+ struct sta_info *sta;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+ list_for_each_entry(sta, &local->sta_list, list) {
+ if (rcu_access_pointer(sta->sta.nmi) == &nmi_sta->sta)
+ ieee80211_nan_update_ndi_carrier(sta->sdata);
+ }
+}
+
+int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_nan_peer_sched *sched)
+{
+ struct ieee80211_nan_peer_sched *new_sched, *old_sched, *to_free;
+ struct sta_info *sta;
+ int ret;
+
+ lockdep_assert_wiphy(sdata->local->hw.wiphy);
+
+ if (!sdata->u.nan.started)
+ return -EINVAL;
+
+ sta = sta_info_get(sdata, sched->peer_addr);
+ if (!sta)
+ return -ENOENT;
+
+ new_sched = kzalloc(struct_size(new_sched, channels, sched->n_channels),
+ GFP_KERNEL);
+ if (!new_sched)
+ return -ENOMEM;
+
+ to_free = new_sched;
+
+ new_sched->seq_id = sched->seq_id;
+ new_sched->committed_dw = sched->committed_dw;
+ new_sched->max_chan_switch = sched->max_chan_switch;
+ new_sched->n_channels = sched->n_channels;
+
+ if (sched->ulw_size && sched->init_ulw) {
+ new_sched->init_ulw = kmemdup(sched->init_ulw, sched->ulw_size,
+ GFP_KERNEL);
+ if (!new_sched->init_ulw) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ new_sched->ulw_size = sched->ulw_size;
+ }
+
+ for (int i = 0; i < sched->n_channels; i++) {
+ ret = ieee80211_nan_init_peer_channel(sdata, sta,
+ &sched->nan_channels[i],
+ &new_sched->channels[i]);
+ if (ret)
+ goto out;
+ }
+
+ for (int m = 0; m < ARRAY_SIZE(sched->maps); m++)
+ ieee80211_nan_init_peer_map(new_sched, &sched->maps[m],
+ &new_sched->maps[m]);
+
+ /* Install the new schedule before calling the driver */
+ old_sched = sta->sta.nan_sched;
+ sta->sta.nan_sched = new_sched;
+
+ ret = drv_nan_peer_sched_changed(sdata->local, sdata, sta);
+ if (ret) {
+ /* Revert to old schedule */
+ sta->sta.nan_sched = old_sched;
+ goto out;
+ }
+
+ ieee80211_nan_update_peer_ndis_carrier(sdata->local, sta);
+
+ /* Success - free old schedule */
+ to_free = old_sched;
+ ret = 0;
+
+out:
+ ieee80211_nan_free_peer_sched(to_free);
+ return ret;
+}
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 62745ca00e06..b73ef3adfcc5 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -1849,20 +1849,7 @@ minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
static void *
minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
{
- struct ieee80211_supported_band *sband;
- struct minstrel_ht_sta *mi;
- struct minstrel_priv *mp = priv;
- struct ieee80211_hw *hw = mp->hw;
- int max_rates = 0;
- int i;
-
- for (i = 0; i < NUM_NL80211_BANDS; i++) {
- sband = hw->wiphy->bands[i];
- if (sband && sband->n_bitrates > max_rates)
- max_rates = sband->n_bitrates;
- }
-
- return kzalloc_obj(*mi, gfp);
+ return kzalloc_obj(struct minstrel_ht_sta, gfp);
}
static void
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d9a654ef082d..3e5d1c47a5b0 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -404,7 +404,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
while ((pos - (u8 *)rthdr) & 7)
*pos++ = 0;
put_unaligned_le64(
- ieee80211_calculate_rx_timestamp(local, status,
+ ieee80211_calculate_rx_timestamp(&local->hw, status,
mpdulen, 0),
pos);
rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_TSFT));
@@ -1589,6 +1589,25 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
if (ieee80211_vif_is_mesh(&rx->sdata->vif))
return ieee80211_rx_mesh_check(rx);
+ /*
+ * Wi-Fi Aware (TM) 4.0 specification 6.2.5:
+ * For NAN_DATA, unicast data frames must have A2 (source)
+ * assigned to an active NDP. If not the frame must be dropped
+ * and NAN Data Path termination frame should be sent. Notify
+ * user space so it can do so.
+ */
+ if (rx->sdata->vif.type == NL80211_IFTYPE_NAN_DATA) {
+ if (ieee80211_is_data(hdr->frame_control) &&
+ !is_multicast_ether_addr(hdr->addr1) &&
+ (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC))) {
+ if (cfg80211_rx_spurious_frame(rx->sdata->dev, hdr->addr2,
+ rx->link_id, GFP_ATOMIC))
+ return RX_DROP_U_SPURIOUS_NOTIF;
+ return RX_DROP_U_SPURIOUS;
+ }
+ return RX_CONTINUE;
+ }
+
if (unlikely((ieee80211_is_data(hdr->frame_control) ||
ieee80211_is_pspoll(hdr->frame_control)) &&
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
@@ -3748,7 +3767,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_AP &&
- sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+ sdata->vif.type != NL80211_IFTYPE_NAN_DATA)
break;
/* verify action_code is present */
@@ -4469,6 +4489,9 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
bool multicast = is_multicast_ether_addr(hdr->addr1) ||
ieee80211_is_s1g_beacon(hdr->frame_control);
+ static const u8 nan_network_id[ETH_ALEN] __aligned(2) = {
+ 0x51, 0x6F, 0x9A, 0x01, 0x00, 0x00
+ };
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
@@ -4597,6 +4620,10 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
(ieee80211_is_auth(hdr->frame_control) &&
ether_addr_equal(sdata->vif.addr, hdr->addr1));
case NL80211_IFTYPE_NAN:
+ if (ieee80211_has_tods(hdr->frame_control) ||
+ ieee80211_has_fromds(hdr->frame_control))
+ return false;
+
/* Accept only frames that are addressed to the NAN cluster
* (based on the Cluster ID). From these frames, accept only
* action frames or authentication frames that are addressed to
@@ -4608,7 +4635,35 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
(ieee80211_is_auth(hdr->frame_control) &&
ether_addr_equal(sdata->vif.addr, hdr->addr1)));
case NL80211_IFTYPE_NAN_DATA:
- return false;
+ if (ieee80211_has_tods(hdr->frame_control) ||
+ ieee80211_has_fromds(hdr->frame_control))
+ return false;
+
+ if (ieee80211_is_data(hdr->frame_control)) {
+ struct ieee80211_sub_if_data *nmi;
+
+ nmi = rcu_dereference(sdata->u.nan_data.nmi);
+ if (!nmi)
+ return false;
+
+ if (!ether_addr_equal(nmi->wdev.u.nan.cluster_id,
+ hdr->addr3))
+ return false;
+
+ return multicast ||
+ ether_addr_equal(sdata->vif.addr, hdr->addr1);
+ }
+
+ /* Non-public action frames (unicast or multicast) */
+ if (ieee80211_is_action(hdr->frame_control) &&
+ !ieee80211_is_public_action(hdr, skb->len) &&
+ (ether_addr_equal(nan_network_id, hdr->addr1) ||
+ ether_addr_equal(sdata->vif.addr, hdr->addr1)))
+ return true;
+
+ /* Unicast secure management frames */
+ return ether_addr_equal(sdata->vif.addr, hdr->addr1) &&
+ ieee80211_is_unicast_robust_mgmt_frame(skb);
default:
break;
}
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 4823c8d45639..eeff230bd909 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -216,7 +216,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
if (link_conf) {
bss_meta.parent_tsf =
- ieee80211_calculate_rx_timestamp(local,
+ ieee80211_calculate_rx_timestamp(&local->hw,
rx_status,
len + FCS_LEN,
24);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 7923ee9eafab..4c31ef8817ce 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -795,6 +795,7 @@ struct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata,
static int sta_info_insert_check(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_sta *same_addr_sta;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
@@ -810,13 +811,18 @@ static int sta_info_insert_check(struct sta_info *sta)
!is_valid_ether_addr(sta->sta.addr)))
return -EINVAL;
+ if (!ieee80211_hw_check(&sdata->local->hw, NEEDS_UNIQUE_STA_ADDR))
+ return 0;
+
/* The RCU read lock is required by rhashtable due to
* asynchronous resize/rehash. We also require the mutex
* for correctness.
*/
rcu_read_lock();
- if (ieee80211_hw_check(&sdata->local->hw, NEEDS_UNIQUE_STA_ADDR) &&
- ieee80211_find_sta_by_ifaddr(&sdata->local->hw, sta->addr, NULL)) {
+ same_addr_sta = ieee80211_find_sta_by_ifaddr(&sdata->local->hw,
+ sta->addr, NULL);
+ /* For NAN, a peer can re-use */
+ if (same_addr_sta && same_addr_sta != rcu_access_pointer(sta->sta.nmi)) {
rcu_read_unlock();
return -ENOTUNIQ;
}
@@ -1294,6 +1300,21 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
lockdep_assert_wiphy(local->hw.wiphy);
+ if (sdata->vif.type == NL80211_IFTYPE_NAN) {
+ struct sta_info *sta_iter, *tmp;
+
+ /* Remove all NDI stations associated with this NMI STA */
+ list_for_each_entry_safe(sta_iter, tmp, &local->sta_list, list) {
+ if (rcu_access_pointer(sta_iter->sta.nmi) != &sta->sta)
+ continue;
+ sta_info_destroy_addr(sta_iter->sdata, sta_iter->addr);
+ }
+
+ /* Free and clear the local peer schedule */
+ ieee80211_nan_free_peer_sched(sta->sta.nan_sched);
+ sta->sta.nan_sched = NULL;
+ }
+
/*
* Before removing the station from the driver and
* rate control, it might still start new aggregation
@@ -1433,6 +1454,8 @@ static int _sta_info_move_state(struct sta_info *sta,
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
ieee80211_vif_dec_num_mcast(sta->sdata);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
+ if (sta->sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
+ ieee80211_nan_update_ndi_carrier(sta->sdata);
/*
* If we have encryption offload, flush (station) queues
@@ -1461,6 +1484,8 @@ static int _sta_info_move_state(struct sta_info *sta,
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_check_fast_xmit(sta);
ieee80211_check_fast_rx(sta);
+ if (sta->sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
+ ieee80211_nan_update_ndi_carrier(sta->sdata);
}
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
sta->sdata->vif.type == NL80211_IFTYPE_AP)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 58ccbea7f6f6..3e5d003bd31f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -505,7 +505,8 @@ struct ieee80211_fragment_cache {
* @status_stats.ack_signal_filled: last ACK signal validity
* @status_stats.avg_ack_signal: average ACK signal
* @cur_max_bandwidth: maximum bandwidth to use for TX to the station,
- * taken from HT/VHT capabilities or VHT operating mode notification
+ * taken from HT/VHT capabilities or VHT operating mode notification.
+ * Invalid for NAN since that is operating on multiple bands.
* @rx_omi_bw_rx: RX OMI bandwidth restriction to apply for RX
* @rx_omi_bw_tx: RX OMI bandwidth restriction to apply for TX
* @rx_omi_bw_staging: RX OMI bandwidth restriction to apply later
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index e5968d754f8b..71cf88039bd4 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -3366,6 +3366,37 @@ TRACE_EVENT(drv_set_eml_op_mode,
)
);
+TRACE_EVENT(drv_nan_peer_sched_changed,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta),
+
+ TP_ARGS(local, sdata, sta),
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __array(u8, map_ids, CFG80211_NAN_MAX_PEER_MAPS)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_ASSIGN;
+ for (int i = 0; i < CFG80211_NAN_MAX_PEER_MAPS; i++)
+ __entry->map_ids[i] = sta->nan_sched ?
+ sta->nan_sched->maps[i].map_id :
+ 0xff;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT
+ " map_ids=[%u, %u]",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
+ __entry->map_ids[0], __entry->map_ids[1]
+ )
+);
+
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e0091a6196fc..b487d2330f25 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1313,13 +1313,19 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
if ((!ieee80211_is_mgmt(hdr->frame_control) ||
ieee80211_is_bufferable_mmpdu(skb) ||
- vif->type == NL80211_IFTYPE_STATION) &&
+ vif->type == NL80211_IFTYPE_STATION ||
+ vif->type == NL80211_IFTYPE_NAN ||
+ vif->type == NL80211_IFTYPE_NAN_DATA) &&
sta && sta->uploaded) {
/*
* This will be NULL if the driver didn't set the
* opt-in hardware flag.
*/
txq = sta->sta.txq[IEEE80211_NUM_TIDS];
+ } else if ((!ieee80211_is_mgmt(hdr->frame_control) ||
+ ieee80211_is_bufferable_mmpdu(skb)) &&
+ !sta) {
+ txq = vif->txq_mgmt;
}
} else if (sta) {
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@@ -1512,9 +1518,15 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
txqi->txq.vif = &sdata->vif;
if (!sta) {
- sdata->vif.txq = &txqi->txq;
- txqi->txq.tid = 0;
- txqi->txq.ac = IEEE80211_AC_BE;
+ txqi->txq.tid = tid;
+
+ if (tid == IEEE80211_NUM_TIDS) {
+ sdata->vif.txq_mgmt = &txqi->txq;
+ txqi->txq.ac = IEEE80211_AC_VO;
+ } else {
+ sdata->vif.txq = &txqi->txq;
+ txqi->txq.ac = IEEE80211_AC_BE;
+ }
return;
}
@@ -2531,6 +2543,13 @@ int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
if (!sta)
return -ENOLINK;
break;
+ case NL80211_IFTYPE_NAN_DATA:
+ if (is_multicast_ether_addr(skb->data)) {
+ *sta_out = ERR_PTR(-ENOENT);
+ return 0;
+ }
+ sta = sta_info_get(sdata, skb->data);
+ break;
default:
return -EINVAL;
}
@@ -2824,18 +2843,37 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);
hdrlen = 24;
break;
+ case NL80211_IFTYPE_NAN_DATA: {
+ struct ieee80211_sub_if_data *nmi;
+
+ /* DA SA Cluster ID */
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ nmi = rcu_dereference(sdata->u.nan_data.nmi);
+ if (!nmi) {
+ ret = -ENOTCONN;
+ goto free;
+ }
+ memcpy(hdr.addr3, nmi->wdev.u.nan.cluster_id, ETH_ALEN);
+ hdrlen = 24;
+ break;
+ }
default:
ret = -EINVAL;
goto free;
}
if (!chanctx_conf) {
- if (!ieee80211_vif_is_mld(&sdata->vif)) {
+ if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA) {
+ /* NAN operates on multiple bands */
+ band = NUM_NL80211_BANDS;
+ } else if (!ieee80211_vif_is_mld(&sdata->vif)) {
ret = -ENOTCONN;
goto free;
+ } else {
+ /* MLD transmissions must not rely on the band */
+ band = 0;
}
- /* MLD transmissions must not rely on the band */
- band = 0;
} else {
band = chanctx_conf->def.chan->band;
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 8987a4504520..b093bc203c81 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -325,7 +325,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
struct ieee80211_vif *vif = &sdata->vif;
struct fq *fq = &local->fq;
struct ps_data *ps = NULL;
- struct txq_info *txqi;
+ struct txq_info *txqi = NULL;
struct sta_info *sta;
int i;
@@ -344,37 +344,49 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct ieee80211_txq *txq = sta->sta.txq[i];
+ struct txq_info *sta_txqi;
if (!txq)
continue;
- txqi = to_txq_info(txq);
+ sta_txqi = to_txq_info(txq);
if (ac != txq->ac)
continue;
if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY,
- &txqi->flags))
+ &sta_txqi->flags))
continue;
spin_unlock(&fq->lock);
- drv_wake_tx_queue(local, txqi);
+ drv_wake_tx_queue(local, sta_txqi);
spin_lock(&fq->lock);
}
}
- if (!vif->txq)
- goto out;
+ if (vif->txq) {
+ txqi = to_txq_info(vif->txq);
- txqi = to_txq_info(vif->txq);
+ /* txq and txq_mgmt are mutually exclusive */
+ WARN_ON_ONCE(vif->txq_mgmt);
- if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
- (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
- goto out;
+ if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
+ (ps && atomic_read(&ps->num_sta_ps)) ||
+ ac != vif->txq->ac)
+ txqi = NULL;
+ } else if (vif->txq_mgmt) {
+ txqi = to_txq_info(vif->txq_mgmt);
+
+ if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
+ ac != vif->txq_mgmt->ac)
+ txqi = NULL;
+ }
spin_unlock(&fq->lock);
- drv_wake_tx_queue(local, txqi);
+ if (txqi)
+ drv_wake_tx_queue(local, txqi);
+
local_bh_enable();
return;
out:
@@ -1732,16 +1744,12 @@ static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata)
}
}
-static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
+static int
+ieee80211_reconfig_nan_offload_de(struct ieee80211_sub_if_data *sdata)
{
struct cfg80211_nan_func *func, **funcs;
int res, id, i = 0;
- res = drv_start_nan(sdata->local, sdata,
- &sdata->u.nan.conf);
- if (WARN_ON(res))
- return res;
-
funcs = kzalloc_objs(*funcs, sdata->local->hw.max_nan_de_entries + 1);
if (!funcs)
return -ENOMEM;
@@ -1750,12 +1758,12 @@ static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
* This is a little bit ugly. We need to call a potentially sleeping
* callback for each NAN function, so we can't hold the spinlock.
*/
- spin_lock_bh(&sdata->u.nan.func_lock);
+ spin_lock_bh(&sdata->u.nan.de.func_lock);
- idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id)
+ idr_for_each_entry(&sdata->u.nan.de.function_inst_ids, func, id)
funcs[i++] = func;
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ spin_unlock_bh(&sdata->u.nan.de.func_lock);
for (i = 0; funcs[i]; i++) {
res = drv_add_nan_func(sdata->local, sdata, funcs[i]);
@@ -1767,6 +1775,77 @@ static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
}
kfree(funcs);
+ return res;
+}
+
+static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_sub_if_data *ndi_sdata;
+ struct sta_info *sta;
+ int res;
+
+ res = drv_start_nan(local, sdata, &sdata->u.nan.conf);
+ if (WARN_ON(res))
+ return res;
+
+ if (!(sdata->local->hw.wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE))
+ return ieee80211_reconfig_nan_offload_de(sdata);
+
+ drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);
+
+ /* Now we can add all the NDIs to the driver */
+ list_for_each_entry(ndi_sdata, &local->interfaces, list) {
+ if (ndi_sdata->vif.type == NL80211_IFTYPE_NAN_DATA) {
+ res = drv_add_interface(local, ndi_sdata);
+ if (WARN_ON(res))
+ return res;
+ }
+ }
+
+ /* Add NMI stations (stations on the NAN interface) */
+ list_for_each_entry(sta, &local->sta_list, list) {
+ enum ieee80211_sta_state state;
+
+ if (!sta->uploaded || sta->sdata != sdata)
+ continue;
+
+ for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state;
+ state++) {
+ res = drv_sta_state(local, sdata, sta, state,
+ state + 1);
+ if (WARN_ON(res))
+ return res;
+ }
+
+ /* Add peer schedules for NMI stations that have them */
+ if (!sta->sta.nan_sched)
+ continue;
+
+ res = drv_nan_peer_sched_changed(local, sdata, sta);
+ if (WARN_ON(res))
+ return res;
+ }
+
+ /* Add NDI stations (stations on NAN_DATA interfaces) */
+ list_for_each_entry(sta, &local->sta_list, list) {
+ enum ieee80211_sta_state state;
+
+ if (!sta->uploaded ||
+ sta->sdata->vif.type != NL80211_IFTYPE_NAN_DATA)
+ continue;
+
+ if (WARN_ON(!sta->sta.nmi))
+ continue;
+
+ for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state;
+ state++) {
+ res = drv_sta_state(local, sta->sdata, sta, state,
+ state + 1);
+ if (WARN_ON(res))
+ return res;
+ }
+ }
return 0;
}
@@ -1921,6 +2000,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
continue;
+ /* These vifs can't be added before NAN was started */
+ if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
+ continue;
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
ieee80211_sdata_running(sdata)) {
res = drv_add_interface(local, sdata);
@@ -1938,6 +2020,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
continue;
+ if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
+ continue;
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
ieee80211_sdata_running(sdata))
drv_remove_interface(local, sdata);
@@ -2021,6 +2105,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MONITOR:
break;
+ case NL80211_IFTYPE_NAN:
+ case NL80211_IFTYPE_NAN_DATA:
+ /* NAN stations are handled later */
+ break;
case NL80211_IFTYPE_ADHOC:
if (sdata->vif.cfg.ibss_joined)
WARN_ON(drv_join_ibss(local, sdata));
@@ -3411,20 +3499,7 @@ u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs)
return 1;
}
-/**
- * ieee80211_calculate_rx_timestamp - calculate timestamp in frame
- * @local: mac80211 hw info struct
- * @status: RX status
- * @mpdu_len: total MPDU length (including FCS)
- * @mpdu_offset: offset into MPDU to calculate timestamp at
- *
- * This function calculates the RX timestamp at the given MPDU offset, taking
- * into account what the RX timestamp was. An offset of 0 will just normalize
- * the timestamp to TSF at beginning of MPDU reception.
- *
- * Returns: the calculated timestamp
- */
-u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
+u64 ieee80211_calculate_rx_timestamp(struct ieee80211_hw *hw,
struct ieee80211_rx_status *status,
unsigned int mpdu_len,
unsigned int mpdu_offset)
@@ -3543,7 +3618,7 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
case RX_ENC_LEGACY: {
struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[status->band];
+ sband = hw->wiphy->bands[status->band];
ri.legacy = sband->bitrates[status->rate_idx].bitrate;
if (mactime_plcp_start) {
@@ -3575,6 +3650,7 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
return ts;
}
+EXPORT_SYMBOL_GPL(ieee80211_calculate_rx_timestamp);
/* Cancel CAC for the interfaces under the specified @local. If @ctx is
* also provided, only the interfaces using that ctx will be canceled.
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index a6570781740a..f3bb5a561a38 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -133,6 +133,10 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
if (!vht_cap_ie || !own_vht_cap->vht_supported)
return;
+ /* NDI station are using the capabilities from the NMI station */
+ if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_NAN_DATA))
+ return;
+
if (sband) {
/* Allow VHT if at least one channel on the sband supports 80 MHz */
bool have_80mhz = false;
@@ -320,7 +324,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
IEEE80211_STA_RX_BW_160;
}
- link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
+ if (sdata->vif.type != NL80211_IFTYPE_NAN)
+ link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
/*
* Work around the Cisco 9115 FW 17.3 bug by taking the min of
@@ -373,6 +378,10 @@ __ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta,
} else {
struct ieee80211_bss_conf *link_conf;
+ if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_NAN_DATA ||
+ sdata->vif.type == NL80211_IFTYPE_NAN))
+ return IEEE80211_STA_RX_BW_20;
+
rcu_read_lock();
link_conf = rcu_dereference(sdata->vif.link_conf[link_id]);
band = link_conf->chanreq.oper.chan->band;
@@ -518,6 +527,11 @@ _ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta,
} else {
struct ieee80211_bss_conf *link_conf;
+ /* NAN operates on multiple channels so a chandef must be given */
+ if (WARN_ON_ONCE(sta->sdata->vif.type == NL80211_IFTYPE_NAN ||
+ sta->sdata->vif.type == NL80211_IFTYPE_NAN_DATA))
+ return IEEE80211_STA_RX_BW_20;
+
rcu_read_lock();
link_conf = rcu_dereference(sta->sdata->vif.link_conf[link_sta->link_id]);
if (WARN_ON_ONCE(!link_conf)) {
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 64a57475ce50..724ec831a885 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -18,7 +18,6 @@
#include <crypto/utils.h>
#include "ieee80211_i.h"
-#include "michael.h"
#include "tkip.h"
#include "aes_ccm.h"
#include "aes_cmac.h"
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 62a83faf0e07..a77fd5ba6368 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
-cfg80211-y += pmsr.o
+cfg80211-y += michael-mic.o pmsr.o
cfg80211-$(CONFIG_OF) += of.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
diff --git a/net/mac80211/michael.c b/net/wireless/michael-mic.c
index 8a1afc93e749..ec5164756e0a 100644
--- a/net/mac80211/michael.c
+++ b/net/wireless/michael-mic.c
@@ -5,10 +5,13 @@
*/
#include <linux/types.h>
#include <linux/bitops.h>
+#include <linux/export.h>
#include <linux/ieee80211.h>
#include <linux/unaligned.h>
-#include "michael.h"
+struct michael_mic_ctx {
+ u32 l, r;
+};
static void michael_block(struct michael_mic_ctx *mctx, u32 val)
{
@@ -81,3 +84,4 @@ void michael_mic(const u8 *key, struct ieee80211_hdr *hdr,
put_unaligned_le32(mctx.l, mic);
put_unaligned_le32(mctx.r, mic + 4);
}
+EXPORT_SYMBOL_GPL(michael_mic);