Brings lots of driver updates and API changes needed for mt76 updates.
Disable iwlwifi and ath11k on 5.15, since backport is too difficult,
and the only remaining targets won't need those drivers.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- /dev/null
+--- a/ath10k-6.4/mac.c
++++ b/ath10k-6.4/mac.c
+@@ -2310,8 +2310,8 @@ static void ath10k_mac_vif_ap_csa_count_
+ if (!arvif->is_up)
+ return;
+
+- if (!ieee80211_beacon_cntdwn_is_complete(vif)) {
+- ieee80211_beacon_update_cntdwn(vif);
++ if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) {
++ ieee80211_beacon_update_cntdwn(vif, 0);
+
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
+ if (ret)
+@@ -2323,7 +2323,7 @@ static void ath10k_mac_vif_ap_csa_count_
+ ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
+ ret);
+ } else {
+- ieee80211_csa_finish(vif);
++ ieee80211_csa_finish(vif, 0);
+ }
+ }
+
+--- a/ath10k-6.4/wmi.c
++++ b/ath10k-6.4/wmi.c
+@@ -4284,8 +4284,8 @@ void ath10k_wmi_event_host_swba(struct a
+ * actual channel switch is done
+ */
+ if (arvif->vif->bss_conf.csa_active &&
+- ieee80211_beacon_cntdwn_is_complete(arvif->vif)) {
+- ieee80211_csa_finish(arvif->vif);
++ ieee80211_beacon_cntdwn_is_complete(arvif->vif, 0)) {
++ ieee80211_csa_finish(arvif->vif, 0);
+ continue;
+ }
+
PKG_NAME:=mac80211
-PKG_VERSION:=6.6.15
-PKG_RELEASE:=2
+PKG_VERSION:=6.9.9
+PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0-only
PKG_LICENSE_FILES:=COPYING
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources/
-PKG_HASH:=3bbc461121134fda9089c084a5eed577d05e7837a157edf9a3797937172a3ece
+PKG_HASH:=3417da091a57c7b1c145d44c1fae9f1e0bac6d0c8ad61b37e57b0a802eeb2837
PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(if $(BUILD_VARIANT),$(PKG_NAME)-$(BUILD_VARIANT)/)backports-$(PKG_VERSION)
ifeq ($(strip $(CONFIG_EXTERNAL_KERNEL_TREE)),"")
ifeq ($(strip $(CONFIG_KERNEL_GIT_CLONE_URI)),"")
define Build/Configure
- cmp $(PKG_BUILD_DIR)/include/linux/ath9k_platform.h $(LINUX_DIR)/include/linux/ath9k_platform.h
cmp $(PKG_BUILD_DIR)/include/linux/ath5k_platform.h $(LINUX_DIR)/include/linux/ath5k_platform.h
cmp $(PKG_BUILD_DIR)/include/linux/rt2x00_platform.h $(LINUX_DIR)/include/linux/rt2x00_platform.h
endef
$(call KernelPackage/mac80211/Default)
TITLE:=Qualcomm 802.11ax wireless chipset support (common code)
URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath11k
- DEPENDS+= +kmod-ath +@DRIVER_11AC_SUPPORT +@DRIVER_11AX_SUPPORT \
+ DEPENDS+= +kmod-ath +@DRIVER_11AC_SUPPORT +@DRIVER_11AX_SUPPORT @!LINUX_5_15 \
+kmod-crypto-michael-mic +ATH11K_THERMAL:kmod-hwmon-core +ATH11K_THERMAL:kmod-thermal
FILES:=$(PKG_BUILD_DIR)/drivers/soc/qcom/qmi_helpers.ko \
$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath11k/ath11k.ko
define KernelPackage/iwlwifi
$(call KernelPackage/mac80211/Default)
- DEPENDS:= +kmod-mac80211 +kmod-ptp @PCI_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11AX_SUPPORT
+ DEPENDS:= +kmod-mac80211 +kmod-ptp @PCI_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11AX_SUPPORT @!LINUX_5_15
TITLE:=Intel AGN Wireless support
FILES:= \
$(PKG_BUILD_DIR)/drivers/net/wireless/intel/iwlwifi/iwlwifi.ko \
+++ /dev/null
-From e8053643b6d70e23a634f14e4408f3a6d1d3a6bf Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@qq.com>
-Date: Sat, 27 May 2023 09:04:48 +0000
-Subject: [PATCH] wifi: ath: add struct_group for struct ath_cycle_counters
-
-Add a struct_group to around all members in struct ath_cycle_counters.
-It can help the compiler detect the intended bounds of the memcpy() and
-memset().
-
-This patch fixes the following build warning:
-
-In function 'fortify_memset_chk',
- inlined from 'ath9k_ps_wakeup' at /home/db/openwrt/build_dir/target-mips_24kc_musl/linux-ath79_generic/backports-6.1.24/drivers/net/wireless/ath/ath9k/main.c:140:3:
-./include/linux/fortify-string.h:314:25: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning]
- 314 | __write_overflow_field(p_size_field, size);
- | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Signed-off-by: Shiji Yang <yangshiji66@qq.com>
----
- drivers/net/wireless/ath/ath.h | 10 ++++++----
- drivers/net/wireless/ath/ath5k/ani.c | 2 +-
- drivers/net/wireless/ath/ath5k/base.c | 4 ++--
- drivers/net/wireless/ath/ath5k/mac80211-ops.c | 2 +-
- drivers/net/wireless/ath/ath9k/link.c | 2 +-
- drivers/net/wireless/ath/ath9k/main.c | 4 ++--
- drivers/net/wireless/ath/hw.c | 2 +-
- 7 files changed, 14 insertions(+), 12 deletions(-)
-
---- a/drivers/net/wireless/ath/ath.h
-+++ b/drivers/net/wireless/ath/ath.h
-@@ -43,10 +43,12 @@ struct ath_ani {
- };
-
- struct ath_cycle_counters {
-- u32 cycles;
-- u32 rx_busy;
-- u32 rx_frame;
-- u32 tx_frame;
-+ struct_group(cnts,
-+ u32 cycles;
-+ u32 rx_busy;
-+ u32 rx_frame;
-+ u32 tx_frame;
-+ );
- };
-
- enum ath_device_state {
---- a/drivers/net/wireless/ath/ath5k/ani.c
-+++ b/drivers/net/wireless/ath/ath5k/ani.c
-@@ -379,7 +379,7 @@ ath5k_hw_ani_get_listen_time(struct ath5
- spin_lock_bh(&common->cc_lock);
-
- ath_hw_cycle_counters_update(common);
-- memcpy(&as->last_cc, &common->cc_ani, sizeof(as->last_cc));
-+ memcpy(&as->last_cc.cnts, &common->cc_ani.cnts, sizeof(as->last_cc.cnts));
-
- /* clears common->cc_ani */
- listen = ath_hw_get_listen_time(common);
---- a/drivers/net/wireless/ath/ath5k/base.c
-+++ b/drivers/net/wireless/ath/ath5k/base.c
-@@ -2985,8 +2985,8 @@ ath5k_reset(struct ath5k_hw *ah, struct
- memset(&ah->survey, 0, sizeof(ah->survey));
- spin_lock_bh(&common->cc_lock);
- ath_hw_cycle_counters_update(common);
-- memset(&common->cc_survey, 0, sizeof(common->cc_survey));
-- memset(&common->cc_ani, 0, sizeof(common->cc_ani));
-+ memset(&common->cc_survey.cnts, 0, sizeof(common->cc_survey.cnts));
-+ memset(&common->cc_ani.cnts, 0, sizeof(common->cc_ani.cnts));
- spin_unlock_bh(&common->cc_lock);
-
- /*
---- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
-+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
-@@ -664,7 +664,7 @@ ath5k_get_survey(struct ieee80211_hw *hw
- ah->survey.time_rx += cc->rx_frame / div;
- ah->survey.time_tx += cc->tx_frame / div;
- }
-- memset(cc, 0, sizeof(*cc));
-+ memset(&cc->cnts, 0, sizeof(cc->cnts));
- spin_unlock_bh(&common->cc_lock);
-
- memcpy(survey, &ah->survey, sizeof(*survey));
---- a/drivers/net/wireless/ath/ath9k/link.c
-+++ b/drivers/net/wireless/ath/ath9k/link.c
-@@ -536,7 +536,7 @@ int ath_update_survey_stats(struct ath_s
- if (cc->cycles > 0)
- ret = cc->rx_busy * 100 / cc->cycles;
-
-- memset(cc, 0, sizeof(*cc));
-+ memset(&cc->cnts, 0, sizeof(cc->cnts));
-
- ath_update_survey_nf(sc, pos);
-
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -135,8 +135,8 @@ void ath9k_ps_wakeup(struct ath_softc *s
- if (power_mode != ATH9K_PM_AWAKE) {
- spin_lock(&common->cc_lock);
- ath_hw_cycle_counters_update(common);
-- memset(&common->cc_survey, 0, sizeof(common->cc_survey));
-- memset(&common->cc_ani, 0, sizeof(common->cc_ani));
-+ memset(&common->cc_survey.cnts, 0, sizeof(common->cc_survey.cnts));
-+ memset(&common->cc_ani.cnts, 0, sizeof(common->cc_ani.cnts));
- spin_unlock(&common->cc_lock);
- }
-
---- a/drivers/net/wireless/ath/hw.c
-+++ b/drivers/net/wireless/ath/hw.c
-@@ -183,7 +183,7 @@ int32_t ath_hw_get_listen_time(struct at
- listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) /
- (common->clockrate * 1000);
-
-- memset(cc, 0, sizeof(*cc));
-+ memset(&cc->cnts, 0, sizeof(cc->cnts));
-
- return listen_time;
- }
help
--- a/local-symbols
+++ b/local-symbols
-@@ -101,6 +101,7 @@ ADM8211=
+@@ -94,6 +94,7 @@ ADM8211=
ATH_COMMON=
WLAN_VENDOR_ATH=
ATH_DEBUG=
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
-@@ -3340,6 +3340,8 @@ void regulatory_hint_country_ie(struct w
+@@ -3364,6 +3364,8 @@ void regulatory_hint_country_ie(struct w
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request = NULL, *lr;
/* IE len must be evenly divisible by 2 */
if (country_ie_len & 0x01)
return;
-@@ -3591,6 +3593,7 @@ static bool is_wiphy_all_set_reg_flag(en
+@@ -3615,6 +3617,7 @@ static bool is_wiphy_all_set_reg_flag(en
void regulatory_hint_disconnect(void)
{
static bool
ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
@@ -79,6 +80,19 @@ ath5k_pci_eeprom_read(struct ath_common
- struct ath5k_hw *ah = (struct ath5k_hw *) common->ah;
+ struct ath5k_hw *ah = common->ah;
u32 status, timeout;
+ struct ath5k_platform_data *pdata = NULL;
+++ /dev/null
-[PATCH 1/2] carl9170: re-fix fortified-memset warning
-@ 2023-06-23 15:23 Arnd Bergmann
- 2023-06-23 15:24 ` [PATCH 2/2] mac80211: make ieee80211_tx_info padding explicit Arnd Bergmann
- ` (2 more replies)
- 0 siblings, 3 replies; 9+ messages in thread
-From: Arnd Bergmann @ 2023-06-23 15:23 UTC (permalink / raw)
- To: Christian Lamparter, Kalle Valo, Kees Cook, Johannes Berg
- Cc: Arnd Bergmann, linux-wireless, linux-kernel
-
-From: Arnd Bergmann <arnd@arndb.de>
-
-The carl9170_tx_release() function sometimes triggers a fortified-memset
-warning in my randconfig builds:
-
-In file included from include/linux/string.h:254,
- from drivers/net/wireless/ath/carl9170/tx.c:40:
-In function 'fortify_memset_chk',
- inlined from 'carl9170_tx_release' at drivers/net/wireless/ath/carl9170/tx.c:283:2,
- inlined from 'kref_put' at include/linux/kref.h:65:3,
- inlined from 'carl9170_tx_put_skb' at drivers/net/wireless/ath/carl9170/tx.c:342:9:
-include/linux/fortify-string.h:493:25: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning]
- 493 | __write_overflow_field(p_size_field, size);
-
-Kees previously tried to avoid this by using memset_after(), but it seems
-this does not fully address the problem. I noticed that the memset_after()
-here is done on a different part of the union (status) than the original
-cast was from (rate_driver_data), which may confuse the compiler.
-
-Unfortunately, the memset_after() trick does not work on driver_rates[]
-because that is part of an anonymous struct, and I could not get
-struct_group() to do this either. Using two separate memset() calls
-on the two members does address the warning though.
-
-Fixes: fb5f6a0e8063b ("mac80211: Use memset_after() to clear tx status")
-Signed-off-by: Arnd Bergmann <arnd@arndb.de>
----
- drivers/net/wireless/ath/carl9170/tx.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/wireless/ath/carl9170/tx.c
-+++ b/drivers/net/wireless/ath/carl9170/tx.c
-@@ -280,7 +280,8 @@ static void carl9170_tx_release(struct k
- * carl9170_tx_fill_rateinfo() has filled the rate information
- * before we get to this point.
- */
-- memset_after(&txinfo->status, 0, rates);
-+ memset(&txinfo->pad, 0, sizeof(txinfo->pad));
-+ memset(&txinfo->rate_driver_data, 0, sizeof(txinfo->rate_driver_data));
-
- if (atomic_read(&ar->tx_total_queued))
- ar->tx_schedule = true;
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
-@@ -87,6 +87,12 @@ config ATH10K_TRACING
+@@ -88,6 +88,12 @@ config ATH10K_TRACING
help
Select this to ath10k use tracing infrastructure.
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
--- a/local-symbols
+++ b/local-symbols
-@@ -160,6 +160,7 @@ ATH10K_SNOC=
+@@ -153,6 +153,7 @@ ATH10K_SNOC=
ATH10K_DEBUG=
ATH10K_DEBUGFS=
ATH10K_SPECTRAL=
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -3507,6 +3507,16 @@ int ath10k_core_register(struct ath10k *
+@@ -3527,6 +3527,16 @@ int ath10k_core_register(struct ath10k *
queue_work(ar->workqueue, &ar->register_work);
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -9917,6 +9917,21 @@ static int ath10k_mac_init_rd(struct ath
+@@ -9918,6 +9918,21 @@ static int ath10k_mac_init_rd(struct ath
return 0;
}
int ath10k_mac_register(struct ath10k *ar)
{
static const u32 cipher_suites[] = {
-@@ -10275,6 +10290,12 @@ int ath10k_mac_register(struct ath10k *a
+@@ -10280,6 +10295,12 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
-@@ -72,6 +72,12 @@ config ATH10K_DEBUGFS
+@@ -73,6 +73,12 @@ config ATH10K_DEBUGFS
If unsure, say Y to make it easier to debug problems.
ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o
--- a/local-symbols
+++ b/local-symbols
-@@ -161,6 +161,7 @@ ATH10K_DEBUG=
+@@ -154,6 +154,7 @@ ATH10K_DEBUG=
ATH10K_DEBUGFS=
ATH10K_SPECTRAL=
ATH10K_THERMAL=
WCN36XX=
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -26,6 +26,7 @@
+@@ -27,6 +27,7 @@
#include "testmode.h"
#include "wmi-ops.h"
#include "coredump.h"
unsigned int ath10k_debug_mask;
EXPORT_SYMBOL(ath10k_debug_mask);
-@@ -67,6 +68,7 @@ static const struct ath10k_hw_params ath
+@@ -68,6 +69,7 @@ static const struct ath10k_hw_params ath
.name = "qca988x hw2.0",
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
-@@ -107,6 +109,7 @@ static const struct ath10k_hw_params ath
+@@ -109,6 +111,7 @@ static const struct ath10k_hw_params ath
.name = "qca988x hw2.0 ubiquiti",
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
-@@ -148,6 +151,7 @@ static const struct ath10k_hw_params ath
+@@ -151,6 +154,7 @@ static const struct ath10k_hw_params ath
.name = "qca9887 hw1.0",
.patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
-@@ -189,6 +193,7 @@ static const struct ath10k_hw_params ath
+@@ -193,6 +197,7 @@ static const struct ath10k_hw_params ath
.name = "qca6174 hw3.2 sdio",
.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
.uart_pin = 19,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
-@@ -225,6 +230,7 @@ static const struct ath10k_hw_params ath
+@@ -230,6 +235,7 @@ static const struct ath10k_hw_params ath
.name = "qca6164 hw2.1",
.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
.uart_pin = 6,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
-@@ -265,6 +271,7 @@ static const struct ath10k_hw_params ath
+@@ -271,6 +277,7 @@ static const struct ath10k_hw_params ath
.name = "qca6174 hw2.1",
.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
.uart_pin = 6,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
-@@ -305,6 +312,7 @@ static const struct ath10k_hw_params ath
+@@ -312,6 +319,7 @@ static const struct ath10k_hw_params ath
.name = "qca6174 hw3.0",
.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
-@@ -345,6 +353,7 @@ static const struct ath10k_hw_params ath
+@@ -353,6 +361,7 @@ static const struct ath10k_hw_params ath
.name = "qca6174 hw3.2",
.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
-@@ -389,6 +398,7 @@ static const struct ath10k_hw_params ath
+@@ -398,6 +407,7 @@ static const struct ath10k_hw_params ath
.name = "qca99x0 hw2.0",
.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.otp_exe_param = 0x00000700,
.continuous_frag_desc = true,
.cck_rate_map_rev2 = true,
-@@ -435,6 +445,7 @@ static const struct ath10k_hw_params ath
+@@ -445,6 +455,7 @@ static const struct ath10k_hw_params ath
.name = "qca9984/qca9994 hw1.0",
.patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
.otp_exe_param = 0x00000700,
.continuous_frag_desc = true,
-@@ -488,6 +499,7 @@ static const struct ath10k_hw_params ath
+@@ -499,6 +510,7 @@ static const struct ath10k_hw_params ath
.name = "qca9888 hw2.0",
.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
.otp_exe_param = 0x00000700,
.continuous_frag_desc = true,
-@@ -538,6 +550,7 @@ static const struct ath10k_hw_params ath
+@@ -550,6 +562,7 @@ static const struct ath10k_hw_params ath
.name = "qca9377 hw1.0",
.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
-@@ -578,6 +591,7 @@ static const struct ath10k_hw_params ath
+@@ -591,6 +604,7 @@ static const struct ath10k_hw_params ath
.name = "qca9377 hw1.1",
.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
-@@ -620,6 +634,7 @@ static const struct ath10k_hw_params ath
+@@ -634,6 +648,7 @@ static const struct ath10k_hw_params ath
.name = "qca9377 hw1.1 sdio",
.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 19,
.otp_exe_param = 0,
.channel_counters_freq_hz = 88000,
.max_probe_resp_desc_thres = 0,
-@@ -653,6 +668,7 @@ static const struct ath10k_hw_params ath
+@@ -668,6 +683,7 @@ static const struct ath10k_hw_params ath
.name = "qca4019 hw1.0",
.patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
.otp_exe_param = 0x0010000,
.continuous_frag_desc = true,
-@@ -698,6 +714,7 @@ static const struct ath10k_hw_params ath
+@@ -714,6 +730,7 @@ static const struct ath10k_hw_params ath
.dev_id = 0,
.bus = ATH10K_BUS_SNOC,
.name = "wcn3990 hw1.0",
.continuous_frag_desc = true,
.tx_chain_mask = 0x7,
.rx_chain_mask = 0x7,
-@@ -3222,6 +3239,10 @@ int ath10k_core_start(struct ath10k *ar,
+@@ -3242,6 +3259,10 @@ int ath10k_core_start(struct ath10k *ar,
goto err_hif_stop;
}
return 0;
err_hif_stop:
-@@ -3480,9 +3501,18 @@ static void ath10k_core_register_work(st
+@@ -3500,9 +3521,18 @@ static void ath10k_core_register_work(st
goto err_spectral_destroy;
}
err_spectral_destroy:
ath10k_spectral_destroy(ar);
err_debug_destroy:
-@@ -3528,6 +3558,8 @@ void ath10k_core_unregister(struct ath10
+@@ -3548,6 +3578,8 @@ void ath10k_core_unregister(struct ath10
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
return;
* relayfs debugfs file cleanly. Otherwise the parent debugfs tree
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
-@@ -14,6 +14,7 @@
+@@ -15,6 +15,7 @@
#include <linux/pci.h>
#include <linux/uuid.h>
#include <linux/time.h>
#include "htt.h"
#include "htc.h"
-@@ -1256,6 +1257,13 @@ struct ath10k {
+@@ -1257,6 +1258,13 @@ struct ath10k {
} testmode;
struct {
u32 fw_crash_counter;
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
-@@ -519,6 +519,7 @@ struct ath10k_hw_params {
+@@ -521,6 +521,7 @@ struct ath10k_hw_params {
const char *name;
u32 patch_load_addr;
int uart_pin;
+#endif /* _LEDS_H_ */
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -24,6 +24,7 @@
+@@ -25,6 +25,7 @@
#include "wmi-tlv.h"
#include "wmi-ops.h"
#include "wow.h"
{
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
-@@ -4601,6 +4601,8 @@ static const struct wmi_ops wmi_tlv_ops
+@@ -4606,6 +4606,8 @@ static const struct wmi_ops wmi_tlv_ops
.gen_echo = ath10k_wmi_tlv_op_gen_echo,
.gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf,
.gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable,
static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
-@@ -7472,6 +7472,49 @@ ath10k_wmi_op_gen_peer_set_param(struct
+@@ -7493,6 +7493,49 @@ ath10k_wmi_op_gen_peer_set_param(struct
return skb;
}
static struct sk_buff *
ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
enum wmi_sta_ps_mode psmode)
-@@ -9138,6 +9181,9 @@ static const struct wmi_ops wmi_ops = {
+@@ -9157,6 +9200,9 @@ static const struct wmi_ops wmi_ops = {
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_op_gen_echo,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -9208,6 +9254,8 @@ static const struct wmi_ops wmi_10_1_ops
+@@ -9227,6 +9273,8 @@ static const struct wmi_ops wmi_10_1_ops
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_op_gen_echo,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -9280,6 +9328,8 @@ static const struct wmi_ops wmi_10_2_ops
+@@ -9299,6 +9347,8 @@ static const struct wmi_ops wmi_10_2_ops
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
/* .gen_pdev_enable_adaptive_cca not implemented */
};
-@@ -9351,6 +9401,8 @@ static const struct wmi_ops wmi_10_2_4_o
+@@ -9370,6 +9420,8 @@ static const struct wmi_ops wmi_10_2_4_o
ath10k_wmi_op_gen_pdev_enable_adaptive_cca,
.get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype,
.gen_bb_timing = ath10k_wmi_10_2_4_op_gen_bb_timing,
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
-@@ -9432,6 +9484,8 @@ static const struct wmi_ops wmi_10_4_ops
+@@ -9451,6 +9503,8 @@ static const struct wmi_ops wmi_10_4_ops
.gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
.gen_echo = ath10k_wmi_op_gen_echo,
.gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config,
int ath10k_wmi_attach(struct ath10k *ar)
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
-@@ -3030,6 +3030,41 @@ enum wmi_10_4_feature_mask {
+@@ -3034,6 +3034,41 @@ enum wmi_10_4_feature_mask {
};
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
-@@ -1312,6 +1312,10 @@ struct ath10k {
+@@ -1313,6 +1313,10 @@ struct ath10k {
s32 tx_power_2g_limit;
s32 tx_power_5g_limit;
if (ret)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -10292,7 +10292,7 @@ int ath10k_mac_register(struct ath10k *a
+@@ -10297,7 +10297,7 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;
#ifdef CPTCFG_MAC80211_LEDS
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -1028,6 +1028,40 @@ static inline int ath10k_vdev_setup_sync
+@@ -1022,6 +1022,40 @@ static inline int ath10k_vdev_setup_sync
return ar->last_wmi_vdev_start_status;
}
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
struct cfg80211_chan_def *chandef = NULL;
-@@ -1060,7 +1094,8 @@ static int ath10k_monitor_vdev_start(str
+@@ -1054,7 +1088,8 @@ static int ath10k_monitor_vdev_start(str
arg.channel.min_power = 0;
arg.channel.max_power = channel->max_power * 2;
arg.channel.max_reg_power = channel->max_reg_power * 2;
reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
-@@ -1506,7 +1541,8 @@ static int ath10k_vdev_start_restart(str
+@@ -1500,7 +1535,8 @@ static int ath10k_vdev_start_restart(str
arg.channel.min_power = 0;
arg.channel.max_power = chandef->chan->max_power * 2;
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
-@@ -3437,7 +3473,8 @@ static int ath10k_update_channel_list(st
+@@ -3431,7 +3467,8 @@ static int ath10k_update_channel_list(st
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -8,6 +8,7 @@
+@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/dmi.h>
#include <linux/ctype.h>
-@@ -3409,6 +3410,8 @@ static int ath10k_core_probe_fw(struct a
+@@ -3429,6 +3430,8 @@ static int ath10k_core_probe_fw(struct a
device_get_mac_address(ar->dev, ar->mac_addr);
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -10088,7 +10088,6 @@ int ath10k_mac_register(struct ath10k *a
+@@ -10089,7 +10089,6 @@ int ath10k_mac_register(struct ath10k *a
ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
-@@ -235,7 +235,11 @@ enum htt_rx_ring_flags {
+@@ -236,7 +236,11 @@ enum htt_rx_ring_flags {
};
#define HTT_RX_RING_SIZE_MIN 128
#define HTT_RX_RING_FILL_LEVEL_DUAL_MAC (HTT_RX_RING_SIZE - 1)
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
-@@ -131,7 +131,11 @@ static const struct ce_attr pci_host_ce_
+@@ -132,7 +132,11 @@ static const struct ce_attr pci_host_ce_
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.recv_cb = ath10k_pci_htt_htc_rx_cb,
},
-@@ -140,7 +144,11 @@ static const struct ce_attr pci_host_ce_
+@@ -141,7 +145,11 @@ static const struct ce_attr pci_host_ce_
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.recv_cb = ath10k_pci_htc_rx_cb,
},
-@@ -167,7 +175,11 @@ static const struct ce_attr pci_host_ce_
+@@ -168,7 +176,11 @@ static const struct ce_attr pci_host_ce_
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 512,
.recv_cb = ath10k_pci_htt_rx_cb,
},
-@@ -192,7 +204,11 @@ static const struct ce_attr pci_host_ce_
+@@ -193,7 +205,11 @@ static const struct ce_attr pci_host_ce_
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
+++ /dev/null
-From 4a93b554cf9fa64faa7cf164c0d32fc3ce67108b Mon Sep 17 00:00:00 2001
-From: Arowa Suliman <arowa@chromium.org>
-Date: Sat, 26 Aug 2023 08:42:42 +0300
-Subject: [PATCH] wifi: ath11k: mhi: add a warning message for MHI_CB_EE_RDDM
- crash
-
-Currently, the ath11k driver does not print a crash signature when a
-MHI_CB_EE_RDDM crash happens. Checked by triggering a simulated crash using the
-command and checking dmesg for logs:
-
-echo assert > /sys/kernel/debug/ath11k/../simulate_fw_crash
-
-Add a warning when firmware crash MHI_CB_EE_RDDM happens.
-
-Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23
-
-Signed-off-by: Arowa Suliman <arowa@chromium.org>
-Reviewed-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230714001126.463127-1-arowa@chromium.org
----
- drivers/net/wireless/ath/ath11k/mhi.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/wireless/ath/ath11k/mhi.c
-+++ b/drivers/net/wireless/ath/ath11k/mhi.c
-@@ -333,6 +333,7 @@ static void ath11k_mhi_op_status_cb(stru
- ath11k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");
- break;
- case MHI_CB_EE_RDDM:
-+ ath11k_warn(ab, "firmware crashed: MHI_CB_EE_RDDM\n");
- if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)))
- queue_work(ab->workqueue_aux, &ab->reset_work);
- break;
+++ /dev/null
-From 5bd2ced044bb95029d5c44cf7d23ced73e0fc05b Mon Sep 17 00:00:00 2001
-From: Muna Sinada <quic_msinada@quicinc.com>
-Date: Sat, 26 Aug 2023 08:42:46 +0300
-Subject: [PATCH] wifi: ath11k: move references from rsvd2 to info fields
-
-Remove references to reserved fields and add new info fields for
-struct hal_rx_ppdu_end_user_stats. Reserved fields should not be
-accessed, therefore existing references to it are to be changed to
-referencing specific info fields.
-
-Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00356-QCAHKSWPL_SILICONZ-1
-
-Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/1692827868-15667-1-git-send-email-quic_msinada@quicinc.com
----
- drivers/net/wireless/ath/ath11k/hal_rx.c | 10 +++++-----
- drivers/net/wireless/ath/ath11k/hal_rx.h | 11 ++++++++---
- 2 files changed, 13 insertions(+), 8 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/hal_rx.c
-+++ b/drivers/net/wireless/ath/ath11k/hal_rx.c
-@@ -814,7 +814,7 @@ ath11k_hal_rx_handle_ofdma_info(void *rx
-
- rx_user_status->ul_ofdma_user_v0_word0 = __le32_to_cpu(ppdu_end_user->info6);
-
-- rx_user_status->ul_ofdma_user_v0_word1 = __le32_to_cpu(ppdu_end_user->rsvd2[10]);
-+ rx_user_status->ul_ofdma_user_v0_word1 = __le32_to_cpu(ppdu_end_user->info9);
- }
-
- static inline void
-@@ -825,11 +825,11 @@ ath11k_hal_rx_populate_byte_count(void *
- (struct hal_rx_ppdu_end_user_stats *)rx_tlv;
-
- rx_user_status->mpdu_ok_byte_count =
-- FIELD_GET(HAL_RX_PPDU_END_USER_STATS_RSVD2_6_MPDU_OK_BYTE_COUNT,
-- __le32_to_cpu(ppdu_end_user->rsvd2[6]));
-+ FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_OK_BYTE_COUNT,
-+ __le32_to_cpu(ppdu_end_user->info7));
- rx_user_status->mpdu_err_byte_count =
-- FIELD_GET(HAL_RX_PPDU_END_USER_STATS_RSVD2_8_MPDU_ERR_BYTE_COUNT,
-- __le32_to_cpu(ppdu_end_user->rsvd2[8]));
-+ FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO9_MPDU_ERR_BYTE_COUNT,
-+ __le32_to_cpu(ppdu_end_user->info8));
- }
-
- static inline void
---- a/drivers/net/wireless/ath/ath11k/hal_rx.h
-+++ b/drivers/net/wireless/ath/ath11k/hal_rx.h
-@@ -222,8 +222,8 @@ struct hal_rx_ppdu_start {
- #define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP GENMASK(15, 0)
- #define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_EOSP_BITMAP GENMASK(31, 16)
-
--#define HAL_RX_PPDU_END_USER_STATS_RSVD2_6_MPDU_OK_BYTE_COUNT GENMASK(24, 0)
--#define HAL_RX_PPDU_END_USER_STATS_RSVD2_8_MPDU_ERR_BYTE_COUNT GENMASK(24, 0)
-+#define HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT GENMASK(24, 0)
-+#define HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT GENMASK(24, 0)
-
- struct hal_rx_ppdu_end_user_stats {
- __le32 rsvd0[2];
-@@ -236,7 +236,12 @@ struct hal_rx_ppdu_end_user_stats {
- __le32 info4;
- __le32 info5;
- __le32 info6;
-- __le32 rsvd2[11];
-+ __le32 rsvd2[5];
-+ __le32 info7;
-+ __le32 rsvd3;
-+ __le32 info8;
-+ __le32 rsvd3[2];
-+ __le32 info9;
- } __packed;
-
- struct hal_rx_ppdu_end_user_stats_ext {
+++ /dev/null
-From 7791487cd16cafd018cba0bf73789111a9f16843 Mon Sep 17 00:00:00 2001
-From: Muna Sinada <quic_msinada@quicinc.com>
-Date: Sat, 26 Aug 2023 08:42:46 +0300
-Subject: [PATCH] wifi: ath11k: fix tid bitmap is 0 in peer rx mu stats
-
-Correct parsing of reading offset for rx tid 16 bit bitmap. Incorrect
-offset caused peer rx mu stats tid bitmap to always be zero. This
-correction is in the software context and does not affect the
-firmware interface.
-
-Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00356-QCAHKSWPL_SILICONZ-1
-
-Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/1692827868-15667-2-git-send-email-quic_msinada@quicinc.com
----
- drivers/net/wireless/ath/ath11k/hal_rx.c | 10 +++++-----
- drivers/net/wireless/ath/ath11k/hal_rx.h | 17 +++++++++--------
- 2 files changed, 14 insertions(+), 13 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/hal_rx.c
-+++ b/drivers/net/wireless/ath/ath11k/hal_rx.c
-@@ -814,7 +814,7 @@ ath11k_hal_rx_handle_ofdma_info(void *rx
-
- rx_user_status->ul_ofdma_user_v0_word0 = __le32_to_cpu(ppdu_end_user->info6);
-
-- rx_user_status->ul_ofdma_user_v0_word1 = __le32_to_cpu(ppdu_end_user->info9);
-+ rx_user_status->ul_ofdma_user_v0_word1 = __le32_to_cpu(ppdu_end_user->info10);
- }
-
- static inline void
-@@ -826,10 +826,10 @@ ath11k_hal_rx_populate_byte_count(void *
-
- rx_user_status->mpdu_ok_byte_count =
- FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_OK_BYTE_COUNT,
-- __le32_to_cpu(ppdu_end_user->info7));
-+ __le32_to_cpu(ppdu_end_user->info8));
- rx_user_status->mpdu_err_byte_count =
- FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO9_MPDU_ERR_BYTE_COUNT,
-- __le32_to_cpu(ppdu_end_user->info8));
-+ __le32_to_cpu(ppdu_end_user->info9));
- }
-
- static inline void
-@@ -903,8 +903,8 @@ ath11k_hal_rx_parse_mon_status_tlv(struc
- FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX,
- __le32_to_cpu(eu_stats->info2));
- ppdu_info->tid =
-- ffs(FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP,
-- __le32_to_cpu(eu_stats->info6))) - 1;
-+ ffs(FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO7_TID_BITMAP,
-+ __le32_to_cpu(eu_stats->info7))) - 1;
- ppdu_info->tcp_msdu_count =
- FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO4_TCP_MSDU_CNT,
- __le32_to_cpu(eu_stats->info4));
---- a/drivers/net/wireless/ath/ath11k/hal_rx.h
-+++ b/drivers/net/wireless/ath/ath11k/hal_rx.h
-@@ -149,7 +149,7 @@ struct hal_rx_mon_ppdu_info {
- u8 beamformed;
- u8 rssi_comb;
- u8 rssi_chain_pri20[HAL_RX_MAX_NSS];
-- u8 tid;
-+ u16 tid;
- u16 ht_flags;
- u16 vht_flags;
- u16 he_flags;
-@@ -219,11 +219,11 @@ struct hal_rx_ppdu_start {
- #define HAL_RX_PPDU_END_USER_STATS_INFO5_OTHER_MSDU_CNT GENMASK(15, 0)
- #define HAL_RX_PPDU_END_USER_STATS_INFO5_TCP_ACK_MSDU_CNT GENMASK(31, 16)
-
--#define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP GENMASK(15, 0)
--#define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_EOSP_BITMAP GENMASK(31, 16)
-+#define HAL_RX_PPDU_END_USER_STATS_INFO7_TID_BITMAP GENMASK(15, 0)
-+#define HAL_RX_PPDU_END_USER_STATS_INFO7_TID_EOSP_BITMAP GENMASK(31, 16)
-
--#define HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT GENMASK(24, 0)
--#define HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT GENMASK(24, 0)
-+#define HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_OK_BYTE_COUNT GENMASK(24, 0)
-+#define HAL_RX_PPDU_END_USER_STATS_INFO9_MPDU_ERR_BYTE_COUNT GENMASK(24, 0)
-
- struct hal_rx_ppdu_end_user_stats {
- __le32 rsvd0[2];
-@@ -236,12 +236,13 @@ struct hal_rx_ppdu_end_user_stats {
- __le32 info4;
- __le32 info5;
- __le32 info6;
-- __le32 rsvd2[5];
- __le32 info7;
-- __le32 rsvd3;
-+ __le32 rsvd2[4];
- __le32 info8;
-- __le32 rsvd3[2];
-+ __le32 rsvd3;
- __le32 info9;
-+ __le32 rsvd4[2];
-+ __le32 info10;
- } __packed;
-
- struct hal_rx_ppdu_end_user_stats_ext {
+++ /dev/null
-From 1133af5aea588a58043244a4ecb5ce511b310356 Mon Sep 17 00:00:00 2001
-From: Wen Gong <quic_wgong@quicinc.com>
-Date: Wed, 30 Aug 2023 02:02:26 -0400
-Subject: [PATCH] wifi: ath11k: add chip id board name while searching
- board-2.bin for WCN6855
-
-Sometimes board-2.bin does not have the board data which matched the
-parameters such as bus type, vendor, device, subsystem-vendor,
-subsystem-device, qmi-chip-id and qmi-board-id, then wlan will load fail.
-
-Hence add another type which only matches the bus type and qmi-chip-id,
-then the ratio of missing board data reduced.
-
-Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23
-
-Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230830060226.18664-1-quic_wgong@quicinc.com
----
- drivers/net/wireless/ath/ath11k/core.c | 108 ++++++++++++++++++++-----
- 1 file changed, 87 insertions(+), 21 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/core.c
-+++ b/drivers/net/wireless/ath/ath11k/core.c
-@@ -985,9 +985,15 @@ int ath11k_core_check_dt(struct ath11k_b
- return 0;
- }
-
-+enum ath11k_bdf_name_type {
-+ ATH11K_BDF_NAME_FULL,
-+ ATH11K_BDF_NAME_BUS_NAME,
-+ ATH11K_BDF_NAME_CHIP_ID,
-+};
-+
- static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name,
- size_t name_len, bool with_variant,
-- bool bus_type_mode)
-+ enum ath11k_bdf_name_type name_type)
- {
- /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
- char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = { 0 };
-@@ -998,11 +1004,8 @@ static int __ath11k_core_create_board_na
-
- switch (ab->id.bdf_search) {
- case ATH11K_BDF_SEARCH_BUS_AND_BOARD:
-- if (bus_type_mode)
-- scnprintf(name, name_len,
-- "bus=%s",
-- ath11k_bus_str(ab->hif.bus));
-- else
-+ switch (name_type) {
-+ case ATH11K_BDF_NAME_FULL:
- scnprintf(name, name_len,
- "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s",
- ath11k_bus_str(ab->hif.bus),
-@@ -1012,6 +1015,19 @@ static int __ath11k_core_create_board_na
- ab->qmi.target.chip_id,
- ab->qmi.target.board_id,
- variant);
-+ break;
-+ case ATH11K_BDF_NAME_BUS_NAME:
-+ scnprintf(name, name_len,
-+ "bus=%s",
-+ ath11k_bus_str(ab->hif.bus));
-+ break;
-+ case ATH11K_BDF_NAME_CHIP_ID:
-+ scnprintf(name, name_len,
-+ "bus=%s,qmi-chip-id=%d",
-+ ath11k_bus_str(ab->hif.bus),
-+ ab->qmi.target.chip_id);
-+ break;
-+ }
- break;
- default:
- scnprintf(name, name_len,
-@@ -1030,19 +1046,29 @@ static int __ath11k_core_create_board_na
- static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name,
- size_t name_len)
- {
-- return __ath11k_core_create_board_name(ab, name, name_len, true, false);
-+ return __ath11k_core_create_board_name(ab, name, name_len, true,
-+ ATH11K_BDF_NAME_FULL);
- }
-
- static int ath11k_core_create_fallback_board_name(struct ath11k_base *ab, char *name,
- size_t name_len)
- {
-- return __ath11k_core_create_board_name(ab, name, name_len, false, false);
-+ return __ath11k_core_create_board_name(ab, name, name_len, false,
-+ ATH11K_BDF_NAME_FULL);
- }
-
- static int ath11k_core_create_bus_type_board_name(struct ath11k_base *ab, char *name,
- size_t name_len)
- {
-- return __ath11k_core_create_board_name(ab, name, name_len, false, true);
-+ return __ath11k_core_create_board_name(ab, name, name_len, false,
-+ ATH11K_BDF_NAME_BUS_NAME);
-+}
-+
-+static int ath11k_core_create_chip_id_board_name(struct ath11k_base *ab, char *name,
-+ size_t name_len)
-+{
-+ return __ath11k_core_create_board_name(ab, name, name_len, false,
-+ ATH11K_BDF_NAME_CHIP_ID);
- }
-
- const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
-@@ -1289,16 +1315,21 @@ int ath11k_core_fetch_board_data_api_1(s
- #define BOARD_NAME_SIZE 200
- int ath11k_core_fetch_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd)
- {
-- char boardname[BOARD_NAME_SIZE], fallback_boardname[BOARD_NAME_SIZE];
-+ char *boardname = NULL, *fallback_boardname = NULL, *chip_id_boardname = NULL;
- char *filename, filepath[100];
-- int ret;
-+ int ret = 0;
-
- filename = ATH11K_BOARD_API2_FILE;
-+ boardname = kzalloc(BOARD_NAME_SIZE, GFP_KERNEL);
-+ if (!boardname) {
-+ ret = -ENOMEM;
-+ goto exit;
-+ }
-
-- ret = ath11k_core_create_board_name(ab, boardname, sizeof(boardname));
-+ ret = ath11k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);
- if (ret) {
- ath11k_err(ab, "failed to create board name: %d", ret);
-- return ret;
-+ goto exit;
- }
-
- ab->bd_api = 2;
-@@ -1307,13 +1338,19 @@ int ath11k_core_fetch_bdf(struct ath11k_
- ATH11K_BD_IE_BOARD_NAME,
- ATH11K_BD_IE_BOARD_DATA);
- if (!ret)
-- goto success;
-+ goto exit;
-+
-+ fallback_boardname = kzalloc(BOARD_NAME_SIZE, GFP_KERNEL);
-+ if (!fallback_boardname) {
-+ ret = -ENOMEM;
-+ goto exit;
-+ }
-
- ret = ath11k_core_create_fallback_board_name(ab, fallback_boardname,
-- sizeof(fallback_boardname));
-+ BOARD_NAME_SIZE);
- if (ret) {
- ath11k_err(ab, "failed to create fallback board name: %d", ret);
-- return ret;
-+ goto exit;
- }
-
- ret = ath11k_core_fetch_board_data_api_n(ab, bd, fallback_boardname,
-@@ -1321,7 +1358,28 @@ int ath11k_core_fetch_bdf(struct ath11k_
- ATH11K_BD_IE_BOARD_NAME,
- ATH11K_BD_IE_BOARD_DATA);
- if (!ret)
-- goto success;
-+ goto exit;
-+
-+ chip_id_boardname = kzalloc(BOARD_NAME_SIZE, GFP_KERNEL);
-+ if (!chip_id_boardname) {
-+ ret = -ENOMEM;
-+ goto exit;
-+ }
-+
-+ ret = ath11k_core_create_chip_id_board_name(ab, chip_id_boardname,
-+ BOARD_NAME_SIZE);
-+ if (ret) {
-+ ath11k_err(ab, "failed to create chip id board name: %d", ret);
-+ goto exit;
-+ }
-+
-+ ret = ath11k_core_fetch_board_data_api_n(ab, bd, chip_id_boardname,
-+ ATH11K_BD_IE_BOARD,
-+ ATH11K_BD_IE_BOARD_NAME,
-+ ATH11K_BD_IE_BOARD_DATA);
-+
-+ if (!ret)
-+ goto exit;
-
- ab->bd_api = 1;
- ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_DEFAULT_BOARD_FILE);
-@@ -1334,14 +1392,22 @@ int ath11k_core_fetch_bdf(struct ath11k_
- ath11k_err(ab, "failed to fetch board data for %s from %s\n",
- fallback_boardname, filepath);
-
-+ ath11k_err(ab, "failed to fetch board data for %s from %s\n",
-+ chip_id_boardname, filepath);
-+
- ath11k_err(ab, "failed to fetch board.bin from %s\n",
- ab->hw_params.fw.dir);
-- return ret;
- }
-
--success:
-- ath11k_dbg(ab, ATH11K_DBG_BOOT, "using board api %d\n", ab->bd_api);
-- return 0;
-+exit:
-+ kfree(boardname);
-+ kfree(fallback_boardname);
-+ kfree(chip_id_boardname);
-+
-+ if (!ret)
-+ ath11k_dbg(ab, ATH11K_DBG_BOOT, "using board api %d\n", ab->bd_api);
-+
-+ return ret;
- }
-
- int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd)
+++ /dev/null
-From ac13a7842ab46a87aa315514d6d7e19b03cb2adc Mon Sep 17 00:00:00 2001
-From: Dmitry Antipov <dmantipov@yandex.ru>
-Date: Wed, 6 Sep 2023 12:36:55 +0300
-Subject: [PATCH] wifi: ath11k: drop NULL pointer check in
- ath11k_update_per_peer_tx_stats()
-
-Since 'user_stats' is a fixed-size array of 'struct htt_ppdu_user_stats'
-in 'struct htt_ppdu_stats', any of its member can't be NULL and so
-relevant check may be dropped.
-
-Found by Linux Verification Center (linuxtesting.org) with SVACE.
-
-Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230906093704.14001-1-dmantipov@yandex.ru
----
- drivers/net/wireless/ath/ath11k/dp_rx.c | 3 ---
- 1 file changed, 3 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/dp_rx.c
-+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
-@@ -1388,9 +1388,6 @@ ath11k_update_per_peer_tx_stats(struct a
- u8 tid = HTT_PPDU_STATS_NON_QOS_TID;
- bool is_ampdu = false;
-
-- if (!usr_stats)
-- return;
--
- if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE)))
- return;
-
+++ /dev/null
-From 82ae3f4635382ff23e2ece55b5d5e713223951ec Mon Sep 17 00:00:00 2001
-From: Dmitry Antipov <dmantipov@yandex.ru>
-Date: Thu, 24 Aug 2023 10:50:44 +0300
-Subject: [PATCH] wifi: ath11k: drop redundant check in
- ath11k_dp_rx_mon_dest_process()
-
-In 'ath11k_dp_rx_mon_dest_process()', 'mon_dst_srng' points to
-a member of 'srng_list', which is a fixed-size array inside
-'struct ath11k_hal'. This way, if 'ring_id' is valid (i. e.
-between 0 and HAL_SRNG_RING_ID_MAX - 1 inclusive), 'mon_dst_srng'
-can't be NULL and so relevant check may be dropped.
-
-Found by Linux Verification Center (linuxtesting.org) with SVACE.
-
-Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230824075121.121144-1-dmantipov@yandex.ru
----
- drivers/net/wireless/ath/ath11k/dp_rx.c | 7 -------
- 1 file changed, 7 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/dp_rx.c
-+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
-@@ -5100,13 +5100,6 @@ static void ath11k_dp_rx_mon_dest_proces
-
- mon_dst_srng = &ar->ab->hal.srng_list[ring_id];
-
-- if (!mon_dst_srng) {
-- ath11k_warn(ar->ab,
-- "HAL Monitor Destination Ring Init Failed -- %p",
-- mon_dst_srng);
-- return;
-- }
--
- spin_lock_bh(&pmon->mon_lock);
-
- ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng);
+++ /dev/null
-From 9066794113c4813b6ce4a66ed6ce14ecdf35625d Mon Sep 17 00:00:00 2001
-From: Dmitry Antipov <dmantipov@yandex.ru>
-Date: Thu, 24 Aug 2023 10:50:45 +0300
-Subject: [PATCH] wifi: ath11k: remove unused members of 'struct ath11k_base'
-
-Remove set but otherwise unused 'wlan_init_status' and
-'wmi_ready' members of 'struct ath11k_base', adjust
-'ath11k_wmi_tlv_rdy_parse()' accordingly.
-
-Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230824075121.121144-2-dmantipov@yandex.ru
----
- drivers/net/wireless/ath/ath11k/core.h | 2 --
- drivers/net/wireless/ath/ath11k/wmi.c | 2 --
- 2 files changed, 4 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/core.h
-+++ b/drivers/net/wireless/ath/ath11k/core.h
-@@ -901,8 +901,6 @@ struct ath11k_base {
- struct list_head peers;
- wait_queue_head_t peer_mapping_wq;
- u8 mac_addr[ETH_ALEN];
-- bool wmi_ready;
-- u32 wlan_init_status;
- int irq_num[ATH11K_IRQ_NUM_MAX];
- struct ath11k_ext_irq_grp ext_irq_grp[ATH11K_EXT_IRQ_GRP_NUM_MAX];
- struct ath11k_targ_cap target_caps;
---- a/drivers/net/wireless/ath/ath11k/wmi.c
-+++ b/drivers/net/wireless/ath/ath11k/wmi.c
-@@ -7222,14 +7222,12 @@ static int ath11k_wmi_tlv_rdy_parse(stru
- memset(&fixed_param, 0, sizeof(fixed_param));
- memcpy(&fixed_param, (struct wmi_ready_event *)ptr,
- min_t(u16, sizeof(fixed_param), len));
-- ab->wlan_init_status = fixed_param.ready_event_min.status;
- rdy_parse->num_extra_mac_addr =
- fixed_param.ready_event_min.num_extra_mac_addr;
-
- ether_addr_copy(ab->mac_addr,
- fixed_param.ready_event_min.mac_addr.addr);
- ab->pktlog_defs_checksum = fixed_param.pktlog_defs_checksum;
-- ab->wmi_ready = true;
- break;
- case WMI_TAG_ARRAY_FIXED_STRUCT:
- addr_list = (struct wmi_mac_addr *)ptr;
+++ /dev/null
-From 458f66c30df2b8495790cf6fca76ebad44046921 Mon Sep 17 00:00:00 2001
-From: Dmitry Antipov <dmantipov@yandex.ru>
-Date: Thu, 21 Sep 2023 11:16:57 +0300
-Subject: [PATCH] wifi: ath11k: use kstrtoul_from_user() where appropriate
-
-Use 'kstrtoul_from_user()' in 'ath11k_write_file_spectral_count()'
-and 'ath11k_write_file_spectral_bins()'
-
-Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230824075121.121144-4-dmantipov@yandex.ru
----
- drivers/net/wireless/ath/ath11k/spectral.c | 26 +++++++---------------
- 1 file changed, 8 insertions(+), 18 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/spectral.c
-+++ b/drivers/net/wireless/ath/ath11k/spectral.c
-@@ -386,16 +386,11 @@ static ssize_t ath11k_write_file_spectra
- {
- struct ath11k *ar = file->private_data;
- unsigned long val;
-- char buf[32];
-- ssize_t len;
--
-- len = min(count, sizeof(buf) - 1);
-- if (copy_from_user(buf, user_buf, len))
-- return -EFAULT;
-+ ssize_t ret;
-
-- buf[len] = '\0';
-- if (kstrtoul(buf, 0, &val))
-- return -EINVAL;
-+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
-+ if (ret)
-+ return ret;
-
- if (val > ATH11K_SPECTRAL_SCAN_COUNT_MAX)
- return -EINVAL;
-@@ -441,16 +436,11 @@ static ssize_t ath11k_write_file_spectra
- {
- struct ath11k *ar = file->private_data;
- unsigned long val;
-- char buf[32];
-- ssize_t len;
--
-- len = min(count, sizeof(buf) - 1);
-- if (copy_from_user(buf, user_buf, len))
-- return -EFAULT;
-+ ssize_t ret;
-
-- buf[len] = '\0';
-- if (kstrtoul(buf, 0, &val))
-- return -EINVAL;
-+ ret = kstrtoul_from_user(user_buf, count, 0, &val);
-+ if (ret)
-+ return ret;
-
- if (val < ATH11K_SPECTRAL_MIN_BINS ||
- val > ar->ab->hw_params.spectral.max_fft_bins)
+++ /dev/null
-From 87fd0602610d6965c45afc61780ac98842e8f902 Mon Sep 17 00:00:00 2001
-From: Wu Yunchuan <yunchuan@nfschina.com>
-Date: Thu, 21 Sep 2023 11:50:05 +0300
-Subject: [PATCH] wifi: ath11k: remove unnecessary (void*) conversions
-
-No need cast (void *) to (struct ath11k_base *),
-struct hal_rx_msdu_link *), (struct ath11k_buffer_addr *) or
-other types.
-
-Signed-off-by: Wu Yunchuan <yunchuan@nfschina.com>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230919045150.524304-1-yunchuan@nfschina.com
----
- drivers/net/wireless/ath/ath11k/dp.c | 2 +-
- drivers/net/wireless/ath/ath11k/dp_rx.c | 13 +++++--------
- drivers/net/wireless/ath/ath11k/hal.c | 8 +++-----
- drivers/net/wireless/ath/ath11k/hal_rx.c | 17 +++++++----------
- drivers/net/wireless/ath/ath11k/hal_tx.c | 2 +-
- drivers/net/wireless/ath/ath11k/mac.c | 4 ++--
- drivers/net/wireless/ath/ath11k/spectral.c | 2 +-
- drivers/net/wireless/ath/ath11k/wmi.c | 6 +++---
- 8 files changed, 23 insertions(+), 31 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/dp.c
-+++ b/drivers/net/wireless/ath/ath11k/dp.c
-@@ -1009,7 +1009,7 @@ void ath11k_dp_vdev_tx_attach(struct ath
-
- static int ath11k_dp_tx_pending_cleanup(int buf_id, void *skb, void *ctx)
- {
-- struct ath11k_base *ab = (struct ath11k_base *)ctx;
-+ struct ath11k_base *ab = ctx;
- struct sk_buff *msdu = skb;
-
- dma_unmap_single(ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len,
---- a/drivers/net/wireless/ath/ath11k/dp_rx.c
-+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
-@@ -1256,7 +1256,7 @@ static int ath11k_htt_tlv_ppdu_stats_par
- int cur_user;
- u16 peer_id;
-
-- ppdu_info = (struct htt_ppdu_stats_info *)data;
-+ ppdu_info = data;
-
- switch (tag) {
- case HTT_PPDU_STATS_TAG_COMMON:
-@@ -4492,8 +4492,7 @@ int ath11k_dp_rx_monitor_link_desc_retur
- src_srng_desc = ath11k_hal_srng_src_get_next_entry(ar->ab, hal_srng);
-
- if (src_srng_desc) {
-- struct ath11k_buffer_addr *src_desc =
-- (struct ath11k_buffer_addr *)src_srng_desc;
-+ struct ath11k_buffer_addr *src_desc = src_srng_desc;
-
- *src_desc = *((struct ath11k_buffer_addr *)p_last_buf_addr_info);
- } else {
-@@ -4512,8 +4511,7 @@ void ath11k_dp_rx_mon_next_link_desc_get
- u8 *rbm,
- void **pp_buf_addr_info)
- {
-- struct hal_rx_msdu_link *msdu_link =
-- (struct hal_rx_msdu_link *)rx_msdu_link_desc;
-+ struct hal_rx_msdu_link *msdu_link = rx_msdu_link_desc;
- struct ath11k_buffer_addr *buf_addr_info;
-
- buf_addr_info = (struct ath11k_buffer_addr *)&msdu_link->buf_addr_info;
-@@ -4554,7 +4552,7 @@ static void ath11k_hal_rx_msdu_list_get(
- u32 first = FIELD_PREP(RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU, 1);
- u8 tmp = 0;
-
-- msdu_link = (struct hal_rx_msdu_link *)msdu_link_desc;
-+ msdu_link = msdu_link_desc;
- msdu_details = &msdu_link->msdu_link[0];
-
- for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) {
-@@ -4651,8 +4649,7 @@ ath11k_dp_rx_mon_mpdu_pop(struct ath11k
- bool is_frag, is_first_msdu;
- bool drop_mpdu = false;
- struct ath11k_skb_rxcb *rxcb;
-- struct hal_reo_entrance_ring *ent_desc =
-- (struct hal_reo_entrance_ring *)ring_entry;
-+ struct hal_reo_entrance_ring *ent_desc = ring_entry;
- int buf_id;
- u32 rx_link_buf_info[2];
- u8 rbm;
---- a/drivers/net/wireless/ath/ath11k/hal.c
-+++ b/drivers/net/wireless/ath/ath11k/hal.c
-@@ -571,7 +571,7 @@ u32 ath11k_hal_ce_get_desc_size(enum hal
- void ath11k_hal_ce_src_set_desc(void *buf, dma_addr_t paddr, u32 len, u32 id,
- u8 byte_swap_data)
- {
-- struct hal_ce_srng_src_desc *desc = (struct hal_ce_srng_src_desc *)buf;
-+ struct hal_ce_srng_src_desc *desc = buf;
-
- desc->buffer_addr_low = paddr & HAL_ADDR_LSB_REG_MASK;
- desc->buffer_addr_info =
-@@ -586,8 +586,7 @@ void ath11k_hal_ce_src_set_desc(void *bu
-
- void ath11k_hal_ce_dst_set_desc(void *buf, dma_addr_t paddr)
- {
-- struct hal_ce_srng_dest_desc *desc =
-- (struct hal_ce_srng_dest_desc *)buf;
-+ struct hal_ce_srng_dest_desc *desc = buf;
-
- desc->buffer_addr_low = paddr & HAL_ADDR_LSB_REG_MASK;
- desc->buffer_addr_info =
-@@ -597,8 +596,7 @@ void ath11k_hal_ce_dst_set_desc(void *bu
-
- u32 ath11k_hal_ce_dst_status_get_length(void *buf)
- {
-- struct hal_ce_srng_dst_status_desc *desc =
-- (struct hal_ce_srng_dst_status_desc *)buf;
-+ struct hal_ce_srng_dst_status_desc *desc = buf;
- u32 len;
-
- len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, desc->flags);
---- a/drivers/net/wireless/ath/ath11k/hal_rx.c
-+++ b/drivers/net/wireless/ath/ath11k/hal_rx.c
-@@ -265,7 +265,7 @@ out:
- void ath11k_hal_rx_buf_addr_info_set(void *desc, dma_addr_t paddr,
- u32 cookie, u8 manager)
- {
-- struct ath11k_buffer_addr *binfo = (struct ath11k_buffer_addr *)desc;
-+ struct ath11k_buffer_addr *binfo = desc;
- u32 paddr_lo, paddr_hi;
-
- paddr_lo = lower_32_bits(paddr);
-@@ -279,7 +279,7 @@ void ath11k_hal_rx_buf_addr_info_set(voi
- void ath11k_hal_rx_buf_addr_info_get(void *desc, dma_addr_t *paddr,
- u32 *cookie, u8 *rbm)
- {
-- struct ath11k_buffer_addr *binfo = (struct ath11k_buffer_addr *)desc;
-+ struct ath11k_buffer_addr *binfo = desc;
-
- *paddr =
- (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR, binfo->info1)) << 32) |
-@@ -292,7 +292,7 @@ void ath11k_hal_rx_msdu_link_info_get(vo
- u32 *msdu_cookies,
- enum hal_rx_buf_return_buf_manager *rbm)
- {
-- struct hal_rx_msdu_link *link = (struct hal_rx_msdu_link *)link_desc;
-+ struct hal_rx_msdu_link *link = link_desc;
- struct hal_rx_msdu_details *msdu;
- int i;
-
-@@ -699,7 +699,7 @@ u32 ath11k_hal_reo_qdesc_size(u32 ba_win
- void ath11k_hal_reo_qdesc_setup(void *vaddr, int tid, u32 ba_window_size,
- u32 start_seq, enum hal_pn_type type)
- {
-- struct hal_rx_reo_queue *qdesc = (struct hal_rx_reo_queue *)vaddr;
-+ struct hal_rx_reo_queue *qdesc = vaddr;
- struct hal_rx_reo_queue_ext *ext_desc;
-
- memset(qdesc, 0, sizeof(*qdesc));
-@@ -809,8 +809,7 @@ static inline void
- ath11k_hal_rx_handle_ofdma_info(void *rx_tlv,
- struct hal_rx_user_status *rx_user_status)
- {
-- struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
-- (struct hal_rx_ppdu_end_user_stats *)rx_tlv;
-+ struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
-
- rx_user_status->ul_ofdma_user_v0_word0 = __le32_to_cpu(ppdu_end_user->info6);
-
-@@ -821,8 +820,7 @@ static inline void
- ath11k_hal_rx_populate_byte_count(void *rx_tlv, void *ppduinfo,
- struct hal_rx_user_status *rx_user_status)
- {
-- struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
-- (struct hal_rx_ppdu_end_user_stats *)rx_tlv;
-+ struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
-
- rx_user_status->mpdu_ok_byte_count =
- FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_OK_BYTE_COUNT,
-@@ -1540,8 +1538,7 @@ void ath11k_hal_rx_reo_ent_buf_paddr_get
- u32 *sw_cookie, void **pp_buf_addr,
- u8 *rbm, u32 *msdu_cnt)
- {
-- struct hal_reo_entrance_ring *reo_ent_ring =
-- (struct hal_reo_entrance_ring *)rx_desc;
-+ struct hal_reo_entrance_ring *reo_ent_ring = rx_desc;
- struct ath11k_buffer_addr *buf_addr_info;
- struct rx_mpdu_desc *rx_mpdu_desc_info_details;
-
---- a/drivers/net/wireless/ath/ath11k/hal_tx.c
-+++ b/drivers/net/wireless/ath/ath11k/hal_tx.c
-@@ -37,7 +37,7 @@ static const u8 dscp_tid_map[DSCP_TID_MA
- void ath11k_hal_tx_cmd_desc_setup(struct ath11k_base *ab, void *cmd,
- struct hal_tx_info *ti)
- {
-- struct hal_tcl_data_cmd *tcl_cmd = (struct hal_tcl_data_cmd *)cmd;
-+ struct hal_tcl_data_cmd *tcl_cmd = cmd;
-
- tcl_cmd->buf_addr_info.info0 =
- FIELD_PREP(BUFFER_ADDR_INFO0_ADDR, ti->paddr);
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -6970,8 +6970,8 @@ err:
-
- static int ath11k_mac_vif_unref(int buf_id, void *skb, void *ctx)
- {
-- struct ieee80211_vif *vif = (struct ieee80211_vif *)ctx;
-- struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
-+ struct ieee80211_vif *vif = ctx;
-+ struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
-
- if (skb_cb->vif == vif)
- skb_cb->vif = NULL;
---- a/drivers/net/wireless/ath/ath11k/spectral.c
-+++ b/drivers/net/wireless/ath/ath11k/spectral.c
-@@ -592,7 +592,7 @@ int ath11k_spectral_process_fft(struct a
- return -EINVAL;
- }
-
-- tlv = (struct spectral_tlv *)data;
-+ tlv = data;
- tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header));
- /* convert Dword into bytes */
- tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE;
---- a/drivers/net/wireless/ath/ath11k/wmi.c
-+++ b/drivers/net/wireless/ath/ath11k/wmi.c
-@@ -2281,7 +2281,7 @@ int ath11k_wmi_send_scan_start_cmd(struc
- tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_UINT32) |
- FIELD_PREP(WMI_TLV_LEN, len);
- ptr += TLV_HDR_SIZE;
-- tmp_ptr = (u32 *)ptr;
-+ tmp_ptr = ptr;
-
- for (i = 0; i < params->num_chan; ++i)
- tmp_ptr[i] = params->chan_list[i];
-@@ -4148,7 +4148,7 @@ static int ath11k_init_cmd_send(struct a
- ptr += TLV_HDR_SIZE + len;
-
- if (param->hw_mode_id != WMI_HOST_HW_MODE_MAX) {
-- hw_mode = (struct wmi_pdev_set_hw_mode_cmd_param *)ptr;
-+ hw_mode = ptr;
- hw_mode->tlv_header = FIELD_PREP(WMI_TLV_TAG,
- WMI_TAG_PDEV_SET_HW_MODE_CMD) |
- FIELD_PREP(WMI_TLV_LEN,
-@@ -4168,7 +4168,7 @@ static int ath11k_init_cmd_send(struct a
- len = sizeof(*band_to_mac);
-
- for (idx = 0; idx < param->num_band_to_mac; idx++) {
-- band_to_mac = (void *)ptr;
-+ band_to_mac = ptr;
-
- band_to_mac->tlv_header = FIELD_PREP(WMI_TLV_TAG,
- WMI_TAG_PDEV_BAND_TO_MAC) |
+++ /dev/null
-From 4fd15bb705d3faa7e6adab2daba2e3af80d9b6bd Mon Sep 17 00:00:00 2001
-From: Dmitry Antipov <dmantipov@yandex.ru>
-Date: Tue, 26 Sep 2023 07:29:04 +0300
-Subject: [PATCH] wifi: ath11k: fix ath11k_mac_op_remain_on_channel() stack
- usage
-
-When compiling with clang 16.0.6, I've noticed the following:
-
-drivers/net/wireless/ath/ath11k/mac.c:8903:12: warning: stack frame
-size (1032) exceeds limit (1024) in 'ath11k_mac_op_remain_on_channel'
-[-Wframe-larger-than]
-static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
- ^
-68/1032 (6.59%) spills, 964/1032 (93.41%) variables
-
-So switch to kzalloc()'ed instance of 'struct scan_req_params' like
-it's done in 'ath11k_mac_op_hw_scan()'. Compile tested only.
-
-Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230926042906.13725-1-dmantipov@yandex.ru
----
- drivers/net/wireless/ath/ath11k/mac.c | 44 +++++++++++++++------------
- 1 file changed, 25 insertions(+), 19 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -8908,7 +8908,7 @@ static int ath11k_mac_op_remain_on_chann
- {
- struct ath11k *ar = hw->priv;
- struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
-- struct scan_req_params arg;
-+ struct scan_req_params *arg;
- int ret;
- u32 scan_time_msec;
-
-@@ -8940,27 +8940,31 @@ static int ath11k_mac_op_remain_on_chann
-
- scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
-
-- memset(&arg, 0, sizeof(arg));
-- ath11k_wmi_start_scan_init(ar, &arg);
-- arg.num_chan = 1;
-- arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list),
-- GFP_KERNEL);
-- if (!arg.chan_list) {
-+ arg = kzalloc(sizeof(*arg), GFP_KERNEL);
-+ if (!arg) {
- ret = -ENOMEM;
- goto exit;
- }
-+ ath11k_wmi_start_scan_init(ar, arg);
-+ arg->num_chan = 1;
-+ arg->chan_list = kcalloc(arg->num_chan, sizeof(*arg->chan_list),
-+ GFP_KERNEL);
-+ if (!arg->chan_list) {
-+ ret = -ENOMEM;
-+ goto free_arg;
-+ }
-
-- arg.vdev_id = arvif->vdev_id;
-- arg.scan_id = ATH11K_SCAN_ID;
-- arg.chan_list[0] = chan->center_freq;
-- arg.dwell_time_active = scan_time_msec;
-- arg.dwell_time_passive = scan_time_msec;
-- arg.max_scan_time = scan_time_msec;
-- arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE;
-- arg.scan_flags |= WMI_SCAN_FILTER_PROBE_REQ;
-- arg.burst_duration = duration;
-+ arg->vdev_id = arvif->vdev_id;
-+ arg->scan_id = ATH11K_SCAN_ID;
-+ arg->chan_list[0] = chan->center_freq;
-+ arg->dwell_time_active = scan_time_msec;
-+ arg->dwell_time_passive = scan_time_msec;
-+ arg->max_scan_time = scan_time_msec;
-+ arg->scan_flags |= WMI_SCAN_FLAG_PASSIVE;
-+ arg->scan_flags |= WMI_SCAN_FILTER_PROBE_REQ;
-+ arg->burst_duration = duration;
-
-- ret = ath11k_start_scan(ar, &arg);
-+ ret = ath11k_start_scan(ar, arg);
- if (ret) {
- ath11k_warn(ar->ab, "failed to start roc scan: %d\n", ret);
-
-@@ -8986,7 +8990,9 @@ static int ath11k_mac_op_remain_on_chann
- ret = 0;
-
- free_chan_list:
-- kfree(arg.chan_list);
-+ kfree(arg->chan_list);
-+free_arg:
-+ kfree(arg);
- exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
+++ /dev/null
-From 9e61589ac3c2d23c528d3ffd44604d98553ea1cb Mon Sep 17 00:00:00 2001
-From: Kalle Valo <quic_kvalo@quicinc.com>
-Date: Wed, 27 Sep 2023 17:27:08 +0300
-Subject: [PATCH] wifi: ath11k: mac: fix struct ieee80211_sband_iftype_data
- handling
-
-Commit e8c1841278a7 ("wifi: cfg80211: annotate iftype_data pointer with
-sparse") added sparse checks for struct ieee80211_sband_iftype_data handling
-which immediately found an issue in ath11k:
-
-drivers/net/wireless/ath/ath11k/mac.c:7952:22: warning: incorrect type in argument 1 (different address spaces)
-drivers/net/wireless/ath/ath11k/mac.c:7952:22: expected struct ieee80211_sta_he_cap const *he_cap
-drivers/net/wireless/ath/ath11k/mac.c:7952:22: got struct ieee80211_sta_he_cap const [noderef] __iftype_data *
-
-The problem here is that we are accessing sband->iftype_data directly even
-though we should use for_each_sband_iftype_data() or similar. Fortunately
-there's ieee80211_get_he_iftype_cap_vif() which is just what we need here so
-use it to get HE capabilities.
-
-Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23
-
-Reported-by: Johannes Berg <johannes@sipsolutions.net>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230927142708.2897504-2-kvalo@kernel.org
----
- drivers/net/wireless/ath/ath11k/mac.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -7913,12 +7913,14 @@ ath11k_mac_get_tx_mcs_map(const struct i
-
- static bool
- ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar,
-+ struct ath11k_vif *arvif,
- enum nl80211_band band,
- const struct cfg80211_bitrate_mask *mask,
- int *nss)
- {
- struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
- u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
-+ const struct ieee80211_sta_he_cap *he_cap;
- u16 he_mcs_map = 0;
- u8 ht_nss_mask = 0;
- u8 vht_nss_mask = 0;
-@@ -7949,7 +7951,11 @@ ath11k_mac_bitrate_mask_get_single_nss(s
- return false;
- }
-
-- he_mcs_map = le16_to_cpu(ath11k_mac_get_tx_mcs_map(&sband->iftype_data->he_cap));
-+ he_cap = ieee80211_get_he_iftype_cap_vif(sband, arvif->vif);
-+ if (!he_cap)
-+ return false;
-+
-+ he_mcs_map = le16_to_cpu(ath11k_mac_get_tx_mcs_map(he_cap));
-
- for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) {
- if (mask->control[band].he_mcs[i] == 0)
-@@ -8365,7 +8371,7 @@ ath11k_mac_op_set_bitrate_mask(struct ie
- ieee80211_iterate_stations_atomic(ar->hw,
- ath11k_mac_disable_peer_fixed_rate,
- arvif);
-- } else if (ath11k_mac_bitrate_mask_get_single_nss(ar, band, mask,
-+ } else if (ath11k_mac_bitrate_mask_get_single_nss(ar, arvif, band, mask,
- &single_nss)) {
- rate = WMI_FIXED_RATE_NONE;
- nss = single_nss;
+++ /dev/null
-From 69fcb525905600a151997cd16367bb92c34a2b14 Mon Sep 17 00:00:00 2001
-From: Aditya Kumar Singh <quic_adisi@quicinc.com>
-Date: Tue, 3 Oct 2023 17:26:54 +0300
-Subject: [PATCH] wifi: ath11k: fix CAC running state during virtual interface
- start
-
-Currently channel definition's primary channel's DFS CAC time
-as well as primary channel's state i.e usable are used to set
-the CAC_RUNNING flag for the ath11k radio structure. However,
-this is wrong since certain channel definition are possbile
-where primary channel may not be a DFS channel but, secondary
-channel is a DFS channel. For example - channel 36 with 160 MHz
-bandwidth.
-In such cases, the flag will not be set which is wrong.
-
-Fix this issue by using cfg80211_chandef_dfs_usable() function
-from cfg80211 which return trues if at least one channel is in
-usable state.
-
-While at it, modify the CAC running debug log message to print
-the CAC time as well in milli-seconds.
-
-Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
-
-Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230912051857.2284-3-quic_adisi@quicinc.com
----
- drivers/net/wireless/ath/ath11k/mac.c | 19 +++++++++++--------
- 1 file changed, 11 insertions(+), 8 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -5,6 +5,7 @@
- */
-
- #include <net/mac80211.h>
-+#include <net/cfg80211.h>
- #include <linux/etherdevice.h>
- #include <linux/bitfield.h>
- #include <linux/inetdevice.h>
-@@ -7196,6 +7197,7 @@ ath11k_mac_vdev_start_restart(struct ath
- struct wmi_vdev_start_req_arg arg = {};
- const struct cfg80211_chan_def *chandef = &ctx->def;
- int ret = 0;
-+ unsigned int dfs_cac_time;
-
- lockdep_assert_held(&ar->conf_mutex);
-
-@@ -7275,20 +7277,21 @@ ath11k_mac_vdev_start_restart(struct ath
- ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM started, vdev_id %d\n",
- arvif->vif->addr, arvif->vdev_id);
-
-- /* Enable CAC Flag in the driver by checking the channel DFS cac time,
-- * i.e dfs_cac_ms value which will be valid only for radar channels
-- * and state as NL80211_DFS_USABLE which indicates CAC needs to be
-+ /* Enable CAC Flag in the driver by checking the all sub-channel's DFS
-+ * state as NL80211_DFS_USABLE which indicates CAC needs to be
- * done before channel usage. This flags is used to drop rx packets.
- * during CAC.
- */
- /* TODO Set the flag for other interface types as required */
-- if (arvif->vdev_type == WMI_VDEV_TYPE_AP &&
-- chandef->chan->dfs_cac_ms &&
-- chandef->chan->dfs_state == NL80211_DFS_USABLE) {
-+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP && ctx->radar_enabled &&
-+ cfg80211_chandef_dfs_usable(ar->hw->wiphy, chandef)) {
- set_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
-+ dfs_cac_time = cfg80211_chandef_dfs_cac_time(ar->hw->wiphy,
-+ chandef);
- ath11k_dbg(ab, ATH11K_DBG_MAC,
-- "CAC Started in chan_freq %d for vdev %d\n",
-- arg.channel.freq, arg.vdev_id);
-+ "cac started dfs_cac_time %u center_freq %d center_freq1 %d for vdev %d\n",
-+ dfs_cac_time, arg.channel.freq, chandef->center_freq1,
-+ arg.vdev_id);
- }
-
- ret = ath11k_mac_set_txbf_conf(arvif);
+++ /dev/null
-From 77f1ee6fd8b6e470f721d05a2e269039d5cafcb7 Mon Sep 17 00:00:00 2001
-From: Aditya Kumar Singh <quic_adisi@quicinc.com>
-Date: Tue, 3 Oct 2023 17:26:54 +0300
-Subject: [PATCH] wifi: ath11k: fix Tx power value during active CAC
-
-Tx power is fetched from firmware's pdev stats. However, during active
-CAC, firmware does not fill the current Tx power and sends the max
-initialised value filled during firmware init. If host sends this power
-to user space, this is wrong since in certain situations, the Tx power
-could be greater than the max allowed by the regulatory. Hence, host
-should not be fetching the Tx power during an active CAC.
-
-Fix this issue by returning -EAGAIN error so that user space knows that there's
-no valid value available.
-
-Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
-
-Fixes: 9a2aa68afe3d ("wifi: ath11k: add get_txpower mac ops")
-Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20230912051857.2284-4-quic_adisi@quicinc.com
----
- drivers/net/wireless/ath/ath11k/mac.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -9068,6 +9068,14 @@ static int ath11k_mac_op_get_txpower(str
- return -EAGAIN;
- }
-
-+ /* Firmware doesn't provide Tx power during CAC hence no need to fetch
-+ * the stats.
-+ */
-+ if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
-+ mutex_unlock(&ar->conf_mutex);
-+ return -EAGAIN;
-+ }
-+
- req_param.pdev_id = ar->pdev->pdev_id;
- req_param.stats_id = WMI_REQUEST_PDEV_STAT;
-
+++ /dev/null
-From e149353e6562f3e3246f75dfc4cca6a0cc5b4efc Mon Sep 17 00:00:00 2001
-From: Aloka Dixit <quic_alokad@quicinc.com>
-Date: Mon, 9 Oct 2023 10:13:54 +0300
-Subject: [PATCH] wifi: ath11k: call ath11k_mac_fils_discovery() without
- condition
-
-Mac80211 does not set flags BSS_CHANGED_FILS_DISCOVERY and
-BSS_CHANGED_UNSOL_BCAST_PROBE_RESP if there are no updates to
-FILS discovery and unsolicited broadcast probe response transmission
-configurations respectively. This results in the transmissions getting
-stopped during BSS change operations which do not include these
-attributes. Remove the checks for the flags and always send the existing
-configuration to firmware.
-
-Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
-
-Signed-off-by: Aloka Dixit <quic_alokad@quicinc.com>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20231004044915.6817-1-quic_alokad@quicinc.com
----
- drivers/net/wireless/ath/ath11k/mac.c | 4 +---
- 1 file changed, 1 insertion(+), 3 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -3732,9 +3732,7 @@ static void ath11k_mac_op_bss_info_chang
- arvif->vdev_id, ret);
- }
-
-- if (changed & BSS_CHANGED_FILS_DISCOVERY ||
-- changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP)
-- ath11k_mac_fils_discovery(arvif, info);
-+ ath11k_mac_fils_discovery(arvif, info);
-
- if (changed & BSS_CHANGED_ARP_FILTER) {
- ipv4_cnt = min(vif->cfg.arp_addr_cnt, ATH11K_IPV4_MAX_COUNT);
+++ /dev/null
-From a47111663491ff2829df0626493ce81b48dd880a Mon Sep 17 00:00:00 2001
-From: Kalle Valo <quic_kvalo@quicinc.com>
-Date: Tue, 10 Oct 2023 09:22:50 +0300
-Subject: [PATCH] wifi: ath11k: ath11k_debugfs_register(): fix
- format-truncation warning
-
-In v6.6-rc4 with GCC 13.2 I see a new warning:
-
-drivers/net/wireless/ath/ath11k/debugfs.c: In function 'ath11k_debugfs_register':
-drivers/net/wireless/ath/ath11k/debugfs.c:1597:51: error: '%d' directive output may be truncated writing between 1 and 3 bytes into a region of size 2 [-Werror=format-truncation=]
-drivers/net/wireless/ath/ath11k/debugfs.c:1597:48: note: directive argument in the range [0, 255]
-drivers/net/wireless/ath/ath11k/debugfs.c:1597:9: note: 'snprintf' output between 5 and 7 bytes into a destination of size 5
-
-Increase the size of pdev_name to 10 bytes to make sure there's enough room for
-the string. Also change the format to '%u' as ar->pdev_idx is u8.
-
-Compile tested only.
-
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20231010062250.2580951-1-kvalo@kernel.org
----
- drivers/net/wireless/ath/ath11k/debugfs.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/debugfs.c
-+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
-@@ -1591,10 +1591,10 @@ static const struct file_operations fops
- int ath11k_debugfs_register(struct ath11k *ar)
- {
- struct ath11k_base *ab = ar->ab;
-- char pdev_name[5];
-+ char pdev_name[10];
- char buf[100] = {0};
-
-- snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
-+ snprintf(pdev_name, sizeof(pdev_name), "%s%u", "mac", ar->pdev_idx);
-
- ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
- if (IS_ERR(ar->debug.debugfs_pdev))
+++ /dev/null
-From 534c2dd8099a9cc4bad8ea8b3c7fa1f730e10d5d Mon Sep 17 00:00:00 2001
-From: Aditya Kumar Singh <quic_adisi@quicinc.com>
-Date: Tue, 10 Oct 2023 10:27:19 +0300
-Subject: [PATCH] wifi: ath11k: add parsing of phy bitmap for reg rules
-
-Certain regulatory domains could put restrictions on phy mode operation.
-For example, in a few countries HE Operation is not allowed. For such
-countries, firmware indicates this via phy bitmap in each reg rule.
-
-Currently, there is no logic to parse this info and then pass it on to the
-cfg80211/regulatory.
-
-Add parsing of this phy bitmap from the regulatory channel change event and
-then accordingly map it to cfg80211/regulatory flags and pass it on to it.
-
-While at it, correct typo in debug print s/dsf/dfs.
-
-Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
-
-Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
-Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20231004092655.25020-1-quic_adisi@quicinc.com
----
- drivers/net/wireless/ath/ath11k/reg.c | 11 +++++++++++
- drivers/net/wireless/ath/ath11k/reg.h | 3 +++
- drivers/net/wireless/ath/ath11k/wmi.c | 5 +++--
- 3 files changed, 17 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/reg.c
-+++ b/drivers/net/wireless/ath/ath11k/reg.c
-@@ -352,6 +352,16 @@ static u32 ath11k_map_fw_reg_flags(u16 r
- return flags;
- }
-
-+static u32 ath11k_map_fw_phy_flags(u32 phy_flags)
-+{
-+ u32 flags = 0;
-+
-+ if (phy_flags & ATH11K_REG_PHY_BITMAP_NO11AX)
-+ flags |= NL80211_RRF_NO_HE;
-+
-+ return flags;
-+}
-+
- static bool
- ath11k_reg_can_intersect(struct ieee80211_reg_rule *rule1,
- struct ieee80211_reg_rule *rule2)
-@@ -685,6 +695,7 @@ ath11k_reg_build_regd(struct ath11k_base
- }
-
- flags |= ath11k_map_fw_reg_flags(reg_rule->flags);
-+ flags |= ath11k_map_fw_phy_flags(reg_info->phybitmap);
-
- ath11k_reg_update_rule(tmp_regd->reg_rules + i,
- reg_rule->start_freq,
---- a/drivers/net/wireless/ath/ath11k/reg.h
-+++ b/drivers/net/wireless/ath/ath11k/reg.h
-@@ -24,6 +24,9 @@ enum ath11k_dfs_region {
- ATH11K_DFS_REG_UNDEF,
- };
-
-+/* Phy bitmaps */
-+#define ATH11K_REG_PHY_BITMAP_NO11AX BIT(5)
-+
- /* ATH11K Regulatory API's */
- void ath11k_reg_init(struct ath11k *ar);
- void ath11k_reg_free(struct ath11k_base *ab);
---- a/drivers/net/wireless/ath/ath11k/wmi.c
-+++ b/drivers/net/wireless/ath/ath11k/wmi.c
-@@ -5440,10 +5440,11 @@ static int ath11k_pull_reg_chan_list_ext
- }
-
- ath11k_dbg(ab, ATH11K_DBG_WMI,
-- "cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
-+ "cc_ext %s dfs %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d phy_bitmap 0x%x",
- reg_info->alpha2, reg_info->dfs_region,
- reg_info->min_bw_2ghz, reg_info->max_bw_2ghz,
-- reg_info->min_bw_5ghz, reg_info->max_bw_5ghz);
-+ reg_info->min_bw_5ghz, reg_info->max_bw_5ghz,
-+ reg_info->phybitmap);
-
- ath11k_dbg(ab, ATH11K_DBG_WMI,
- "num_2ghz_reg_rules %d num_5ghz_reg_rules %d",
+++ /dev/null
-From 480d230bef0ecd06e72ae3a84117142e38e77503 Mon Sep 17 00:00:00 2001
-From: Jeff Johnson <quic_jjohnson@quicinc.com>
-Date: Mon, 9 Oct 2023 09:36:54 -0700
-Subject: [PATCH] wifi: ath11k: Remove unused struct ath11k_htc_frame
-
-struct ath11k_htc_frame is unused, and since it illogically contains
-two consecutive flexible arrays, it could never be used, so remove it.
-
-No functional changes, compile tested only.
-
-Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20231009-ath11k_htc_frame-v1-1-81d405b7a195@quicinc.com
----
- drivers/net/wireless/ath/ath11k/htc.h | 12 ------------
- 1 file changed, 12 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/htc.h
-+++ b/drivers/net/wireless/ath/ath11k/htc.h
-@@ -156,18 +156,6 @@ struct ath11k_htc_record {
- };
- } __packed __aligned(4);
-
--/* note: the trailer offset is dynamic depending
-- * on payload length. this is only a struct layout draft
-- */
--struct ath11k_htc_frame {
-- struct ath11k_htc_hdr hdr;
-- union {
-- struct ath11k_htc_msg msg;
-- u8 payload[0];
-- };
-- struct ath11k_htc_record trailer[0];
--} __packed __aligned(4);
--
- enum ath11k_htc_svc_gid {
- ATH11K_HTC_SVC_GRP_RSVD = 0,
- ATH11K_HTC_SVC_GRP_WMI = 1,
+++ /dev/null
-From 10c65f97b424fcee439463f933140df2a0022f98 Mon Sep 17 00:00:00 2001
-From: Jeff Johnson <quic_jjohnson@quicinc.com>
-Date: Mon, 9 Oct 2023 09:39:42 -0700
-Subject: [PATCH] wifi: ath11k: Introduce and use ath11k_sta_to_arsta()
-
-Currently, the logic to return an ath11k_sta pointer, given a
-ieee80211_sta pointer, uses typecasting throughout the driver. In
-general, conversion functions are preferable to typecasting since
-using a conversion function allows the compiler to validate the types
-of both the input and output parameters.
-
-ath11k already defines a conversion function ath11k_vif_to_arvif() for
-a similar conversion. So introduce ath11k_sta_to_arsta() for this use
-case, and convert all of the existing typecasting to use this
-function.
-
-No functional changes, compile tested only.
-
-Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
-Link: https://lore.kernel.org/r/20231009-ath11k_sta_to_arsta-v1-1-1563e3a307e8@quicinc.com
----
- drivers/net/wireless/ath/ath11k/core.h | 5 ++++
- drivers/net/wireless/ath/ath11k/debugfs.c | 4 +--
- drivers/net/wireless/ath/ath11k/debugfs_sta.c | 30 +++++++++----------
- drivers/net/wireless/ath/ath11k/dp_rx.c | 8 ++---
- drivers/net/wireless/ath/ath11k/dp_tx.c | 4 +--
- drivers/net/wireless/ath/ath11k/mac.c | 18 +++++------
- drivers/net/wireless/ath/ath11k/peer.c | 2 +-
- drivers/net/wireless/ath/ath11k/wmi.c | 6 ++--
- 8 files changed, 41 insertions(+), 36 deletions(-)
-
---- a/drivers/net/wireless/ath/ath11k/core.h
-+++ b/drivers/net/wireless/ath/ath11k/core.h
-@@ -1223,6 +1223,11 @@ static inline struct ath11k_vif *ath11k_
- return (struct ath11k_vif *)vif->drv_priv;
- }
-
-+static inline struct ath11k_sta *ath11k_sta_to_arsta(struct ieee80211_sta *sta)
-+{
-+ return (struct ath11k_sta *)sta->drv_priv;
-+}
-+
- static inline struct ath11k *ath11k_ab_to_ar(struct ath11k_base *ab,
- int mac_id)
- {
---- a/drivers/net/wireless/ath/ath11k/debugfs.c
-+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
-@@ -1459,7 +1459,7 @@ static void ath11k_reset_peer_ps_duratio
- struct ieee80211_sta *sta)
- {
- struct ath11k *ar = data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
-
- spin_lock_bh(&ar->data_lock);
- arsta->ps_total_duration = 0;
-@@ -1510,7 +1510,7 @@ static void ath11k_peer_ps_state_disable
- struct ieee80211_sta *sta)
- {
- struct ath11k *ar = data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
-
- spin_lock_bh(&ar->data_lock);
- arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
---- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c
-+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
-@@ -136,7 +136,7 @@ static ssize_t ath11k_dbg_sta_dump_tx_st
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- struct ath11k_htt_data_stats *stats;
- static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
-@@ -243,7 +243,7 @@ static ssize_t ath11k_dbg_sta_dump_rx_st
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
- int len = 0, i, retval = 0;
-@@ -340,7 +340,7 @@ static int
- ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
- {
- struct ieee80211_sta *sta = inode->i_private;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- struct debug_htt_stats_req *stats_req;
- int type = ar->debug.htt_stats.type;
-@@ -376,7 +376,7 @@ static int
- ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
- {
- struct ieee80211_sta *sta = inode->i_private;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
-
- mutex_lock(&ar->conf_mutex);
-@@ -413,7 +413,7 @@ static ssize_t ath11k_dbg_sta_write_peer
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- int ret, enable;
-
-@@ -453,7 +453,7 @@ static ssize_t ath11k_dbg_sta_read_peer_
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- char buf[32] = {0};
- int len;
-@@ -480,7 +480,7 @@ static ssize_t ath11k_dbg_sta_write_delb
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- u32 tid, initiator, reason;
- int ret;
-@@ -531,7 +531,7 @@ static ssize_t ath11k_dbg_sta_write_addb
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- u32 tid, status;
- int ret;
-@@ -581,7 +581,7 @@ static ssize_t ath11k_dbg_sta_write_addb
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- u32 tid, buf_size;
- int ret;
-@@ -632,7 +632,7 @@ static ssize_t ath11k_dbg_sta_read_aggr_
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- char buf[64];
- int len = 0;
-@@ -652,7 +652,7 @@ static ssize_t ath11k_dbg_sta_write_aggr
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- u32 aggr_mode;
- int ret;
-@@ -697,7 +697,7 @@ ath11k_write_htt_peer_stats_reset(struct
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- struct htt_ext_stats_cfg_params cfg_params = { 0 };
- int ret;
-@@ -756,7 +756,7 @@ static ssize_t ath11k_dbg_sta_read_peer_
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- char buf[20];
- int len;
-@@ -783,7 +783,7 @@ static ssize_t ath11k_dbg_sta_read_curre
- loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- u64 time_since_station_in_power_save;
- char buf[20];
-@@ -817,7 +817,7 @@ static ssize_t ath11k_dbg_sta_read_total
- size_t count, loff_t *ppos)
- {
- struct ieee80211_sta *sta = file->private_data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- char buf[20];
- u64 power_save_duration;
---- a/drivers/net/wireless/ath/ath11k/dp_rx.c
-+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
-@@ -1099,7 +1099,7 @@ int ath11k_dp_rx_ampdu_start(struct ath1
- struct ieee80211_ampdu_params *params)
- {
- struct ath11k_base *ab = ar->ab;
-- struct ath11k_sta *arsta = (void *)params->sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
- int vdev_id = arsta->arvif->vdev_id;
- int ret;
-
-@@ -1117,7 +1117,7 @@ int ath11k_dp_rx_ampdu_stop(struct ath11
- {
- struct ath11k_base *ab = ar->ab;
- struct ath11k_peer *peer;
-- struct ath11k_sta *arsta = (void *)params->sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta);
- int vdev_id = arsta->arvif->vdev_id;
- dma_addr_t paddr;
- bool active;
-@@ -1456,7 +1456,7 @@ ath11k_update_per_peer_tx_stats(struct a
- }
-
- sta = peer->sta;
-- arsta = (struct ath11k_sta *)sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(sta);
-
- memset(&arsta->txrate, 0, sizeof(arsta->txrate));
-
-@@ -5248,7 +5248,7 @@ int ath11k_dp_rx_process_mon_status(stru
- goto next_skb;
- }
-
-- arsta = (struct ath11k_sta *)peer->sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(peer->sta);
- ath11k_dp_rx_update_peer_stats(arsta, ppdu_info);
-
- if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr))
---- a/drivers/net/wireless/ath/ath11k/dp_tx.c
-+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
-@@ -467,7 +467,7 @@ void ath11k_dp_tx_update_txcompl(struct
- }
-
- sta = peer->sta;
-- arsta = (struct ath11k_sta *)sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(sta);
-
- memset(&arsta->txrate, 0, sizeof(arsta->txrate));
- pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,
-@@ -627,7 +627,7 @@ static void ath11k_dp_tx_complete_msdu(s
- ieee80211_free_txskb(ar->hw, msdu);
- return;
- }
-- arsta = (struct ath11k_sta *)peer->sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(peer->sta);
- status.sta = peer->sta;
- status.skb = msdu;
- status.info = info;
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -2832,7 +2832,7 @@ static void ath11k_peer_assoc_prepare(st
-
- lockdep_assert_held(&ar->conf_mutex);
-
-- arsta = (struct ath11k_sta *)sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(sta);
-
- memset(arg, 0, sizeof(*arg));
-
-@@ -4313,7 +4313,7 @@ static int ath11k_mac_op_set_key(struct
- ath11k_warn(ab, "peer %pM disappeared!\n", peer_addr);
-
- if (sta) {
-- arsta = (struct ath11k_sta *)sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(sta);
-
- switch (key->cipher) {
- case WLAN_CIPHER_SUITE_TKIP:
-@@ -4904,7 +4904,7 @@ static int ath11k_mac_station_add(struct
- {
- struct ath11k_base *ab = ar->ab;
- struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct peer_create_params peer_param;
- int ret;
-
-@@ -5028,7 +5028,7 @@ static int ath11k_mac_op_sta_state(struc
- {
- struct ath11k *ar = hw->priv;
- struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k_peer *peer;
- int ret = 0;
-
-@@ -5194,7 +5194,7 @@ static void ath11k_mac_op_sta_set_4addr(
- struct ieee80211_sta *sta, bool enabled)
- {
- struct ath11k *ar = hw->priv;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
-
- if (enabled && !arsta->use_4addr_set) {
- ieee80211_queue_work(ar->hw, &arsta->set_4addr_wk);
-@@ -5208,7 +5208,7 @@ static void ath11k_mac_op_sta_rc_update(
- u32 changed)
- {
- struct ath11k *ar = hw->priv;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
- struct ath11k_peer *peer;
- u32 bw, smps;
-@@ -6201,7 +6201,7 @@ static void ath11k_mac_op_tx(struct ieee
- }
-
- if (control->sta)
-- arsta = (struct ath11k_sta *)control->sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(control->sta);
-
- ret = ath11k_dp_tx(ar, arvif, arsta, skb);
- if (unlikely(ret)) {
-@@ -8233,7 +8233,7 @@ static void ath11k_mac_set_bitrate_mask_
- struct ieee80211_sta *sta)
- {
- struct ath11k_vif *arvif = data;
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arvif->ar;
-
- spin_lock_bh(&ar->data_lock);
-@@ -8637,7 +8637,7 @@ static void ath11k_mac_op_sta_statistics
- struct ieee80211_sta *sta,
- struct station_info *sinfo)
- {
-- struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
-+ struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
- struct ath11k *ar = arsta->arvif->ar;
- s8 signal;
- bool db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT,
---- a/drivers/net/wireless/ath/ath11k/peer.c
-+++ b/drivers/net/wireless/ath/ath11k/peer.c
-@@ -446,7 +446,7 @@ int ath11k_peer_create(struct ath11k *ar
- peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
-
- if (sta) {
-- arsta = (struct ath11k_sta *)sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(sta);
- arsta->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 0) |
- FIELD_PREP(HTT_TCL_META_DATA_PEER_ID,
- peer->peer_id);
---- a/drivers/net/wireless/ath/ath11k/wmi.c
-+++ b/drivers/net/wireless/ath/ath11k/wmi.c
-@@ -6453,7 +6453,7 @@ static int ath11k_wmi_tlv_rssi_chain_par
- goto exit;
- }
-
-- arsta = (struct ath11k_sta *)sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(sta);
-
- BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) >
- ARRAY_SIZE(stats_rssi->rssi_avg_beacon));
-@@ -6541,7 +6541,7 @@ static int ath11k_wmi_tlv_fw_stats_data_
- arvif->bssid,
- NULL);
- if (sta) {
-- arsta = (struct ath11k_sta *)sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(sta);
- arsta->rssi_beacon = src->beacon_snr;
- ath11k_dbg(ab, ATH11K_DBG_WMI,
- "stats vdev id %d snr %d\n",
-@@ -7468,7 +7468,7 @@ static void ath11k_wmi_event_peer_sta_ps
- goto exit;
- }
-
-- arsta = (struct ath11k_sta *)sta->drv_priv;
-+ arsta = ath11k_sta_to_arsta(sta);
-
- spin_lock_bh(&ar->data_lock);
-
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
-@@ -168,8 +168,8 @@ static const struct ath11k_hw_params ath
+@@ -170,8 +170,8 @@ static const struct ath11k_hw_params ath
.supports_shadow_regs = false,
.idle_ps = false,
.supports_sta_ps = false,
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
-@@ -294,6 +294,34 @@ static void ath11k_mhi_op_runtime_put(st
+@@ -239,6 +239,34 @@ static void ath11k_mhi_op_runtime_put(st
{
}
static char *ath11k_mhi_op_callback_to_str(enum mhi_callback reason)
{
switch (reason) {
-@@ -315,6 +343,8 @@ static char *ath11k_mhi_op_callback_to_s
+@@ -260,6 +288,8 @@ static char *ath11k_mhi_op_callback_to_s
return "MHI_CB_FATAL_ERROR";
case MHI_CB_BW_REQ:
return "MHI_CB_BW_REQ";
default:
return "UNKNOWN";
}
-@@ -337,27 +367,14 @@ static void ath11k_mhi_op_status_cb(stru
+@@ -282,27 +312,14 @@ static void ath11k_mhi_op_status_cb(stru
if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)))
queue_work(ab->workqueue_aux, &ab->reset_work);
break;
struct device_node *np;
--- a/drivers/net/wireless/ath/ath11k/mhi.h
+++ b/drivers/net/wireless/ath/ath11k/mhi.h
-@@ -16,6 +16,9 @@
+@@ -17,6 +17,9 @@
#define MHICTRL 0x38
#define MHICTRL_RESET_MASK 0x2
int ath11k_mhi_register(struct ath11k_pci *ar_pci);
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
-@@ -371,13 +371,20 @@ static void ath11k_pci_sw_reset(struct a
+@@ -374,13 +374,20 @@ static void ath11k_pci_sw_reset(struct a
static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
{
struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -9455,6 +9455,7 @@ static int __ath11k_mac_register(struct
+@@ -10034,6 +10034,7 @@ static int __ath11k_mac_register(struct
if (ret)
goto err;
+ Enable ath11k thermal sensors and throttling support.
--- a/drivers/net/wireless/ath/ath11k/Makefile
+++ b/drivers/net/wireless/ath/ath11k/Makefile
-@@ -22,7 +22,7 @@ ath11k-y += core.o \
+@@ -23,7 +23,7 @@ ath11k-y += core.o \
ath11k-$(CPTCFG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
ath11k-$(CPTCFG_NL80211_TESTMODE) += testmode.o
ath11k-$(CPTCFG_ATH11K_TRACING) += trace.o
--- a/drivers/net/wireless/ath/ath11k/thermal.h
+++ b/drivers/net/wireless/ath/ath11k/thermal.h
-@@ -25,7 +25,7 @@ struct ath11k_thermal {
+@@ -26,7 +26,7 @@ struct ath11k_thermal {
int temperature;
};
-#if IS_REACHABLE(CONFIG_THERMAL)
+#if IS_REACHABLE(CPTCFG_ATH11K_THERMAL)
- int ath11k_thermal_register(struct ath11k_base *sc);
- void ath11k_thermal_unregister(struct ath11k_base *sc);
+ int ath11k_thermal_register(struct ath11k_base *ab);
+ void ath11k_thermal_unregister(struct ath11k_base *ab);
int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state);
--- a/local-symbols
+++ b/local-symbols
-@@ -173,6 +173,7 @@ ATH11K_DEBUG=
+@@ -166,6 +166,7 @@ ATH11K_DEBUG=
ATH11K_DEBUGFS=
ATH11K_TRACING=
ATH11K_SPECTRAL=
+++ /dev/null
-From 04178918e7f6b5f34dde81ec79ee8a1ccace3be3 Mon Sep 17 00:00:00 2001
-From: Robert Marko <robimarko@gmail.com>
-Date: Mon, 17 Oct 2022 11:45:03 +0200
-Subject: [PATCH] wifi: ath11k: pci: fix compilation in 5.16 and older
-
-Commit ("genirq/msi, treewide: Use a named struct for PCI/MSI attributes")
-changed the msi_desc structure a bit, however that is only available in
-kernels 5.17 and newer, so check for kernel version to allow compilation
-in 5.16 and older.
-
-Signed-off-by: Robert Marko <robimarko@gmail.com>
----
- drivers/net/wireless/ath/ath11k/pci.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/wireless/ath/ath11k/pci.c
-+++ b/drivers/net/wireless/ath/ath11k/pci.c
-@@ -459,7 +459,11 @@ static int ath11k_pci_alloc_msi(struct a
- pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
- &ab->pci.msi.addr_lo);
-
-+#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 17, 0))
- if (msi_desc->pci.msi_attrib.is_64) {
-+#else
-+ if (msi_desc->msi_attrib.is_64) {
-+#endif
- pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
- &ab->pci.msi.addr_hi);
- } else {
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
-@@ -36,7 +36,7 @@ bool ath11k_ftm_mode;
+@@ -37,7 +37,7 @@ bool ath11k_ftm_mode;
module_param_named(ftm_mode, ath11k_ftm_mode, bool, 0444);
MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
{
.hw_rev = ATH11K_HW_IPQ8074,
.name = "ipq8074 hw2.0",
-@@ -2040,7 +2040,8 @@ static void ath11k_core_reset(struct wor
+@@ -2138,7 +2138,8 @@ static void ath11k_core_reset(struct wor
static int ath11k_init_hw_params(struct ath11k_base *ab)
{
const struct ath11k_hw_params *hw_params = NULL;
for (i = 0; i < ARRAY_SIZE(ath11k_hw_params); i++) {
hw_params = &ath11k_hw_params[i];
-@@ -2056,7 +2057,31 @@ static int ath11k_init_hw_params(struct
+@@ -2154,7 +2155,31 @@ static int ath11k_init_hw_params(struct
ab->hw_params = *hw_params;
--- a/drivers/net/wireless/ath/ath11k/reg.c
+++ b/drivers/net/wireless/ath/ath11k/reg.c
-@@ -362,129 +362,6 @@ static u32 ath11k_map_fw_phy_flags(u32 p
+@@ -363,134 +363,6 @@ static u32 ath11k_map_fw_phy_flags(u32 p
return flags;
}
- /* Use the flags of both the rules */
- new_rule->flags = rule1->flags | rule2->flags;
-
+- if ((rule1->flags & NL80211_RRF_PSD) && (rule2->flags & NL80211_RRF_PSD))
+- new_rule->psd = min_t(s8, rule1->psd, rule2->psd);
+- else
+- new_rule->flags &= ~NL80211_RRF_PSD;
+-
- /* To be safe, lts use the max cac timeout of both rules */
- new_rule->dfs_cac_ms = max_t(u32, rule1->dfs_cac_ms,
- rule2->dfs_cac_ms);
static const char *
ath11k_reg_get_regdom_str(enum nl80211_dfs_regions dfs_region)
{
-@@ -619,9 +496,9 @@ ath11k_reg_update_weather_radar_band(str
+@@ -641,11 +513,11 @@ ath11k_reg_ap_pwr_convert(enum ieee80211
struct ieee80211_regdomain *
ath11k_reg_build_regd(struct ath11k_base *ab,
-- struct cur_regulatory_info *reg_info, bool intersect)
-+ struct cur_regulatory_info *reg_info)
+- struct cur_regulatory_info *reg_info, bool intersect,
++ struct cur_regulatory_info *reg_info,
+ enum wmi_vdev_type vdev_type,
+ enum ieee80211_ap_reg_power power_type)
{
- struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
+ struct ieee80211_regdomain *new_regd = NULL;
- struct cur_reg_rule *reg_rule;
+ struct cur_reg_rule *reg_rule, *reg_rule_6ghz;
u8 i = 0, j = 0, k = 0;
u8 num_rules;
-@@ -638,26 +515,26 @@ ath11k_reg_build_regd(struct ath11k_base
- num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP];
+@@ -688,26 +560,26 @@ ath11k_reg_build_regd(struct ath11k_base
+ }
if (!num_rules)
- goto ret;
reg_info->dfs_region, num_rules);
/* Update reg_rules[] below. Firmware is expected to
* send these rules in order(2 GHz rules first and then 5 GHz)
-@@ -697,7 +574,7 @@ ath11k_reg_build_regd(struct ath11k_base
+@@ -746,7 +618,7 @@ ath11k_reg_build_regd(struct ath11k_base
flags |= ath11k_map_fw_reg_flags(reg_rule->flags);
flags |= ath11k_map_fw_phy_flags(reg_info->phybitmap);
reg_rule->start_freq,
reg_rule->end_freq, max_bw,
reg_rule->ant_gain, reg_rule->reg_power,
-@@ -712,7 +589,7 @@ ath11k_reg_build_regd(struct ath11k_base
+@@ -761,7 +633,7 @@ ath11k_reg_build_regd(struct ath11k_base
reg_info->dfs_region == ATH11K_DFS_REG_ETSI &&
(reg_rule->end_freq > ETSI_WEATHER_RADAR_BAND_LOW &&
reg_rule->start_freq < ETSI_WEATHER_RADAR_BAND_HIGH)){
reg_rule, &i,
flags, max_bw);
continue;
-@@ -723,37 +600,20 @@ ath11k_reg_build_regd(struct ath11k_base
+@@ -772,51 +644,23 @@ ath11k_reg_build_regd(struct ath11k_base
"\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d) (%d, %d)\n",
i + 1, reg_rule->start_freq, reg_rule->end_freq,
max_bw, reg_rule->ant_gain, reg_rule->reg_power,
}
- tmp_regd->n_reg_rules = i;
--
++ new_regd->n_reg_rules = i;
+
- if (intersect) {
- default_regd = ab->default_regd[reg_info->phy_id];
-
- } else {
- new_regd = tmp_regd;
- }
-+ new_regd->n_reg_rules = i;
-
+-
-ret:
return new_regd;
}
---- a/drivers/net/wireless/ath/ath11k/reg.h
-+++ b/drivers/net/wireless/ath/ath11k/reg.h
-@@ -33,7 +33,7 @@ void ath11k_reg_free(struct ath11k_base
- void ath11k_regd_update_work(struct work_struct *work);
- struct ieee80211_regdomain *
- ath11k_reg_build_regd(struct ath11k_base *ab,
-- struct cur_regulatory_info *reg_info, bool intersect);
-+ struct cur_regulatory_info *reg_info);
- int ath11k_regd_update(struct ath11k *ar);
- int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait);
- #endif
---- a/drivers/net/wireless/ath/ath11k/wmi.c
-+++ b/drivers/net/wireless/ath/ath11k/wmi.c
-@@ -7060,24 +7060,12 @@ static void ath11k_wmi_htc_tx_complete(s
- wake_up(&wmi->tx_ce_desc_wq);
- }
-
-static bool ath11k_reg_is_world_alpha(char *alpha)
-{
- if (alpha[0] == '0' && alpha[1] == '0')
- return false;
-}
-
- static int ath11k_reg_chan_list_event(struct ath11k_base *ab,
- struct sk_buff *skb,
- enum wmi_reg_chan_list_cmd_type id)
+ static enum wmi_vdev_type ath11k_reg_get_ar_vdev_type(struct ath11k *ar)
+ {
+ struct ath11k_vif *arvif;
+@@ -839,7 +683,6 @@ int ath11k_reg_handle_chan_list(struct a
+ enum ieee80211_ap_reg_power power_type)
{
- struct cur_regulatory_info *reg_info = NULL;
- struct ieee80211_regdomain *regd = NULL;
+ struct ieee80211_regdomain *regd;
- bool intersect = false;
- int ret = 0, pdev_idx, i, j;
+ int pdev_idx;
struct ath11k *ar;
-
-@@ -7141,17 +7129,7 @@ static int ath11k_reg_chan_list_event(st
+ enum wmi_vdev_type vdev_type;
+@@ -891,24 +734,14 @@ int ath11k_reg_handle_chan_list(struct a
(char *)reg_info->alpha2, 2))
- goto mem_free;
+ goto retfail;
- /* Intersect new rules with default regd if a new country setting was
- * requested, i.e a default regd was already set during initialization
- !ath11k_reg_is_world_alpha((char *)reg_info->alpha2))
- intersect = true;
-
-- regd = ath11k_reg_build_regd(ab, reg_info, intersect);
-+ regd = ath11k_reg_build_regd(ab, reg_info);
+ ar = ab->pdevs[pdev_idx].ar;
+ vdev_type = ath11k_reg_get_ar_vdev_type(ar);
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
+- "wmi handle chan list power type %d vdev type %d intersect %d\n",
+- power_type, vdev_type, intersect);
++ "wmi handle chan list power type %d vdev type %d\n",
++ power_type, vdev_type);
+
+- regd = ath11k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type);
++ regd = ath11k_reg_build_regd(ab, reg_info, vdev_type, power_type);
if (!regd) {
ath11k_warn(ab, "failed to build regd from reg_info\n");
goto fallback;
+--- a/drivers/net/wireless/ath/ath11k/reg.h
++++ b/drivers/net/wireless/ath/ath11k/reg.h
+@@ -35,7 +35,7 @@ void ath11k_reg_free(struct ath11k_base
+ void ath11k_regd_update_work(struct work_struct *work);
+ struct ieee80211_regdomain *
+ ath11k_reg_build_regd(struct ath11k_base *ab,
+- struct cur_regulatory_info *reg_info, bool intersect,
++ struct cur_regulatory_info *reg_info,
+ enum wmi_vdev_type vdev_type,
+ enum ieee80211_ap_reg_power power_type);
+ int ath11k_regd_update(struct ath11k *ar);
sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
-@@ -153,6 +153,7 @@ struct ath_common {
+@@ -151,6 +151,7 @@ struct ath_common {
int debug_mask;
enum ath_device_state state;
unsigned long op_flags;
---- a/include/linux/ath9k_platform.h
-+++ b/include/linux/ath9k_platform.h
-@@ -46,6 +46,9 @@ struct ath9k_platform_data {
- int (*external_reset)(void);
-
- bool use_eeprom;
-+
-+ int num_leds;
-+ const struct gpio_led *leds;
- };
-
- #endif /* _LINUX_ATH9K_PLATFORM_H */
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -15,6 +15,7 @@
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -538,6 +538,11 @@ irqreturn_t ath_isr(int irq, void *dev)
+@@ -537,6 +537,11 @@ irqreturn_t ath_isr(int irq, void *dev)
return IRQ_HANDLED;
}
void (*spectral_scan_trigger)(struct ath_hw *ah);
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -1918,6 +1918,26 @@ void ar9003_hw_init_rate_txpower(struct
+@@ -1915,6 +1915,26 @@ void ar9003_hw_init_rate_txpower(struct
}
}
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
-@@ -1954,6 +1974,7 @@ void ar9003_hw_attach_phy_ops(struct ath
+@@ -1951,6 +1971,7 @@ void ar9003_hw_attach_phy_ops(struct ath
priv_ops->set_radar_params = ar9003_hw_set_radar_params;
priv_ops->fast_chan_change = ar9003_hw_fast_chan_change;
static const u8 ofdm2pwr[] = {
ALL_TARGET_LEGACY_6_24,
ALL_TARGET_LEGACY_6_24,
-@@ -1068,11 +1054,6 @@ static bool ar9003_hw_ani_control(struct
+@@ -1065,11 +1051,6 @@ static bool ar9003_hw_ani_control(struct
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
struct ar5416AniState *aniState = &ah->ani;
s32 value, value2;
switch (cmd & ah->ani_function) {
-@@ -1086,61 +1067,6 @@ static bool ar9003_hw_ani_control(struct
+@@ -1083,61 +1064,6 @@ static bool ar9003_hw_ani_control(struct
*/
u32 on = param ? 1 : 0;
if (pdata && pdata->leds && pdata->num_leds)
for (i = 0; i < pdata->num_leds; i++) {
---- a/include/linux/ath9k_platform.h
-+++ b/include/linux/ath9k_platform.h
-@@ -49,6 +49,10 @@ struct ath9k_platform_data {
-
- int num_leds;
- const struct gpio_led *leds;
-+
-+ unsigned num_btns;
-+ const struct gpio_keys_button *btns;
-+ unsigned btn_poll_interval;
- };
-
- #endif /* _LINUX_ATH9K_PLATFORM_H */
static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
-@@ -659,6 +660,7 @@ void ath_reset_work(struct work_struct *
+@@ -658,6 +659,7 @@ void ath_reset_work(struct work_struct *
static int ath9k_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
-@@ -737,6 +739,11 @@ static int ath9k_start(struct ieee80211_
+@@ -736,6 +738,11 @@ static int ath9k_start(struct ieee80211_
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
}
--- a/local-symbols
+++ b/local-symbols
-@@ -128,6 +128,7 @@ ATH9K_WOW=
+@@ -121,6 +121,7 @@ ATH9K_WOW=
ATH9K_RFKILL=
ATH9K_CHANNEL_CONTEXT=
ATH9K_PCOEM=
+
config ATH9K_DEBUGFS
bool "Atheros ath9k debugging"
- depends on ATH9K && DEBUG_FS
+ depends on ATH9K && DEBUG_FS && MAC80211_DEBUGFS
static int ath_ahb_probe(struct platform_device *pdev)
{
void __iomem *mem;
-@@ -80,6 +318,17 @@ static int ath_ahb_probe(struct platform
+@@ -80,6 +274,17 @@ static int ath_ahb_probe(struct platform
int ret = 0;
struct ath_hw *ah;
char hw_name[64];
if (!dev_get_platdata(&pdev->dev)) {
dev_err(&pdev->dev, "no platform data specified\n");
-@@ -118,13 +367,16 @@ static int ath_ahb_probe(struct platform
+@@ -118,17 +323,23 @@ static int ath_ahb_probe(struct platform
sc->mem = mem;
sc->irq = irq;
if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n");
goto err_irq;
-@@ -155,6 +407,9 @@ static int ath_ahb_remove(struct platfor
- free_irq(sc->irq, sc);
- ieee80211_free_hw(sc->hw);
}
+#ifdef CONFIG_OF
+ pdev->dev.platform_data = NULL;
+#endif
- return 0;
- }
-@@ -164,6 +419,9 @@ static struct platform_driver ath_ahb_dr
- .remove = ath_ahb_remove,
+ ah = sc->sc_ah;
+ ath9k_hw_name(ah, hw_name, sizeof(hw_name));
+@@ -162,6 +373,9 @@ static struct platform_driver ath_ahb_dr
+ .remove_new = ath_ahb_remove,
.driver = {
.name = "ath9k",
+#ifdef CONFIG_OF
static int modparam_bad_frames_preempt;
module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
MODULE_PARM_DESC(bad_frames_preempt,
-@@ -2869,10 +2874,10 @@ static int b43_gpio_init(struct b43_wlde
+@@ -2870,10 +2875,10 @@ static int b43_gpio_init(struct b43_wlde
u32 mask, set;
b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0);
antenna = b43_antenna_to_phyctl(antenna);
ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
/* We can't send beacons with short preamble. Would get PHY errors. */
-@@ -3284,8 +3284,8 @@ static int b43_chip_init(struct b43_wlde
+@@ -3285,8 +3285,8 @@ static int b43_chip_init(struct b43_wlde
/* Select the antennae */
if (phy->ops->set_rx_antenna)
if (phy->type == B43_PHYTYPE_B) {
value16 = b43_read16(dev, 0x005E);
-@@ -3986,7 +3986,6 @@ static int b43_op_config(struct ieee8021
+@@ -3988,7 +3988,6 @@ static int b43_op_config(struct ieee8021
struct b43_wldev *dev = wl->current_dev;
struct b43_phy *phy = &dev->phy;
struct ieee80211_conf *conf = &hw->conf;
int err = 0;
mutex_lock(&wl->mutex);
-@@ -4029,11 +4028,9 @@ static int b43_op_config(struct ieee8021
+@@ -4031,11 +4030,9 @@ static int b43_op_config(struct ieee8021
}
/* Antennas for RX and management frame TX. */
if (wl->radio_enabled != phy->radio_on) {
if (wl->radio_enabled) {
-@@ -5176,6 +5173,47 @@ static int b43_op_get_survey(struct ieee
+@@ -5178,6 +5175,47 @@ static int b43_op_get_survey(struct ieee
return 0;
}
+}
+
static const struct ieee80211_ops b43_hw_ops = {
- .tx = b43_op_tx,
- .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-@@ -5198,6 +5236,8 @@ static const struct ieee80211_ops b43_hw
+ .add_chanctx = ieee80211_emulate_add_chanctx,
+ .remove_chanctx = ieee80211_emulate_remove_chanctx,
+@@ -5204,6 +5242,8 @@ static const struct ieee80211_ops b43_hw
.sw_scan_complete = b43_op_sw_scan_complete_notifier,
.get_survey = b43_op_get_survey,
.rfkill_poll = b43_rfkill_poll,
};
/* Hard-reset the chip. Do not call this directly.
-@@ -5499,6 +5539,8 @@ static int b43_one_core_attach(struct b4
+@@ -5505,6 +5545,8 @@ static int b43_one_core_attach(struct b4
if (!wldev)
goto out;
wldev->use_pio = b43_modparam_pio;
wldev->dev = dev;
wldev->wl = wl;
-@@ -5590,6 +5632,9 @@ static struct b43_wl *b43_wireless_init(
+@@ -5596,6 +5638,9 @@ static struct b43_wl *b43_wireless_init(
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
-@@ -2886,6 +2886,14 @@ static int b43_gpio_init(struct b43_wlde
+@@ -2887,6 +2887,14 @@ static int b43_gpio_init(struct b43_wlde
} else if (dev->dev->chip_id == 0x5354) {
/* Don't allow overtaking buttons GPIOs */
set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -979,8 +979,36 @@ static struct wireless_dev *brcmf_cfg802
+@@ -980,8 +980,36 @@ static struct wireless_dev *brcmf_cfg802
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_pub *drvr = cfg->pub;
struct wireless_dev *wdev;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -3327,6 +3327,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -3313,6 +3313,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
* preference in cfg struct to apply this to
* FW later while initializing the dongle
*/
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -7987,6 +7987,7 @@ static s32 brcmf_translate_country_code(
+@@ -7979,6 +7979,7 @@ static s32 brcmf_translate_country_code(
return 0;
}
static int
brcmf_parse_dump_obss(char *buf, struct brcmf_dump_survey *survey)
{
-@@ -8209,6 +8210,7 @@ exit:
+@@ -8201,6 +8202,7 @@ exit:
brcmf_set_mpc(ifp, 1);
return err;
}
static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *req)
-@@ -8361,8 +8363,10 @@ struct brcmf_cfg80211_info *brcmf_cfg802
+@@ -8353,8 +8355,10 @@ struct brcmf_cfg80211_info *brcmf_cfg802
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
#endif
@set -e ; test -f local-symbols || ( \
echo "/--------------" ;\
echo "| You shouldn't run make in the backports tree, but only in" ;\
-@@ -60,58 +62,62 @@ mrproper:
+@@ -60,57 +62,62 @@ mrproper:
echo "| (that isn't currently running.)" ;\
echo "\\--" ;\
false)
- done \
- ) > Kconfig.kernel ;\
- kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) M=$(BACKPORT_DIR) \
-- kernelversion | sed 's/^\(\([3-5]\|2\.6\)\.[0-9]\+\).*/\1/;t;d');\
+- kernelversion | sed 's/^\(\([3-6]\|2\.6\)\.[0-9]\+\).*/\1/;t;d');\
- test "$$kver" != "" || echo "Kernel version parse failed!" ;\
- test "$$kver" != "" ;\
-- kvers="$$(seq 14 39 | sed 's/^/2.6./')" ;\
-- kvers="$$kvers $$(seq 0 19 | sed 's/^/3./')" ;\
- kvers="$$kvers $$(seq 0 20 | sed 's/^/4./')" ;\
-- kvers="$$kvers $$(seq 0 99 | sed 's/^/5./')" ;\
+- kvers="$$kvers $$(seq 0 19 | sed 's/^/5./')" ;\
+- kvers="$$kvers $$(seq 0 20 | sed 's/^/6./')" ;\
- print=0 ;\
- for v in $$kvers ; do \
- if [ "$$print" = "1" ] ; then \
+ @echo " done."
+
+Kconfig.versions: Kconfig.kernel
-+ @kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) M=$(BACKPORT_DIR) \
-+ kernelversion | sed 's/^\(\([3-5]\|2\.6\)\.[0-9]\+\).*/\1/;t;d');\
++ @kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) M=$(BACKPORT_DIR) \
++ kernelversion | sed 's/^\(\([3-6]\|2\.6\)\.[0-9]\+\).*/\1/;t;d');\
+ test "$$kver" != "" || echo "Kernel version parse failed!" ;\
+ test "$$kver" != "" ;\
-+ kvers="$$(seq 14 39 | sed 's/^/2.6./')" ;\
-+ kvers="$$kvers $$(seq 0 19 | sed 's/^/3./')" ;\
+ kvers="$$kvers $$(seq 0 20 | sed 's/^/4./')" ;\
-+ kvers="$$kvers $$(seq 0 99 | sed 's/^/5./')" ;\
++ kvers="$$kvers $$(seq 0 19 | sed 's/^/5./')" ;\
++ kvers="$$kvers $$(seq 0 20 | sed 's/^/6./')" ;\
+ print=0 ;\
+ for v in $$kvers ; do \
+ if [ "$$print" = "1" ] ; then \
+ echo " def_bool y" ;\
+ fi ;\
+ if [ "$$v" = "$$kver" ] ; then print=1 ; fi ;\
-+ done > $@
-+ @RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | \
++ done > Kconfig.versions ;\
++ # RHEL as well, sadly we need to grep for it ;\
++ RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | \
+ sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\
+ RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | \
+ sed 's/.*=\s*\([0-9]*\)/\1/;t;d') ;\
--- a/local-symbols
+++ b/local-symbols
-@@ -493,43 +493,6 @@ USB_VL600=
+@@ -471,43 +471,6 @@ USB_VL600=
USB_NET_CH9200=
USB_NET_AQC111=
USB_RTL8153_ECM=
config B43_PHY_G
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
-@@ -2853,7 +2853,7 @@ static struct ssb_device *b43_ssb_gpio_d
+@@ -2854,7 +2854,7 @@ static struct ssb_device *b43_ssb_gpio_d
{
struct ssb_bus *bus = dev->dev->sdev->bus;
return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
#else
return bus->chipco.dev;
-@@ -4871,7 +4871,7 @@ static int b43_wireless_core_init(struct
+@@ -4873,7 +4873,7 @@ static int b43_wireless_core_init(struct
}
if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
depends on CORDIC
--- a/Kconfig.local
+++ b/Kconfig.local
-@@ -1483,117 +1483,6 @@ config BACKPORTED_USB_NET_AQC111
+@@ -1417,117 +1417,6 @@ config BACKPORTED_USB_NET_AQC111
config BACKPORTED_USB_RTL8153_ECM
tristate
default USB_RTL8153_ECM
source "$BACKPORT_DIR/drivers/staging/Kconfig"
--- a/Makefile.kernel
+++ b/Makefile.kernel
-@@ -43,8 +43,6 @@ obj-$(CPTCFG_QRTR) += net/qrtr/
+@@ -42,8 +42,6 @@ obj-$(CPTCFG_QRTR) += net/qrtr/
obj-$(CPTCFG_QCOM_QMI_HELPERS) += drivers/soc/qcom/
obj-$(CPTCFG_MHI_BUS) += drivers/bus/mhi/
obj-$(CPTCFG_WLAN) += drivers/net/wireless/
+++ /dev/null
---- a/drivers/net/wireless/virtual/mac80211_hwsim.c
-+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
-@@ -6179,7 +6179,9 @@ static struct genl_family hwsim_genl_fam
- .module = THIS_MODULE,
- .small_ops = hwsim_ops,
- .n_small_ops = ARRAY_SIZE(hwsim_ops),
-+#if LINUX_VERSION_IS_GEQ(6,1,0)
- .resv_start_op = HWSIM_CMD_REPORT_PMSR + 1, // match with __HWSIM_CMD_MAX
-+#endif
- .mcgrps = hwsim_mcgrps,
- .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
- };
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -17551,7 +17551,9 @@ static struct genl_family nl80211_fam __
- .n_ops = ARRAY_SIZE(nl80211_ops),
- .small_ops = nl80211_small_ops,
- .n_small_ops = ARRAY_SIZE(nl80211_small_ops),
-+#if LINUX_VERSION_IS_GEQ(6,1,0)
- .resv_start_op = NL80211_CMD_REMOVE_LINK_STA + 1,
-+#endif
- .mcgrps = nl80211_mcgrps,
- .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
- .parallel_ops = true,
source "$BACKPORT_DIR/drivers/net/usb/Kconfig"
--- a/Makefile.kernel
+++ b/Makefile.kernel
-@@ -39,9 +39,7 @@ obj-y += compat/
+@@ -38,9 +38,7 @@ obj-y += compat/
obj-$(CPTCFG_CFG80211) += net/wireless/
obj-$(CPTCFG_MAC80211) += net/mac80211/
--- a/local-symbols
+++ b/local-symbols
-@@ -65,14 +65,6 @@ MAC80211_MESH_PS_DEBUG=
+@@ -59,14 +59,6 @@ MAC80211_MESH_PS_DEBUG=
MAC80211_TDLS_DEBUG=
MAC80211_DEBUG_COUNTERS=
MAC80211_STA_HASH_MAX_SIZE=
-MHI_BUS_EP=
QCOM_AOSS_QMP=
QCOM_COMMAND_DB=
- QCOM_CPR=
+ QCOM_GENI_SE=
--- a/backport-include/linux/random.h
+++ b/backport-include/linux/random.h
-@@ -23,7 +23,7 @@ static inline u16 get_random_u16(void)
+@@ -15,7 +15,7 @@ static inline u16 get_random_u16(void)
}
#endif
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 17 Apr 2023 19:42:38 +0200
-Subject: [PATCH] Revert "wifi: iwlwifi: Use generic thermal_zone_get_trip()
- function"
-
-This reverts commit 3d2f20ad46f83b333025f5e8e4afc34be8f13c4c.
----
-
---- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
-+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
-@@ -531,7 +531,7 @@ struct iwl_mvm_tt_mgmt {
- * @tzone: thermal zone device data
- */
- struct iwl_mvm_thermal_device {
-- struct thermal_trip trips[IWL_MAX_DTS_TRIPS];
-+ s16 temp_trips[IWL_MAX_DTS_TRIPS];
- u8 fw_trips_index[IWL_MAX_DTS_TRIPS];
- struct thermal_zone_device *tzone;
- };
---- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
-+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
-@@ -573,11 +573,11 @@ int iwl_mvm_send_temp_report_ths_cmd(str
- * and uncompressed, the FW should get it compressed and sorted
- */
-
-- /* compress trips to cmd array, remove uninitialized values*/
-+ /* compress temp_trips to cmd array, remove uninitialized values*/
- for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
-- if (mvm->tz_device.trips[i].temperature != INT_MIN) {
-+ if (mvm->tz_device.temp_trips[i] != S16_MIN) {
- cmd.thresholds[idx++] =
-- cpu_to_le16((s16)(mvm->tz_device.trips[i].temperature / 1000));
-+ cpu_to_le16(mvm->tz_device.temp_trips[i]);
- }
- }
- cmd.num_temps = cpu_to_le32(idx);
-@@ -593,8 +593,8 @@ int iwl_mvm_send_temp_report_ths_cmd(str
- */
- for (i = 0; i < idx; i++) {
- for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) {
-- if ((int)(le16_to_cpu(cmd.thresholds[i]) * 1000) ==
-- mvm->tz_device.trips[j].temperature)
-+ if (le16_to_cpu(cmd.thresholds[i]) ==
-+ mvm->tz_device.temp_trips[j])
- mvm->tz_device.fw_trips_index[i] = j;
- }
- }
-@@ -638,12 +638,37 @@ out:
- return ret;
- }
-
-+static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device,
-+ int trip, int *temp)
-+{
-+ struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
-+
-+ if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
-+ return -EINVAL;
-+
-+ *temp = mvm->tz_device.temp_trips[trip] * 1000;
-+
-+ return 0;
-+}
-+
-+static int iwl_mvm_tzone_get_trip_type(struct thermal_zone_device *device,
-+ int trip, enum thermal_trip_type *type)
-+{
-+ if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
-+ return -EINVAL;
-+
-+ *type = THERMAL_TRIP_PASSIVE;
-+
-+ return 0;
-+}
-+
- static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
- int trip, int temp)
- {
- struct iwl_mvm *mvm = thermal_zone_device_priv(device);
- struct iwl_mvm_thermal_device *tzone;
-- int ret;
-+ int i, ret;
-+ s16 temperature;
-
- mutex_lock(&mvm->mutex);
-
-@@ -653,17 +678,40 @@ static int iwl_mvm_tzone_set_trip_temp(s
- goto out;
- }
-
-+ if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
- if ((temp / 1000) > S16_MAX) {
- ret = -EINVAL;
- goto out;
- }
-
-+ temperature = (s16)(temp / 1000);
- tzone = &mvm->tz_device;
-+
- if (!tzone) {
- ret = -EIO;
- goto out;
- }
-
-+ /* no updates*/
-+ if (tzone->temp_trips[trip] == temperature) {
-+ ret = 0;
-+ goto out;
-+ }
-+
-+ /* already existing temperature */
-+ for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
-+ if (tzone->temp_trips[i] == temperature) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+ }
-+
-+ tzone->temp_trips[trip] = temperature;
-+
- ret = iwl_mvm_send_temp_report_ths_cmd(mvm);
- out:
- mutex_unlock(&mvm->mutex);
-@@ -672,6 +720,8 @@ out:
-
- static struct thermal_zone_device_ops tzone_ops = {
- .get_temp = iwl_mvm_tzone_get_temp,
-+ .get_trip_temp = iwl_mvm_tzone_get_trip_temp,
-+ .get_trip_type = iwl_mvm_tzone_get_trip_type,
- .set_trip_temp = iwl_mvm_tzone_set_trip_temp,
- };
-
-@@ -693,8 +743,7 @@ static void iwl_mvm_thermal_zone_registe
- BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
-
- sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF);
-- mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name,
-- mvm->tz_device.trips,
-+ mvm->tz_device.tzone = thermal_zone_device_register(name,
- IWL_MAX_DTS_TRIPS,
- IWL_WRITABLE_TRIPS_MSK,
- mvm, &tzone_ops,
-@@ -717,10 +766,8 @@ static void iwl_mvm_thermal_zone_registe
- /* 0 is a valid temperature,
- * so initialize the array with S16_MIN which invalid temperature
- */
-- for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) {
-- mvm->tz_device.trips[i].temperature = INT_MIN;
-- mvm->tz_device.trips[i].type = THERMAL_TRIP_PASSIVE;
-- }
-+ for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
-+ mvm->tz_device.temp_trips[i] = S16_MIN;
- }
-
- static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
--- /dev/null
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+@@ -689,13 +689,23 @@ static void iwl_mvm_thermal_zone_registe
+ for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) {
+ mvm->tz_device.trips[i].temperature = THERMAL_TEMP_INVALID;
+ mvm->tz_device.trips[i].type = THERMAL_TRIP_PASSIVE;
++#if LINUX_VERSION_IS_GEQ(6,9,0)
+ mvm->tz_device.trips[i].flags = THERMAL_TRIP_FLAG_RW_TEMP;
++#endif
+ }
++#if LINUX_VERSION_IS_GEQ(6,9,0)
+ mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name,
+ mvm->tz_device.trips,
+ IWL_MAX_DTS_TRIPS,
+ mvm, &tzone_ops,
+ NULL, 0, 0);
++#else
++ mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name,
++ mvm->tz_device.trips,
++ IWL_MAX_DTS_TRIPS, 0,
++ mvm, &tzone_ops,
++ NULL, 0, 0);
++#endif
+ if (IS_ERR(mvm->tz_device.tzone)) {
+ IWL_DEBUG_TEMP(mvm,
+ "Failed to register to thermal zone (err = %ld)\n",
--- /dev/null
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -16383,9 +16383,14 @@ static u32 nl80211_internal_flags[] = {
+ #undef SELECTOR
+ };
+
++#if LINUX_VERSION_IS_LESS(6,2,0)
++static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
++ struct genl_info *info)
++#else
+ static int nl80211_pre_doit(const struct genl_split_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info)
++#endif
+ {
+ struct cfg80211_registered_device *rdev = NULL;
+ struct wireless_dev *wdev = NULL;
+@@ -16485,9 +16490,14 @@ out_unlock:
+ return err;
+ }
+
++#if LINUX_VERSION_IS_LESS(6,2,0)
++static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
++ struct genl_info *info)
++#else
+ static void nl80211_post_doit(const struct genl_split_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info)
++#endif
+ {
+ u32 internal_flags = nl80211_internal_flags[ops->internal_flags];
+
+++ /dev/null
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -16442,8 +16442,7 @@ static u32 nl80211_internal_flags[] = {
- #undef SELECTOR
- };
-
--static int nl80211_pre_doit(const struct genl_split_ops *ops,
-- struct sk_buff *skb,
-+static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
- struct genl_info *info)
- {
- struct cfg80211_registered_device *rdev = NULL;
-@@ -16544,8 +16543,7 @@ out_unlock:
- return err;
- }
-
--static void nl80211_post_doit(const struct genl_split_ops *ops,
-- struct sk_buff *skb,
-+static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
- struct genl_info *info)
- {
- u32 internal_flags = nl80211_internal_flags[ops->internal_flags];
+++ /dev/null
---- a/backport-include/net/genetlink.h
-+++ b/backport-include/net/genetlink.h
-@@ -3,6 +3,7 @@
- #include_next <net/genetlink.h>
- #include <linux/version.h>
-
-+#if LINUX_VERSION_IS_LESS(4,12,0)
- static inline void __bp_genl_info_userhdr_set(struct genl_info *info,
- void *userhdr)
- {
-@@ -14,7 +15,6 @@ static inline void *__bp_genl_info_userh
- return info->userhdr;
- }
-
--#if LINUX_VERSION_IS_LESS(4,12,0)
- #define GENL_SET_ERR_MSG(info, msg) NL_SET_ERR_MSG(genl_info_extack(info), msg)
-
- static inline int genl_err_attr(struct genl_info *info, int err,
-@@ -44,11 +44,13 @@ static inline struct netlink_ext_ack *ge
- #endif
- }
-
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- /* this gets put in place of info->userhdr, since we use that above */
- static inline void *genl_info_userhdr(struct genl_info *info)
- {
- return (u8 *)info->genlhdr + GENL_HDRLEN;
- }
-+#endif
-
- #if LINUX_VERSION_IS_LESS(4,10,0)
- #define __genl_ro_after_init
--- /dev/null
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+@@ -1581,7 +1581,11 @@ static int brcmf_usb_reset_device(struct
+
+ void brcmf_usb_exit(void)
+ {
++#if LINUX_VERSION_IS_GEQ(6,8,0)
+ struct device_driver *drv = &brcmf_usbdrvr.driver;
++#else
++ struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
++#endif
+ int ret;
+
+ brcmf_dbg(USB, "Enter\n");
+++ /dev/null
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -16442,8 +16442,14 @@ static u32 nl80211_internal_flags[] = {
- #undef SELECTOR
- };
-
-+#if LINUX_VERSION_IS_LESS(6,2,0)
- static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
- struct genl_info *info)
-+#else
-+static int nl80211_pre_doit(const struct genl_split_ops *ops,
-+ struct sk_buff *skb,
-+ struct genl_info *info)
-+#endif
- {
- struct cfg80211_registered_device *rdev = NULL;
- struct wireless_dev *wdev = NULL;
-@@ -16543,8 +16549,14 @@ out_unlock:
- return err;
- }
-
-+#if LINUX_VERSION_IS_LESS(6,2,0)
- static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
- struct genl_info *info)
-+#else
-+static void nl80211_post_doit(const struct genl_split_ops *ops,
-+ struct sk_buff *skb,
-+ struct genl_info *info)
-+#endif
- {
- u32 internal_flags = nl80211_internal_flags[ops->internal_flags];
-
+++ /dev/null
---- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
-+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
-@@ -531,7 +531,11 @@ struct iwl_mvm_tt_mgmt {
- * @tzone: thermal zone device data
- */
- struct iwl_mvm_thermal_device {
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- s16 temp_trips[IWL_MAX_DTS_TRIPS];
-+#else
-+ struct thermal_trip trips[IWL_MAX_DTS_TRIPS];
-+#endif
- u8 fw_trips_index[IWL_MAX_DTS_TRIPS];
- struct thermal_zone_device *tzone;
- };
---- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
-+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
-@@ -573,6 +573,7 @@ int iwl_mvm_send_temp_report_ths_cmd(str
- * and uncompressed, the FW should get it compressed and sorted
- */
-
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- /* compress temp_trips to cmd array, remove uninitialized values*/
- for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
- if (mvm->tz_device.temp_trips[i] != S16_MIN) {
-@@ -580,6 +581,15 @@ int iwl_mvm_send_temp_report_ths_cmd(str
- cpu_to_le16(mvm->tz_device.temp_trips[i]);
- }
- }
-+#else
-+ /* compress trips to cmd array, remove uninitialized values*/
-+ for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
-+ if (mvm->tz_device.trips[i].temperature != INT_MIN) {
-+ cmd.thresholds[idx++] =
-+ cpu_to_le16((s16)(mvm->tz_device.trips[i].temperature / 1000));
-+ }
-+ }
-+#endif
- cmd.num_temps = cpu_to_le32(idx);
-
- if (!idx)
-@@ -593,8 +603,13 @@ int iwl_mvm_send_temp_report_ths_cmd(str
- */
- for (i = 0; i < idx; i++) {
- for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) {
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- if (le16_to_cpu(cmd.thresholds[i]) ==
- mvm->tz_device.temp_trips[j])
-+#else
-+ if ((int)(le16_to_cpu(cmd.thresholds[i]) * 1000) ==
-+ mvm->tz_device.trips[j].temperature)
-+#endif
- mvm->tz_device.fw_trips_index[i] = j;
- }
- }
-@@ -638,6 +653,7 @@ out:
- return ret;
- }
-
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device,
- int trip, int *temp)
- {
-@@ -661,14 +677,19 @@ static int iwl_mvm_tzone_get_trip_type(s
-
- return 0;
- }
-+#endif
-
- static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
- int trip, int temp)
- {
- struct iwl_mvm *mvm = thermal_zone_device_priv(device);
- struct iwl_mvm_thermal_device *tzone;
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- int i, ret;
- s16 temperature;
-+#else
-+ int ret;
-+#endif
-
- mutex_lock(&mvm->mutex);
-
-@@ -678,17 +699,21 @@ static int iwl_mvm_tzone_set_trip_temp(s
- goto out;
- }
-
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) {
- ret = -EINVAL;
- goto out;
- }
-+#endif
-
- if ((temp / 1000) > S16_MAX) {
- ret = -EINVAL;
- goto out;
- }
-
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- temperature = (s16)(temp / 1000);
-+#endif
- tzone = &mvm->tz_device;
-
- if (!tzone) {
-@@ -696,6 +721,7 @@ static int iwl_mvm_tzone_set_trip_temp(s
- goto out;
- }
-
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- /* no updates*/
- if (tzone->temp_trips[trip] == temperature) {
- ret = 0;
-@@ -711,6 +737,7 @@ static int iwl_mvm_tzone_set_trip_temp(s
- }
-
- tzone->temp_trips[trip] = temperature;
-+#endif
-
- ret = iwl_mvm_send_temp_report_ths_cmd(mvm);
- out:
-@@ -720,8 +747,10 @@ out:
-
- static struct thermal_zone_device_ops tzone_ops = {
- .get_temp = iwl_mvm_tzone_get_temp,
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- .get_trip_temp = iwl_mvm_tzone_get_trip_temp,
- .get_trip_type = iwl_mvm_tzone_get_trip_type,
-+#endif
- .set_trip_temp = iwl_mvm_tzone_set_trip_temp,
- };
-
-@@ -743,7 +772,12 @@ static void iwl_mvm_thermal_zone_registe
- BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
-
- sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF);
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- mvm->tz_device.tzone = thermal_zone_device_register(name,
-+#else
-+ mvm->tz_device.tzone = thermal_zone_device_register_with_trips(name,
-+ mvm->tz_device.trips,
-+#endif
- IWL_MAX_DTS_TRIPS,
- IWL_WRITABLE_TRIPS_MSK,
- mvm, &tzone_ops,
-@@ -766,8 +800,15 @@ static void iwl_mvm_thermal_zone_registe
- /* 0 is a valid temperature,
- * so initialize the array with S16_MIN which invalid temperature
- */
-+#if LINUX_VERSION_IS_LESS(6,6,0)
- for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
- mvm->tz_device.temp_trips[i] = S16_MIN;
-+#else
-+ for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++) {
-+ mvm->tz_device.trips[i].temperature = INT_MIN;
-+ mvm->tz_device.trips[i].type = THERMAL_TRIP_PASSIVE;
-+ }
-+#endif
- }
-
- static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
-@@ -5703,6 +5703,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
+@@ -5707,6 +5707,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw")
MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
static const struct pci_device_id mwl8k_pci_id_table[] = {
--- a/drivers/net/wireless/marvell/mwl8k.c
+++ b/drivers/net/wireless/marvell/mwl8k.c
-@@ -6289,6 +6289,8 @@ static int mwl8k_probe(struct pci_dev *p
+@@ -6293,6 +6293,8 @@ static int mwl8k_probe(struct pci_dev *p
priv->running_bsses = 0;
return rc;
err_stop_firmware:
-@@ -6322,8 +6324,6 @@ static void mwl8k_remove(struct pci_dev
+@@ -6326,8 +6328,6 @@ static void mwl8k_remove(struct pci_dev
return;
priv = hw->priv;
mwifiex_init_fw_complete(adapter);
return -1;
} else if (adapter->last_init_cmd == cmdresp_no)
-@@ -1273,8 +1353,8 @@ mwifiex_process_sleep_confirm_resp(struc
+@@ -1265,8 +1345,8 @@ mwifiex_process_sleep_confirm_resp(struc
if (command != HostCmd_CMD_802_11_PS_MODE_ENH) {
mwifiex_dbg(adapter, ERROR,
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
-@@ -1086,6 +1086,8 @@ void mwifiex_cancel_all_pending_cmd(stru
+@@ -1084,6 +1084,8 @@ void mwifiex_cancel_all_pending_cmd(stru
void mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter);
void mwifiex_cancel_scan(struct mwifiex_adapter *adapter);
+++ /dev/null
-From 2ecfe6f07e8e6257cad3d3290c5aec2102120041 Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Sat, 23 Sep 2023 09:01:01 +0800
-Subject: wifi: rt2x00: fix MT7620 low RSSI issue
-
-On Mediatek vendor driver[1], MT7620 (RT6352) uses different RSSI
-base value '-2' compared to the other RT2x00 chips. This patch
-introduces the SoC specific base value to fix the low RSSI value
-reports on MT7620.
-
-[1] Found on MT76x2E_MT7620_LinuxAP_V3.0.4.0_P3 ConvertToRssi().
-
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://lore.kernel.org/r/TYAP286MB031571CDB146C414A908A66DBCFEA@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -856,6 +856,7 @@ static int rt2800_agc_to_rssi(struct rt2
- s8 rssi0 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI0);
- s8 rssi1 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI1);
- s8 rssi2 = rt2x00_get_field32(rxwi_w2, RXWI_W2_RSSI2);
-+ s8 base_val = rt2x00_rt(rt2x00dev, RT6352) ? -2 : -12;
- u16 eeprom;
- u8 offset0;
- u8 offset1;
-@@ -880,9 +881,9 @@ static int rt2800_agc_to_rssi(struct rt2
- * If the value in the descriptor is 0, it is considered invalid
- * and the default (extremely low) rssi value is assumed
- */
-- rssi0 = (rssi0) ? (-12 - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
-- rssi1 = (rssi1) ? (-12 - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
-- rssi2 = (rssi2) ? (-12 - offset2 - rt2x00dev->lna_gain - rssi2) : -128;
-+ rssi0 = (rssi0) ? (base_val - offset0 - rt2x00dev->lna_gain - rssi0) : -128;
-+ rssi1 = (rssi1) ? (base_val - offset1 - rt2x00dev->lna_gain - rssi1) : -128;
-+ rssi2 = (rssi2) ? (base_val - offset2 - rt2x00dev->lna_gain - rssi2) : -128;
-
- /*
- * mac80211 only accepts a single RSSI value. Calculating the
+++ /dev/null
-From 69708fbb2c698f262e03360d064c7066e0679953 Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Sat, 14 Oct 2023 14:55:01 +0800
-Subject: wifi: rt2x00: fix rt2800 watchdog function
-
-The watchdog function is broken on rt2800 series SoCs. This patch
-fixes the incorrect watchdog logic to make it work again.
-
-1. Update current wdt queue index if it's not equal to the previous
- index. Watchdog compares the current and previous queue index to
- judge if the queue hung.
-2. Make sure hung_{rx,tx} 'true' status won't be override by the
- normal queue. Any queue hangs should trigger a reset action.
-3. Clear the watchdog counter of all queues before resetting the
- hardware. This change may help to avoid the reset loop.
-4. Change hang check function return type to bool as we only need
- to return two status, yes or no.
-
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://lore.kernel.org/r/TYAP286MB0315BC1D83D31154924F0D39BCD1A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 17 +++++++++++------
- 1 file changed, 11 insertions(+), 6 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -1237,13 +1237,14 @@ void rt2800_txdone_nostatus(struct rt2x0
- }
- EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus);
-
--static int rt2800_check_hung(struct data_queue *queue)
-+static bool rt2800_check_hung(struct data_queue *queue)
- {
- unsigned int cur_idx = rt2800_drv_get_dma_done(queue);
-
-- if (queue->wd_idx != cur_idx)
-+ if (queue->wd_idx != cur_idx) {
-+ queue->wd_idx = cur_idx;
- queue->wd_count = 0;
-- else
-+ } else
- queue->wd_count++;
-
- return queue->wd_count > 16;
-@@ -1280,7 +1281,7 @@ void rt2800_watchdog(struct rt2x00_dev *
- case QID_MGMT:
- if (rt2x00queue_empty(queue))
- continue;
-- hung_tx = rt2800_check_hung(queue);
-+ hung_tx = hung_tx || rt2800_check_hung(queue);
- break;
- case QID_RX:
- /* For station mode we should reactive at least
-@@ -1289,7 +1290,7 @@ void rt2800_watchdog(struct rt2x00_dev *
- */
- if (rt2x00dev->intf_sta_count == 0)
- continue;
-- hung_rx = rt2800_check_hung(queue);
-+ hung_rx = hung_rx || rt2800_check_hung(queue);
- break;
- default:
- break;
-@@ -1302,8 +1303,12 @@ void rt2800_watchdog(struct rt2x00_dev *
- if (hung_rx)
- rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
-
-- if (hung_tx || hung_rx)
-+ if (hung_tx || hung_rx) {
-+ queue_for_each(rt2x00dev, queue)
-+ queue->wd_count = 0;
-+
- ieee80211_restart_hw(rt2x00dev->hw);
-+ }
- }
- EXPORT_SYMBOL_GPL(rt2800_watchdog);
-
+++ /dev/null
-From 1ffe76d5ae78553948d67a978acd9945c2f0a175 Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Thu, 19 Oct 2023 19:58:56 +0800
-Subject: wifi: rt2x00: improve MT7620 register initialization
-
-1. Do not hard reset the BBP. We can use soft reset instead. This
- change has some help to the calibration failure issue.
-2. Enable falling back to legacy rate from the HT/RTS rate by
- setting the HT_FBK_TO_LEGACY register.
-3. Implement MCS rate specific maximum PSDU size. It can improve
- the transmission quality under the low RSSI condition.
-4. Set BBP_84 register value to 0x19. This is used for extension
- channel overlapping IOT.
-
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://lore.kernel.org/r/TYAP286MB031553CCD4B7A3B89C85935DBCD4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/ralink/rt2x00/rt2800.h | 18 ++++++++++++++++++
- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 24 ++++++++++++++++++++++++
- drivers/net/wireless/ralink/rt2x00/rt2800mmio.c | 3 +++
- 3 files changed, 45 insertions(+)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
-@@ -871,6 +871,18 @@
- #define LED_CFG_LED_POLAR FIELD32(0x40000000)
-
- /*
-+ * AMPDU_MAX_LEN_20M1S: Per MCS max A-MPDU length, 20 MHz, MCS 0-7
-+ * AMPDU_MAX_LEN_20M2S: Per MCS max A-MPDU length, 20 MHz, MCS 8-15
-+ * AMPDU_MAX_LEN_40M1S: Per MCS max A-MPDU length, 40 MHz, MCS 0-7
-+ * AMPDU_MAX_LEN_40M2S: Per MCS max A-MPDU length, 40 MHz, MCS 8-15
-+ * Maximum A-MPDU length = 2^(AMPDU_MAX - 5) kilobytes
-+ */
-+#define AMPDU_MAX_LEN_20M1S 0x1030
-+#define AMPDU_MAX_LEN_20M2S 0x1034
-+#define AMPDU_MAX_LEN_40M1S 0x1038
-+#define AMPDU_MAX_LEN_40M2S 0x103C
-+
-+/*
- * AMPDU_BA_WINSIZE: Force BlockAck window size
- * FORCE_WINSIZE_ENABLE:
- * 0: Disable forcing of BlockAck window size
-@@ -1545,6 +1557,12 @@
- */
- #define EXP_ACK_TIME 0x1380
-
-+/*
-+ * HT_FBK_TO_LEGACY: Enable/Disable HT/RTS fallback to OFDM/CCK rate
-+ * Not available for legacy SoCs
-+ */
-+#define HT_FBK_TO_LEGACY 0x1384
-+
- /* TX_PWR_CFG_5 */
- #define TX_PWR_CFG_5 0x1384
- #define TX_PWR_CFG_5_MCS16_CH0 FIELD32(0x0000000f)
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -5851,6 +5851,7 @@ static int rt2800_init_registers(struct
- struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
- u32 reg;
- u16 eeprom;
-+ u8 bbp;
- unsigned int i;
- int ret;
-
-@@ -5860,6 +5861,19 @@ static int rt2800_init_registers(struct
- if (ret)
- return ret;
-
-+ if (rt2x00_rt(rt2x00dev, RT6352)) {
-+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x01);
-+
-+ bbp = rt2800_bbp_read(rt2x00dev, 21);
-+ bbp |= 0x01;
-+ rt2800_bbp_write(rt2x00dev, 21, bbp);
-+ bbp = rt2800_bbp_read(rt2x00dev, 21);
-+ bbp &= (~0x01);
-+ rt2800_bbp_write(rt2x00dev, 21, bbp);
-+
-+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00);
-+ }
-+
- rt2800_register_write(rt2x00dev, LEGACY_BASIC_RATE, 0x0000013f);
- rt2800_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003);
-
-@@ -6013,6 +6027,14 @@ static int rt2800_init_registers(struct
- reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1);
- rt2x00_set_field32(®, TX_ALC_CFG_1_ROS_BUSY_EN, 0);
- rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg);
-+
-+ rt2800_register_write(rt2x00dev, AMPDU_MAX_LEN_20M1S, 0x77754433);
-+ rt2800_register_write(rt2x00dev, AMPDU_MAX_LEN_20M2S, 0x77765543);
-+ rt2800_register_write(rt2x00dev, AMPDU_MAX_LEN_40M1S, 0x77765544);
-+ rt2800_register_write(rt2x00dev, AMPDU_MAX_LEN_40M2S, 0x77765544);
-+
-+ rt2800_register_write(rt2x00dev, HT_FBK_TO_LEGACY, 0x1010);
-+
- } else {
- rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
-@@ -7231,6 +7253,8 @@ static void rt2800_init_bbp_6352(struct
- rt2800_bbp_dcoc_write(rt2x00dev, 159, 0x64);
-
- rt2800_bbp4_mac_if_ctrl(rt2x00dev);
-+
-+ rt2800_bbp_write(rt2x00dev, 84, 0x19);
- }
-
- static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
---- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
-@@ -760,6 +760,9 @@ int rt2800mmio_init_registers(struct rt2
-
- rt2x00mmio_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
-
-+ if (rt2x00_rt(rt2x00dev, RT6352))
-+ return 0;
-+
- reg = 0;
- rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1);
- rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1);
+++ /dev/null
-From a28533c6be1711584bf3ec978309d5c590029821 Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Thu, 19 Oct 2023 19:58:57 +0800
-Subject: wifi: rt2x00: rework MT7620 channel config function
-
-1. Move the channel configuration code from rt2800_vco_calibration()
- to the rt2800_config_channel().
-2. Use MT7620 SoC specific AGC initial LNA value instead of the
- RT5592's value.
-3. BBP{195,196} pairing write has been replaced with
- rt2800_bbp_glrt_write() to reduce redundant code.
-
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://lore.kernel.org/r/TYAP286MB0315622A4340BFFA530B1B86BCD4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 91 ++++++++++----------------
- 1 file changed, 35 insertions(+), 56 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -3861,14 +3861,6 @@ static void rt2800_config_channel_rf7620
- rfcsr |= tx_agc_fc;
- rt2800_rfcsr_write_bank(rt2x00dev, 7, 59, rfcsr);
- }
--
-- if (conf_is_ht40(conf)) {
-- rt2800_bbp_glrt_write(rt2x00dev, 141, 0x10);
-- rt2800_bbp_glrt_write(rt2x00dev, 157, 0x2f);
-- } else {
-- rt2800_bbp_glrt_write(rt2x00dev, 141, 0x1a);
-- rt2800_bbp_glrt_write(rt2x00dev, 157, 0x40);
-- }
- }
-
- static void rt2800_config_alc_rt6352(struct rt2x00_dev *rt2x00dev,
-@@ -4437,32 +4429,46 @@ static void rt2800_config_channel(struct
- usleep_range(1000, 1500);
- }
-
-- if (rt2x00_rt(rt2x00dev, RT5592) || rt2x00_rt(rt2x00dev, RT6352)) {
-- reg = 0x10;
-- if (!conf_is_ht40(conf)) {
-- if (rt2x00_rt(rt2x00dev, RT6352) &&
-- rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
-- reg |= 0x5;
-- } else {
-- reg |= 0xa;
-- }
-- }
-- rt2800_bbp_write(rt2x00dev, 195, 141);
-- rt2800_bbp_write(rt2x00dev, 196, reg);
-+ if (rt2x00_rt(rt2x00dev, RT5592)) {
-+ bbp = conf_is_ht40(conf) ? 0x10 : 0x1a;
-+ rt2800_bbp_glrt_write(rt2x00dev, 141, bbp);
-
-- /* AGC init.
-- * Despite the vendor driver using different values here for
-- * RT6352 chip, we use 0x1c for now. This may have to be changed
-- * once TSSI got implemented.
-- */
-- reg = (rf->channel <= 14 ? 0x1c : 0x24) + 2*rt2x00dev->lna_gain;
-- rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
-+ bbp = (rf->channel <= 14 ? 0x1c : 0x24) + 2 * rt2x00dev->lna_gain;
-+ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, bbp);
-
-- if (rt2x00_rt(rt2x00dev, RT5592))
-- rt2800_iq_calibrate(rt2x00dev, rf->channel);
-+ rt2800_iq_calibrate(rt2x00dev, rf->channel);
- }
-
- if (rt2x00_rt(rt2x00dev, RT6352)) {
-+ /* BBP for GLRT BW */
-+ bbp = conf_is_ht40(conf) ?
-+ 0x10 : rt2x00_has_cap_external_lna_bg(rt2x00dev) ?
-+ 0x15 : 0x1a;
-+ rt2800_bbp_glrt_write(rt2x00dev, 141, bbp);
-+
-+ bbp = conf_is_ht40(conf) ? 0x2f : 0x40;
-+ rt2800_bbp_glrt_write(rt2x00dev, 157, bbp);
-+
-+ if (rt2x00dev->default_ant.rx_chain_num == 1) {
-+ rt2800_bbp_write(rt2x00dev, 91, 0x07);
-+ rt2800_bbp_write(rt2x00dev, 95, 0x1a);
-+ rt2800_bbp_glrt_write(rt2x00dev, 128, 0xa0);
-+ rt2800_bbp_glrt_write(rt2x00dev, 170, 0x12);
-+ rt2800_bbp_glrt_write(rt2x00dev, 171, 0x10);
-+ } else {
-+ rt2800_bbp_write(rt2x00dev, 91, 0x06);
-+ rt2800_bbp_write(rt2x00dev, 95, 0x9a);
-+ rt2800_bbp_glrt_write(rt2x00dev, 128, 0xe0);
-+ rt2800_bbp_glrt_write(rt2x00dev, 170, 0x30);
-+ rt2800_bbp_glrt_write(rt2x00dev, 171, 0x30);
-+ }
-+
-+ /* AGC init */
-+ bbp = rf->channel <= 14 ? 0x04 + 2 * rt2x00dev->lna_gain : 0;
-+ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, bbp);
-+
-+ usleep_range(1000, 1500);
-+
- if (test_bit(CAPABILITY_EXTERNAL_PA_TX0,
- &rt2x00dev->cap_flags)) {
- reg = rt2800_register_read(rt2x00dev, RF_CONTROL3);
-@@ -5608,26 +5614,6 @@ void rt2800_vco_calibration(struct rt2x0
- rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
-
- if (rt2x00_rt(rt2x00dev, RT6352)) {
-- if (rt2x00dev->default_ant.rx_chain_num == 1) {
-- rt2800_bbp_write(rt2x00dev, 91, 0x07);
-- rt2800_bbp_write(rt2x00dev, 95, 0x1A);
-- rt2800_bbp_write(rt2x00dev, 195, 128);
-- rt2800_bbp_write(rt2x00dev, 196, 0xA0);
-- rt2800_bbp_write(rt2x00dev, 195, 170);
-- rt2800_bbp_write(rt2x00dev, 196, 0x12);
-- rt2800_bbp_write(rt2x00dev, 195, 171);
-- rt2800_bbp_write(rt2x00dev, 196, 0x10);
-- } else {
-- rt2800_bbp_write(rt2x00dev, 91, 0x06);
-- rt2800_bbp_write(rt2x00dev, 95, 0x9A);
-- rt2800_bbp_write(rt2x00dev, 195, 128);
-- rt2800_bbp_write(rt2x00dev, 196, 0xE0);
-- rt2800_bbp_write(rt2x00dev, 195, 170);
-- rt2800_bbp_write(rt2x00dev, 196, 0x30);
-- rt2800_bbp_write(rt2x00dev, 195, 171);
-- rt2800_bbp_write(rt2x00dev, 196, 0x30);
-- }
--
- if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
- rt2800_bbp_write(rt2x00dev, 75, 0x68);
- rt2800_bbp_write(rt2x00dev, 76, 0x4C);
-@@ -5635,13 +5621,6 @@ void rt2800_vco_calibration(struct rt2x0
- rt2800_bbp_write(rt2x00dev, 80, 0x0C);
- rt2800_bbp_write(rt2x00dev, 82, 0xB6);
- }
--
-- /* On 11A, We should delay and wait RF/BBP to be stable
-- * and the appropriate time should be 1000 micro seconds
-- * 2005/06/05 - On 11G, we also need this delay time.
-- * Otherwise it's difficult to pass the WHQL.
-- */
-- usleep_range(1000, 1500);
- }
- }
- EXPORT_SYMBOL_GPL(rt2800_vco_calibration);
+++ /dev/null
-From cca74bed37af1c8217bcd8282d9b384efdbf73bd Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Thu, 19 Oct 2023 19:58:58 +0800
-Subject: wifi: rt2x00: rework MT7620 PA/LNA RF calibration
-
-1. Move MT7620 PA/LNA calibration code to dedicated functions.
-2. For external PA/LNA devices, restore RF and BBP registers before
- R-Calibration.
-3. Do Rx DCOC calibration again before RXIQ calibration.
-4. Add some missing LNA related registers' initialization.
-
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://lore.kernel.org/r/TYAP286MB0315979F92DC563019B8F238BCD4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 176 +++++++++++++++++--------
- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 6 +
- 2 files changed, 130 insertions(+), 52 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -4468,41 +4468,6 @@ static void rt2800_config_channel(struct
- rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, bbp);
-
- usleep_range(1000, 1500);
--
-- if (test_bit(CAPABILITY_EXTERNAL_PA_TX0,
-- &rt2x00dev->cap_flags)) {
-- reg = rt2800_register_read(rt2x00dev, RF_CONTROL3);
-- reg |= 0x00000101;
-- rt2800_register_write(rt2x00dev, RF_CONTROL3, reg);
--
-- reg = rt2800_register_read(rt2x00dev, RF_BYPASS3);
-- reg |= 0x00000101;
-- rt2800_register_write(rt2x00dev, RF_BYPASS3, reg);
--
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0x73);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0x73);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0x73);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0xC8);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xA4);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x05);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0xC8);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xA4);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x05);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x27);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0xC8);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xA4);
-- rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x05);
-- rt2800_rfcsr_write_dccal(rt2x00dev, 05, 0x00);
--
-- rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT,
-- 0x36303636);
-- rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN,
-- 0x6C6C6B6C);
-- rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN,
-- 0x6C6C6B6C);
-- }
- }
-
- bbp = rt2800_bbp_read(rt2x00dev, 4);
-@@ -5612,16 +5577,6 @@ void rt2800_vco_calibration(struct rt2x0
- }
- }
- rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
--
-- if (rt2x00_rt(rt2x00dev, RT6352)) {
-- if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
-- rt2800_bbp_write(rt2x00dev, 75, 0x68);
-- rt2800_bbp_write(rt2x00dev, 76, 0x4C);
-- rt2800_bbp_write(rt2x00dev, 79, 0x1C);
-- rt2800_bbp_write(rt2x00dev, 80, 0x0C);
-- rt2800_bbp_write(rt2x00dev, 82, 0xB6);
-- }
-- }
- }
- EXPORT_SYMBOL_GPL(rt2800_vco_calibration);
-
-@@ -10348,6 +10303,128 @@ do_cal:
- rt2800_register_write(rt2x00dev, RF_BYPASS0, MAC_RF_BYPASS0);
- }
-
-+static void rt2800_restore_rf_bbp_rt6352(struct rt2x00_dev *rt2x00dev)
-+{
-+ if (rt2x00_has_cap_external_pa(rt2x00dev)) {
-+ rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x0);
-+ rt2800_register_write(rt2x00dev, RF_BYPASS3, 0x0);
-+ }
-+
-+ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x02);
-+ }
-+
-+ if (rt2x00_has_cap_external_pa(rt2x00dev)) {
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xd3);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xb3);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xd5);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6c);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xfc);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1f);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xff);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1c);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6b);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xf7);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09);
-+ }
-+
-+ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
-+ rt2800_bbp_write(rt2x00dev, 75, 0x60);
-+ rt2800_bbp_write(rt2x00dev, 76, 0x44);
-+ rt2800_bbp_write(rt2x00dev, 79, 0x1c);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x0c);
-+ rt2800_bbp_write(rt2x00dev, 82, 0xB6);
-+ }
-+
-+ if (rt2x00_has_cap_external_pa(rt2x00dev)) {
-+ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT, 0x3630363a);
-+ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, 0x6c6c666c);
-+ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, 0x6c6c666c);
-+ }
-+}
-+
-+static void rt2800_calibration_rt6352(struct rt2x00_dev *rt2x00dev)
-+{
-+ u32 reg;
-+
-+ if (rt2x00_has_cap_external_pa(rt2x00dev) ||
-+ rt2x00_has_cap_external_lna_bg(rt2x00dev))
-+ rt2800_restore_rf_bbp_rt6352(rt2x00dev);
-+
-+ rt2800_r_calibration(rt2x00dev);
-+ rt2800_rf_self_txdc_cal(rt2x00dev);
-+ rt2800_rxdcoc_calibration(rt2x00dev);
-+ rt2800_bw_filter_calibration(rt2x00dev, true);
-+ rt2800_bw_filter_calibration(rt2x00dev, false);
-+ rt2800_loft_iq_calibration(rt2x00dev);
-+
-+ /* missing DPD calibration for internal PA devices */
-+
-+ rt2800_rxdcoc_calibration(rt2x00dev);
-+ rt2800_rxiq_calibration(rt2x00dev);
-+
-+ if (!rt2x00_has_cap_external_pa(rt2x00dev) &&
-+ !rt2x00_has_cap_external_lna_bg(rt2x00dev))
-+ return;
-+
-+ if (rt2x00_has_cap_external_pa(rt2x00dev)) {
-+ reg = rt2800_register_read(rt2x00dev, RF_CONTROL3);
-+ reg |= 0x00000101;
-+ rt2800_register_write(rt2x00dev, RF_CONTROL3, reg);
-+
-+ reg = rt2800_register_read(rt2x00dev, RF_BYPASS3);
-+ reg |= 0x00000101;
-+ rt2800_register_write(rt2x00dev, RF_BYPASS3, reg);
-+ }
-+
-+ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x42);
-+ }
-+
-+ if (rt2x00_has_cap_external_pa(rt2x00dev)) {
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0x73);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0x73);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0x73);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0xc8);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xa4);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x05);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0xc8);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xa4);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x05);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x27);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0xc8);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xa4);
-+ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x05);
-+ }
-+
-+ if (rt2x00_has_cap_external_pa(rt2x00dev))
-+ rt2800_rfcsr_write_dccal(rt2x00dev, 05, 0x00);
-+
-+ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
-+ rt2800_bbp_write(rt2x00dev, 75, 0x68);
-+ rt2800_bbp_write(rt2x00dev, 76, 0x4c);
-+ rt2800_bbp_write(rt2x00dev, 79, 0x1c);
-+ rt2800_bbp_write(rt2x00dev, 80, 0x0c);
-+ rt2800_bbp_write(rt2x00dev, 82, 0xb6);
-+ }
-+
-+ if (rt2x00_has_cap_external_pa(rt2x00dev)) {
-+ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT, 0x36303636);
-+ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, 0x6c6c6b6c);
-+ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, 0x6c6c6b6c);
-+ }
-+}
-+
- static void rt2800_init_rfcsr_6352(struct rt2x00_dev *rt2x00dev)
- {
- /* Initialize RF central register to default value */
-@@ -10612,13 +10689,8 @@ static void rt2800_init_rfcsr_6352(struc
- rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
- rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
-
-- rt2800_r_calibration(rt2x00dev);
-- rt2800_rf_self_txdc_cal(rt2x00dev);
-- rt2800_rxdcoc_calibration(rt2x00dev);
-- rt2800_bw_filter_calibration(rt2x00dev, true);
-- rt2800_bw_filter_calibration(rt2x00dev, false);
-- rt2800_loft_iq_calibration(rt2x00dev);
-- rt2800_rxiq_calibration(rt2x00dev);
-+ /* Do calibration and init PA/LNA */
-+ rt2800_calibration_rt6352(rt2x00dev);
- }
-
- static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -1263,6 +1263,12 @@ rt2x00_has_cap_external_lna_bg(struct rt
- }
-
- static inline bool
-+rt2x00_has_cap_external_pa(struct rt2x00_dev *rt2x00dev)
-+{
-+ return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_EXTERNAL_PA_TX0);
-+}
-+
-+static inline bool
- rt2x00_has_cap_double_antenna(struct rt2x00_dev *rt2x00dev)
- {
- return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_DOUBLE_ANTENNA);
+++ /dev/null
-From b1275cdd7456ef811747dfb4f3c46310ddd300cd Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Sat, 4 Nov 2023 16:57:58 +0800
-Subject: wifi: rt2x00: introduce DMA busy check watchdog for rt2800
-
-When I tried to fix the watchdog of rt2800, I found that sometimes
-the watchdog can not reset the hung device. This is because the
-queue is not completely stuck, it just becomes very slow. The MTK
-vendor driver for the new chip MT7603/MT7612 has a DMA busy watchdog
-to detect device hangs by checking DMA busy status. This watchdog
-implementation is something similar to it. To reduce unnecessary
-reset, we can check the INT_SOURCE_CSR register together as I found
-that when the radio hung, the RX/TX coherent interrupt will always
-stuck at triggered state.
-
-The 'watchdog' module parameter has been extended to control all
-watchdogs(0=disabled, 1=hang watchdog, 2=DMA watchdog, 3=both). This
-new watchdog function is a slight schedule and it won't affect the
-transmission speed. So we can turn on it by default. Due to the
-INT_SOURCE_CSR register is invalid on rt2800 USB NICs, the DMA busy
-watchdog will be automatically disabled for them.
-
-Tested on MT7620 and RT5350.
-
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://lore.kernel.org/r/TYAP286MB0315D7462CE08A119A99DE34BCA4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/ralink/rt2x00/rt2800.h | 4 ++
- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 77 ++++++++++++++++++++++----
- drivers/net/wireless/ralink/rt2x00/rt2x00.h | 3 +
- 3 files changed, 73 insertions(+), 11 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
-@@ -3194,4 +3194,8 @@ enum rt2800_eeprom_word {
- */
- #define BCN_TBTT_OFFSET 64
-
-+/* Watchdog type mask */
-+#define RT2800_WATCHDOG_HANG BIT(0)
-+#define RT2800_WATCHDOG_DMA_BUSY BIT(1)
-+
- #endif /* RT2800_H */
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -30,9 +30,10 @@
- #include "rt2800lib.h"
- #include "rt2800.h"
-
--static bool modparam_watchdog;
--module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO);
--MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected");
-+static unsigned int modparam_watchdog = RT2800_WATCHDOG_DMA_BUSY;
-+module_param_named(watchdog, modparam_watchdog, uint, 0444);
-+MODULE_PARM_DESC(watchdog, "Enable watchdog to recover tx/rx hangs.\n"
-+ "\t\t(0=disabled, 1=hang watchdog, 2=DMA watchdog(default), 3=both)");
-
- /*
- * Register access.
-@@ -1261,15 +1262,12 @@ static void rt2800_update_survey(struct
- chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
- }
-
--void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
-+static bool rt2800_watchdog_hung(struct rt2x00_dev *rt2x00dev)
- {
- struct data_queue *queue;
- bool hung_tx = false;
- bool hung_rx = false;
-
-- if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
-- return;
--
- rt2800_update_survey(rt2x00dev);
-
- queue_for_each(rt2x00dev, queue) {
-@@ -1297,18 +1295,72 @@ void rt2800_watchdog(struct rt2x00_dev *
- }
- }
-
-+ if (!hung_tx && !hung_rx)
-+ return false;
-+
- if (hung_tx)
- rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n");
-
- if (hung_rx)
- rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
-
-- if (hung_tx || hung_rx) {
-- queue_for_each(rt2x00dev, queue)
-- queue->wd_count = 0;
-+ queue_for_each(rt2x00dev, queue)
-+ queue->wd_count = 0;
-+
-+ return true;
-+}
-+
-+static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev)
-+{
-+ bool busy_rx, busy_tx;
-+ u32 reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG);
-+ u32 reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR);
-+
-+ if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) &&
-+ rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT))
-+ rt2x00dev->rxdma_busy++;
-+ else
-+ rt2x00dev->rxdma_busy = 0;
-
-+ if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
-+ rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT))
-+ rt2x00dev->txdma_busy++;
-+ else
-+ rt2x00dev->txdma_busy = 0;
-+
-+ busy_rx = rt2x00dev->rxdma_busy > 30 ? true : false;
-+ busy_tx = rt2x00dev->txdma_busy > 30 ? true : false;
-+
-+ if (!busy_rx && !busy_tx)
-+ return false;
-+
-+ if (busy_rx)
-+ rt2x00_warn(rt2x00dev, "Watchdog RX DMA busy detected\n");
-+
-+ if (busy_tx)
-+ rt2x00_warn(rt2x00dev, "Watchdog TX DMA busy detected\n");
-+
-+ rt2x00dev->rxdma_busy = 0;
-+ rt2x00dev->txdma_busy = 0;
-+
-+ return true;
-+}
-+
-+void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
-+{
-+ bool reset = false;
-+
-+ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
-+ return;
-+
-+ if (modparam_watchdog & RT2800_WATCHDOG_DMA_BUSY)
-+ reset = rt2800_watchdog_dma_busy(rt2x00dev);
-+
-+ if (modparam_watchdog & RT2800_WATCHDOG_HANG)
-+ reset = rt2800_watchdog_hung(rt2x00dev) || reset;
-+
-+ if (reset)
- ieee80211_restart_hw(rt2x00dev->hw);
-- }
- }
- EXPORT_SYMBOL_GPL(rt2800_watchdog);
-
-@@ -12016,6 +12068,9 @@ int rt2800_probe_hw(struct rt2x00_dev *r
- __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
- }
-
-+ /* USB NICs don't support DMA watchdog as INT_SOURCE_CSR is invalid */
-+ if (rt2x00_is_usb(rt2x00dev))
-+ modparam_watchdog &= ~RT2800_WATCHDOG_DMA_BUSY;
- if (modparam_watchdog) {
- __set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
- rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
-@@ -926,6 +926,9 @@ struct rt2x00_dev {
- */
- u16 beacon_int;
-
-+ /* Rx/Tx DMA busy watchdog counter */
-+ u16 rxdma_busy, txdma_busy;
-+
- /**
- * Timestamp of last received beacon
- */
+++ /dev/null
-From 570beb6285fd355904b22625da20809f477096c5 Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Sat, 4 Nov 2023 16:57:59 +0800
-Subject: wifi: rt2x00: disable RTS threshold for rt2800 by default
-
-rt2800 has a lot of registers to control the RTS enable/disable
-status for different rates. And the driver control them via
-rt2800_set_rts_threshold(). When RTS was disabled in user
-interface, this function won't be called at all. This means that
-the RTS is still 'on' for CCK and OFDM rates. So we'd better to
-disable them by default because it should be like this. The RTS
-for HT20 and HT40 is already default off so we don't need to
-touch them. If we toggle the RTS status, these register bits
-will be enable/disable again by rt2800_set_rts_threshold().
-
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://lore.kernel.org/r/TYAP286MB03155DDB953155B7A2DE849ABCA4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -6100,7 +6100,7 @@ static int rt2800_init_registers(struct
- rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0);
- rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
- rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0);
-- rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 1);
-+ rt2x00_set_field32(®, CCK_PROT_CFG_RTS_TH_EN, 0);
- rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg);
-
- reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG);
-@@ -6113,7 +6113,7 @@ static int rt2800_init_registers(struct
- rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0);
- rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
- rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0);
-- rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 1);
-+ rt2x00_set_field32(®, OFDM_PROT_CFG_RTS_TH_EN, 0);
- rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
-
- reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG);
+++ /dev/null
-From a11d965a218f0cd95b13fe44d0bcd8a20ce134a8 Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Sat, 4 Nov 2023 16:58:00 +0800
-Subject: wifi: rt2x00: restart beacon queue when hardware reset
-
-When a hardware reset is triggered, all registers are reset, so all
-queues are forced to stop in hardware interface. However, mac80211
-will not automatically stop the queue. If we don't manually stop the
-beacon queue, the queue will be deadlocked and unable to start again.
-This patch fixes the issue where Apple devices cannot connect to the
-AP after calling ieee80211_restart_hw().
-
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://lore.kernel.org/r/TYAP286MB031530EB6D98DCE4DF20766CBCA4A@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 3 +++
- drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 11 +++++++++++
- 2 files changed, 14 insertions(+)
-
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
-@@ -101,6 +101,7 @@ void rt2x00lib_disable_radio(struct rt2x
- rt2x00link_stop_tuner(rt2x00dev);
- rt2x00queue_stop_queues(rt2x00dev);
- rt2x00queue_flush_queues(rt2x00dev, true);
-+ rt2x00queue_stop_queue(rt2x00dev->bcn);
-
- /*
- * Disable radio.
-@@ -1286,6 +1287,7 @@ int rt2x00lib_start(struct rt2x00_dev *r
- rt2x00dev->intf_ap_count = 0;
- rt2x00dev->intf_sta_count = 0;
- rt2x00dev->intf_associated = 0;
-+ rt2x00dev->intf_beaconing = 0;
-
- /* Enable the radio */
- retval = rt2x00lib_enable_radio(rt2x00dev);
-@@ -1312,6 +1314,7 @@ void rt2x00lib_stop(struct rt2x00_dev *r
- rt2x00dev->intf_ap_count = 0;
- rt2x00dev->intf_sta_count = 0;
- rt2x00dev->intf_associated = 0;
-+ rt2x00dev->intf_beaconing = 0;
- }
-
- static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)
---- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
-@@ -598,6 +598,17 @@ void rt2x00mac_bss_info_changed(struct i
- */
- if (changes & BSS_CHANGED_BEACON_ENABLED) {
- mutex_lock(&intf->beacon_skb_mutex);
-+
-+ /*
-+ * Clear the 'enable_beacon' flag and clear beacon because
-+ * the beacon queue has been stopped after hardware reset.
-+ */
-+ if (test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags) &&
-+ intf->enable_beacon) {
-+ intf->enable_beacon = false;
-+ rt2x00queue_clear_beacon(rt2x00dev, vif);
-+ }
-+
- if (!bss_conf->enable_beacon && intf->enable_beacon) {
- rt2x00dev->intf_beaconing--;
- intf->enable_beacon = false;
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-@@ -8711,7 +8711,7 @@ static void rt2800_rxdcoc_calibration(st
- rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4);
- rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, saverfb7r4);
+@@ -8692,7 +8692,7 @@ static void rt2800_rxdcoc_calibration(st
+ rfvalue |= 0x03;
+ rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, rfvalue);
- rt2800_bbp_write(rt2x00dev, 158, 141);
+ rt2800_bbp_write(rt2x00dev, 158, 140);
bbpreg = rt2800_bbp_read(rt2x00dev, 159);
- bbpreg = bbpreg & (~0x40);
+ bbpreg |= 0x10;
rt2800_bbp_write(rt2x00dev, 159, bbpreg);
--- a/local-symbols
+++ b/local-symbols
-@@ -352,6 +352,7 @@ RT2X00_LIB_FIRMWARE=
+@@ -334,6 +334,7 @@ RT2X00_LIB_FIRMWARE=
RT2X00_LIB_CRYPTO=
RT2X00_LIB_LEDS=
RT2X00_LIB_DEBUGFS=
/* Firmware functions */
static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
-@@ -168,7 +155,7 @@ static const struct rt2800_ops rt2800soc
+@@ -172,7 +159,7 @@ static const struct rt2800_ops rt2800soc
.register_multiread = rt2x00mmio_register_multiread,
.register_multiwrite = rt2x00mmio_register_multiwrite,
.regbusy_read = rt2x00mmio_regbusy_read,
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
-@@ -226,10 +226,17 @@ static int rt2800soc_probe(struct platfo
+@@ -230,10 +230,17 @@ static int rt2800soc_probe(struct platfo
return rt2x00soc_probe(pdev, &rt2800soc_ops);
}
#include "rt2x00.h"
#include "rt2800lib.h"
-@@ -11285,6 +11286,17 @@ static int rt2800_init_eeprom(struct rt2
+@@ -11282,6 +11283,17 @@ static int rt2800_init_eeprom(struct rt2
rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = {
[EEPROM_CHIP_ID] = 0x0000,
[EEPROM_VERSION] = 0x0001,
-@@ -10407,8 +10425,10 @@ static void rt2800_calibration_rt6352(st
+@@ -10404,8 +10422,10 @@ static void rt2800_calibration_rt6352(st
u32 reg;
if (rt2x00_has_cap_external_pa(rt2x00dev) ||
rt2800_r_calibration(rt2x00dev);
rt2800_rf_self_txdc_cal(rt2x00dev);
-@@ -10426,6 +10446,8 @@ static void rt2800_calibration_rt6352(st
+@@ -10423,6 +10443,8 @@ static void rt2800_calibration_rt6352(st
!rt2x00_has_cap_external_lna_bg(rt2x00dev))
return;
+static int rt2800pci_get_chipeco(void) { return 0; }
+
static const struct ieee80211_ops rt2800pci_mac80211_ops = {
- .tx = rt2x00mac_tx,
- .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-@@ -329,6 +333,9 @@ static const struct rt2800_ops rt2800pci
+ .add_chanctx = ieee80211_emulate_add_chanctx,
+ .remove_chanctx = ieee80211_emulate_remove_chanctx,
+@@ -333,6 +337,9 @@ static const struct rt2800_ops rt2800pci
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
.drv_get_dma_done = rt2800mmio_get_dma_done,
+#endif
+
static const struct ieee80211_ops rt2800soc_mac80211_ops = {
- .tx = rt2x00mac_tx,
- .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-@@ -161,6 +188,9 @@ static const struct rt2800_ops rt2800soc
+ .add_chanctx = ieee80211_emulate_add_chanctx,
+ .remove_chanctx = ieee80211_emulate_remove_chanctx,
+@@ -165,6 +192,9 @@ static const struct rt2800_ops rt2800soc
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
.drv_get_dma_done = rt2800mmio_get_dma_done,
+static int rt2800usb_get_chipeco(void) { return 0; }
+
static const struct ieee80211_ops rt2800usb_mac80211_ops = {
- .tx = rt2x00mac_tx,
- .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-@@ -672,6 +676,9 @@ static const struct rt2800_ops rt2800usb
+ .add_chanctx = ieee80211_emulate_add_chanctx,
+ .remove_chanctx = ieee80211_emulate_remove_chanctx,
+@@ -676,6 +680,9 @@ static const struct rt2800_ops rt2800usb
.drv_init_registers = rt2800usb_init_registers,
.drv_get_txwi = rt2800usb_get_txwi,
.drv_get_dma_done = rt2800usb_get_dma_done,
/* BBP for G band GLRT function (BBP_128 ~ BBP_221) */
rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00);
-@@ -10381,6 +10410,9 @@ static void rt2800_restore_rf_bbp_rt6352
+@@ -10378,6 +10407,9 @@ static void rt2800_restore_rf_bbp_rt6352
rt2800_register_write(rt2x00dev, RF_BYPASS3, 0x0);
}
if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16);
rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23);
-@@ -10458,6 +10490,9 @@ static void rt2800_calibration_rt6352(st
+@@ -10455,6 +10487,9 @@ static void rt2800_calibration_rt6352(st
rt2800_register_write(rt2x00dev, RF_BYPASS3, reg);
}
if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66);
rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20);
-@@ -10548,31 +10583,36 @@ static void rt2800_init_rfcsr_6352(struc
+@@ -10545,31 +10580,36 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write(rt2x00dev, 42, 0x5B);
rt2800_rfcsr_write(rt2x00dev, 43, 0x00);
/* Initialize RF channel register to default value */
rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03);
-@@ -10638,63 +10678,71 @@ static void rt2800_init_rfcsr_6352(struc
+@@ -10635,63 +10675,71 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5);
/* Initialize RF DC calibration register to default value */
rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47);
-@@ -10757,12 +10805,17 @@ static void rt2800_init_rfcsr_6352(struc
+@@ -10754,12 +10802,17 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00);
rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00);
+++ /dev/null
-From d55cb6d8a99441aff55cb9ce663a07f7f1667e83 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:22 +0100
-Subject: [PATCH 01/21] wifi: rtl8xxxu: remove assignment of priv->vif in
- rtl8xxxu_bss_info_changed()
-
-priv->vif gets already set in rtl8xxxu_add_interface, there is no need
-to set it also in rtl8xxxu_bss_info_changed().
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-2-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 1 -
- 1 file changed, 1 deletion(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -5004,7 +5004,6 @@ rtl8xxxu_bss_info_changed(struct ieee802
-
- rtl8xxxu_update_ra_report(rarpt, highest_rate, sgi, bw);
-
-- priv->vif = vif;
- priv->rssi_level = RTL8XXXU_RATR_STA_INIT;
-
- priv->fops->update_rate_mask(priv, ramask, 0, sgi,
+++ /dev/null
-From 2bbd7d584046038ce655e476628bb15e1460fac6 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:23 +0100
-Subject: [PATCH 02/21] wifi: rtl8xxxu: prepare supporting two virtual
- interfaces
-
-To prepare for concurrent mode, add an array ("vifs") to rtl8xxxu_priv
-to keep track of both interfaces.
-
-Keep the old priv->vif as long there are still users of it and let
-priv->vifs[0] point to the same location.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-3-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 2 ++
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 10 +++++++---
- 2 files changed, 9 insertions(+), 3 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-@@ -1897,6 +1897,8 @@ struct rtl8xxxu_priv {
- * is supported and no iface_combinations are provided.
- */
- struct ieee80211_vif *vif;
-+
-+ struct ieee80211_vif *vifs[2];
- struct delayed_work ra_watchdog;
- struct work_struct c2hcmd_work;
- struct sk_buff_head c2hcmd_queue;
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -6569,10 +6569,12 @@ static int rtl8xxxu_add_interface(struct
- int ret;
- u8 val8;
-
-- if (!priv->vif)
-+ if (!priv->vif) {
- priv->vif = vif;
-- else
-+ priv->vifs[0] = vif;
-+ } else {
- return -EOPNOTSUPP;
-+ }
-
- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
-@@ -6622,8 +6624,10 @@ static void rtl8xxxu_remove_interface(st
-
- dev_dbg(&priv->udev->dev, "%s\n", __func__);
-
-- if (priv->vif)
-+ if (priv->vif) {
- priv->vif = NULL;
-+ priv->vifs[0] = NULL;
-+ }
- }
-
- static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed)
+++ /dev/null
-From 7f444692cde83c1455682c2d0d2c9a666422b867 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:24 +0100
-Subject: [PATCH 03/21] wifi: rtl8xxxu: support setting linktype for both
- interfaces
-
-To prepare for concurrent mode, enhance the set_linktype function to be
-able to set the linktype in the MSR register for both hardware ports.
-
-Until the users of set_linktype can handle multiple interfaces, use
-port_num = 0.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-4-martin.kaistra@linutronix.de
----
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 37 +++++++++++--------
- 1 file changed, 22 insertions(+), 15 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -1633,33 +1633,41 @@ rtl8xxxu_gen1_set_tx_power(struct rtl8xx
- }
-
- static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv,
-- enum nl80211_iftype linktype)
-+ enum nl80211_iftype linktype, int port_num)
- {
-- u8 val8;
--
-- val8 = rtl8xxxu_read8(priv, REG_MSR);
-- val8 &= ~MSR_LINKTYPE_MASK;
-+ u8 val8, type;
-
- switch (linktype) {
- case NL80211_IFTYPE_UNSPECIFIED:
-- val8 |= MSR_LINKTYPE_NONE;
-+ type = MSR_LINKTYPE_NONE;
- break;
- case NL80211_IFTYPE_ADHOC:
-- val8 |= MSR_LINKTYPE_ADHOC;
-+ type = MSR_LINKTYPE_ADHOC;
- break;
- case NL80211_IFTYPE_STATION:
-- val8 |= MSR_LINKTYPE_STATION;
-+ type = MSR_LINKTYPE_STATION;
- break;
- case NL80211_IFTYPE_AP:
-- val8 |= MSR_LINKTYPE_AP;
-+ type = MSR_LINKTYPE_AP;
- break;
- default:
-- goto out;
-+ return;
-+ }
-+
-+ switch (port_num) {
-+ case 0:
-+ val8 = rtl8xxxu_read8(priv, REG_MSR) & 0x0c;
-+ val8 |= type;
-+ break;
-+ case 1:
-+ val8 = rtl8xxxu_read8(priv, REG_MSR) & 0x03;
-+ val8 |= type << 2;
-+ break;
-+ default:
-+ return;
- }
-
- rtl8xxxu_write8(priv, REG_MSR, val8);
--out:
-- return;
- }
-
- static void
-@@ -4236,7 +4244,6 @@ static int rtl8xxxu_init_device(struct i
- }
-
- rtl8xxxu_set_mac(priv);
-- rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION);
-
- /*
- * Configure initial WMAC settings
-@@ -4964,7 +4971,7 @@ rtl8xxxu_bss_info_changed(struct ieee802
- if (changed & BSS_CHANGED_ASSOC) {
- dev_dbg(dev, "Changed ASSOC: %i!\n", vif->cfg.assoc);
-
-- rtl8xxxu_set_linktype(priv, vif->type);
-+ rtl8xxxu_set_linktype(priv, vif->type, 0);
-
- if (vif->cfg.assoc) {
- u32 ramask;
-@@ -6610,7 +6617,7 @@ static int rtl8xxxu_add_interface(struct
- ret = -EOPNOTSUPP;
- }
-
-- rtl8xxxu_set_linktype(priv, vif->type);
-+ rtl8xxxu_set_linktype(priv, vif->type, 0);
- ether_addr_copy(priv->mac_addr, vif->addr);
- rtl8xxxu_set_mac(priv);
-
+++ /dev/null
-From a047e46a7b98de384a158b25a05dc09aa7d70c5f Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:25 +0100
-Subject: [PATCH 04/21] wifi: rtl8xxxu: 8188e: convert usage of priv->vif to
- priv->vifs[0]
-
-The driver currently does not support AP or concurrent mode for 8188e,
-so just use priv->vifs[0] instead of priv->vif for now.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-5-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c
-@@ -1699,7 +1699,7 @@ void rtl8188e_handle_ra_tx_report2(struc
- /* We only use macid 0, so only the first item is relevant.
- * AP mode will use more of them if it's ever implemented.
- */
-- if (!priv->vif || priv->vif->type == NL80211_IFTYPE_STATION)
-+ if (!priv->vifs[0] || priv->vifs[0]->type == NL80211_IFTYPE_STATION)
- items = 1;
-
- for (macid = 0; macid < items; macid++) {
+++ /dev/null
-From 00add60cad3c9690ac0f9d4f6685f96ccd607670 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:26 +0100
-Subject: [PATCH 05/21] wifi: rtl8xxxu: support setting mac address register
- for both interfaces
-
-To prepare for concurrent mode, enhance rtl8xxxu_set_mac() to write the
-mac address of the respective interface to REG_MACID or REG_MACID1.
-
-Remove the call to rtl8xxxu_set_mac() from the init function as we set
-it in rtl8xxxu_add_interface() later anyway.
-
-Until rtl8xxxu_add_interface() can handle both interfaces, call
-rtl8xxxu_set_mac() with port_num = 0.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-6-martin.kaistra@linutronix.de
----
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 20 +++++++++++++------
- 1 file changed, 14 insertions(+), 6 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -3580,15 +3580,25 @@ void rtl8723a_phy_lc_calibrate(struct rt
- rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
- }
-
--static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv)
-+static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv, int port_num)
- {
- int i;
- u16 reg;
-
-- reg = REG_MACID;
-+ switch (port_num) {
-+ case 0:
-+ reg = REG_MACID;
-+ break;
-+ case 1:
-+ reg = REG_MACID1;
-+ break;
-+ default:
-+ WARN_ONCE("%s: invalid port_num\n", __func__);
-+ return -EINVAL;
-+ }
-
- for (i = 0; i < ETH_ALEN; i++)
-- rtl8xxxu_write8(priv, reg + i, priv->mac_addr[i]);
-+ rtl8xxxu_write8(priv, reg + i, priv->vifs[port_num]->addr[i]);
-
- return 0;
- }
-@@ -4243,8 +4253,6 @@ static int rtl8xxxu_init_device(struct i
- rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff);
- }
-
-- rtl8xxxu_set_mac(priv);
--
- /*
- * Configure initial WMAC settings
- */
-@@ -6619,7 +6627,7 @@ static int rtl8xxxu_add_interface(struct
-
- rtl8xxxu_set_linktype(priv, vif->type, 0);
- ether_addr_copy(priv->mac_addr, vif->addr);
-- rtl8xxxu_set_mac(priv);
-+ rtl8xxxu_set_mac(priv, 0);
-
- return ret;
- }
+++ /dev/null
-From 9aa776209ca31695bead52674ad943848ccc97d5 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:27 +0100
-Subject: [PATCH 06/21] wifi: rtl8xxxu: extend wifi connected check to both
- interfaces
-
-There are multiple places in the code where the current connection
-status of wifi is checked. The driver will support two interfaces soon
-and either one of them (or both) could be connected.
-
-Convert all uses of (vif && vif->cfg.assoc) to a new helper
-function rtl8xxxu_is_assoc() which checks both interfaces.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-7-martin.kaistra@linutronix.de
----
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 20 +++++++++----------
- 1 file changed, 9 insertions(+), 11 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -6043,18 +6043,20 @@ void rtl8723bu_update_bt_link_info(struc
- btcoex->bt_busy = false;
- }
-
-+static inline bool rtl8xxxu_is_assoc(struct rtl8xxxu_priv *priv)
-+{
-+ return (priv->vifs[0] && priv->vifs[0]->cfg.assoc) ||
-+ (priv->vifs[1] && priv->vifs[1]->cfg.assoc);
-+}
-+
- static
- void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv)
- {
-- struct ieee80211_vif *vif;
- struct rtl8xxxu_btcoex *btcoex;
-- bool wifi_connected;
-
-- vif = priv->vif;
- btcoex = &priv->bt_coex;
-- wifi_connected = (vif && vif->cfg.assoc);
-
-- if (!wifi_connected) {
-+ if (!rtl8xxxu_is_assoc(priv)) {
- rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0);
- rtl8723bu_set_coex_with_type(priv, 0);
- } else if (btcoex->has_sco || btcoex->has_hid || btcoex->has_a2dp) {
-@@ -6072,15 +6074,11 @@ void rtl8723bu_handle_bt_inquiry(struct
- static
- void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv)
- {
-- struct ieee80211_vif *vif;
- struct rtl8xxxu_btcoex *btcoex;
-- bool wifi_connected;
-
-- vif = priv->vif;
- btcoex = &priv->bt_coex;
-- wifi_connected = (vif && vif->cfg.assoc);
-
-- if (wifi_connected) {
-+ if (rtl8xxxu_is_assoc(priv)) {
- u32 val32 = 0;
- u32 high_prio_tx = 0, high_prio_rx = 0;
-
-@@ -7103,7 +7101,7 @@ static void rtl8xxxu_track_cfo(struct rt
- int cfo_khz_a, cfo_khz_b, cfo_average;
- int crystal_cap;
-
-- if (!priv->vif || !priv->vif->cfg.assoc) {
-+ if (!rtl8xxxu_is_assoc(priv)) {
- /* Reset */
- cfo->adjust = true;
-
+++ /dev/null
-From 80fd8687db41b1e04f78c37137d090f2165cca6e Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:28 +0100
-Subject: [PATCH 07/21] wifi: rtl8xxxu: extend check for matching bssid to both
- interfaces
-
-The driver will support two interfaces soon, which both can be in
-station mode, so extend the check, whether cfo information should be
-parsed, to cover both interfaces.
-
-For better code readability put the lines with priv->vifs[port_num] in a
-separate function.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-8-martin.kaistra@linutronix.de
----
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 22 ++++++++++++-------
- 1 file changed, 14 insertions(+), 8 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -5706,6 +5706,16 @@ static void rtl8xxxu_update_beacon_work_
- rtl8xxxu_send_beacon_frame(hw, vif);
- }
-
-+static inline bool rtl8xxxu_is_packet_match_bssid(struct rtl8xxxu_priv *priv,
-+ struct ieee80211_hdr *hdr,
-+ int port_num)
-+{
-+ return priv->vifs[port_num] &&
-+ priv->vifs[port_num]->type == NL80211_IFTYPE_STATION &&
-+ priv->vifs[port_num]->cfg.assoc &&
-+ ether_addr_equal(priv->vifs[port_num]->bss_conf.bssid, hdr->addr2);
-+}
-+
- void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv,
- struct ieee80211_rx_status *rx_status,
- struct rtl8723au_phy_stats *phy_stats,
-@@ -5722,12 +5732,10 @@ void rtl8723au_rx_parse_phystats(struct
- rx_status->signal = priv->fops->cck_rssi(priv, phy_stats);
- } else {
- bool parse_cfo = priv->fops->set_crystal_cap &&
-- priv->vif &&
-- priv->vif->type == NL80211_IFTYPE_STATION &&
-- priv->vif->cfg.assoc &&
- !crc_icv_err &&
- !ieee80211_is_ctl(hdr->frame_control) &&
-- ether_addr_equal(priv->vif->bss_conf.bssid, hdr->addr2);
-+ (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) ||
-+ rtl8xxxu_is_packet_match_bssid(priv, hdr, 1));
-
- if (parse_cfo) {
- priv->cfo_tracking.cfo_tail[0] = phy_stats->path_cfotail[0];
-@@ -5762,12 +5770,10 @@ static void jaguar2_rx_parse_phystats_ty
- bool crc_icv_err)
- {
- bool parse_cfo = priv->fops->set_crystal_cap &&
-- priv->vif &&
-- priv->vif->type == NL80211_IFTYPE_STATION &&
-- priv->vif->cfg.assoc &&
- !crc_icv_err &&
- !ieee80211_is_ctl(hdr->frame_control) &&
-- ether_addr_equal(priv->vif->bss_conf.bssid, hdr->addr2);
-+ (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) ||
-+ rtl8xxxu_is_packet_match_bssid(priv, hdr, 1));
- u8 pwdb_max = 0;
- int rx_path;
-
+++ /dev/null
-From f86dd8eaf8da84ee5b803d90b8c311d7e2725d0b Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:29 +0100
-Subject: [PATCH 08/21] wifi: rtl8xxxu: don't parse CFO, if both interfaces are
- connected in STA mode
-
-If both interfaces are in STATION mode and both are connected to an AP,
-there might be conflicting CFO values for the two connections. Ignore
-the CFO information in this case.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-9-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -5716,6 +5716,14 @@ static inline bool rtl8xxxu_is_packet_ma
- ether_addr_equal(priv->vifs[port_num]->bss_conf.bssid, hdr->addr2);
- }
-
-+static inline bool rtl8xxxu_is_sta_sta(struct rtl8xxxu_priv *priv)
-+{
-+ return (priv->vifs[0] && priv->vifs[0]->cfg.assoc &&
-+ priv->vifs[0]->type == NL80211_IFTYPE_STATION) &&
-+ (priv->vifs[1] && priv->vifs[1]->cfg.assoc &&
-+ priv->vifs[1]->type == NL80211_IFTYPE_STATION);
-+}
-+
- void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv,
- struct ieee80211_rx_status *rx_status,
- struct rtl8723au_phy_stats *phy_stats,
-@@ -5734,6 +5742,7 @@ void rtl8723au_rx_parse_phystats(struct
- bool parse_cfo = priv->fops->set_crystal_cap &&
- !crc_icv_err &&
- !ieee80211_is_ctl(hdr->frame_control) &&
-+ !rtl8xxxu_is_sta_sta(priv) &&
- (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) ||
- rtl8xxxu_is_packet_match_bssid(priv, hdr, 1));
-
-@@ -5772,6 +5781,7 @@ static void jaguar2_rx_parse_phystats_ty
- bool parse_cfo = priv->fops->set_crystal_cap &&
- !crc_icv_err &&
- !ieee80211_is_ctl(hdr->frame_control) &&
-+ !rtl8xxxu_is_sta_sta(priv) &&
- (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) ||
- rtl8xxxu_is_packet_match_bssid(priv, hdr, 1));
- u8 pwdb_max = 0;
+++ /dev/null
-From 3ff7a05996f901a7a10068b42e9dc8435f908a4c Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:30 +0100
-Subject: [PATCH 09/21] wifi: rtl8xxxu: support setting bssid register for
- multiple interfaces
-
-To prepare for concurrent mode, enhance rtl8xxxu_set_bssid() to write the
-BSSID of the respective interface to REG_BSSID or REG_BSSID1.
-
-Like done with rtl8xxxu_set_mac(), call rtl8xxxu_set_bssid() with
-port_num = 0, until the callers also support multiple interfaces.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-10-martin.kaistra@linutronix.de
----
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 18 ++++++++++++++----
- 1 file changed, 14 insertions(+), 4 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -3603,14 +3603,24 @@ static int rtl8xxxu_set_mac(struct rtl8x
- return 0;
- }
-
--static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid)
-+static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid, int port_num)
- {
- int i;
- u16 reg;
-
- dev_dbg(&priv->udev->dev, "%s: (%pM)\n", __func__, bssid);
-
-- reg = REG_BSSID;
-+ switch (port_num) {
-+ case 0:
-+ reg = REG_BSSID;
-+ break;
-+ case 1:
-+ reg = REG_BSSID1;
-+ break;
-+ default:
-+ WARN_ONCE("%s: invalid port_num\n", __func__);
-+ return -EINVAL;
-+ }
-
- for (i = 0; i < ETH_ALEN; i++)
- rtl8xxxu_write8(priv, reg + i, bssid[i]);
-@@ -5068,7 +5078,7 @@ rtl8xxxu_bss_info_changed(struct ieee802
-
- if (changed & BSS_CHANGED_BSSID) {
- dev_dbg(dev, "Changed BSSID!\n");
-- rtl8xxxu_set_bssid(priv, bss_conf->bssid);
-+ rtl8xxxu_set_bssid(priv, bss_conf->bssid, 0);
- }
-
- if (changed & BSS_CHANGED_BASIC_RATES) {
-@@ -5097,7 +5107,7 @@ static int rtl8xxxu_start_ap(struct ieee
- struct device *dev = &priv->udev->dev;
-
- dev_dbg(dev, "Start AP mode\n");
-- rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid);
-+ rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid, 0);
- rtl8xxxu_write16(priv, REG_BCN_INTERVAL, vif->bss_conf.beacon_int);
- priv->fops->report_connect(priv, RTL8XXXU_BC_MC_MACID, 0, true);
-
+++ /dev/null
-From 43532c050f8eec4056a21978fdb5b958e1477553 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:31 +0100
-Subject: [PATCH 10/21] wifi: rtl8xxxu: support multiple interfaces in
- set_aifs()
-
-In concurrent mode supported by this driver, both interfaces will use
-the same channel and same wireless mode.
-It is therefore possible to get the wireless mode by checking the first
-connected interface.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-11-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -4913,14 +4913,20 @@ static void rtl8xxxu_set_aifs(struct rtl
- u8 aifs, aifsn, sifs;
- int i;
-
-- if (priv->vif) {
-+ for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) {
-+ if (!priv->vifs[i])
-+ continue;
-+
- struct ieee80211_sta *sta;
-
- rcu_read_lock();
-- sta = ieee80211_find_sta(priv->vif, priv->vif->bss_conf.bssid);
-+ sta = ieee80211_find_sta(priv->vifs[i], priv->vifs[i]->bss_conf.bssid);
- if (sta)
- wireless_mode = rtl8xxxu_wireless_mode(priv->hw, sta);
- rcu_read_unlock();
-+
-+ if (wireless_mode)
-+ break;
- }
-
- if (priv->hw->conf.chandef.chan->band == NL80211_BAND_5GHZ ||
+++ /dev/null
-From 05b22e9b7d84253f765cde01cb09d144094b61c9 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:32 +0100
-Subject: [PATCH 11/21] wifi: rtl8xxxu: support multiple interfaces in
- update_beacon_work_callback()
-
-As we only want to support AP mode/sending beacons on port 0, it is
-enough to replace priv->vif with priv->vifs[0].
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-12-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -5712,7 +5712,7 @@ static void rtl8xxxu_update_beacon_work_
- struct rtl8xxxu_priv *priv =
- container_of(work, struct rtl8xxxu_priv, update_beacon_work);
- struct ieee80211_hw *hw = priv->hw;
-- struct ieee80211_vif *vif = priv->vif;
-+ struct ieee80211_vif *vif = priv->vifs[0];
-
- if (!vif) {
- WARN_ONCE(true, "no vif to update beacon\n");
+++ /dev/null
-From 6b76638287055791e74b32c401a39ea1b91e7158 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:33 +0100
-Subject: [PATCH 12/21] wifi: rtl8xxxu: support multiple interfaces in
- configure_filter()
-
-As we only want to support AP mode/sending beacons on port 0, change
-from priv->vif to priv->vifs[0] in the check for AP mode.
-Additionally, if we are in AP mode, don't filter RX beacon and probe
-response frames to still allow working STATION mode on the other
-interface.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-13-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -6794,8 +6794,8 @@ static void rtl8xxxu_configure_filter(st
- else
- rcr |= RCR_CHECK_BSSID_BEACON | RCR_CHECK_BSSID_MATCH;
-
-- if (priv->vif && priv->vif->type == NL80211_IFTYPE_AP)
-- rcr &= ~RCR_CHECK_BSSID_MATCH;
-+ if (priv->vifs[0] && priv->vifs[0]->type == NL80211_IFTYPE_AP)
-+ rcr &= ~(RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON);
-
- if (*total_flags & FIF_CONTROL)
- rcr |= RCR_ACCEPT_CTRL_FRAME;
+++ /dev/null
-From 3f9baa99f8429ea6f56e7cc8d881c027518e9573 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:34 +0100
-Subject: [PATCH 13/21] wifi: rtl8xxxu: support multiple interfaces in
- watchdog_callback()
-
-Check first whether priv->vifs[0] exists and is of type STATION, then go
-to priv->vifs[1]. Make sure to call refresh_rate_mask for both
-interfaces.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-14-martin.kaistra@linutronix.de
----
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 19 +++++++++++--------
- 1 file changed, 11 insertions(+), 8 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -7200,11 +7200,15 @@ static void rtl8xxxu_watchdog_callback(s
- {
- struct ieee80211_vif *vif;
- struct rtl8xxxu_priv *priv;
-+ int i;
-
- priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work);
-- vif = priv->vif;
-+ for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) {
-+ vif = priv->vifs[i];
-+
-+ if (!vif || vif->type != NL80211_IFTYPE_STATION)
-+ continue;
-
-- if (vif && vif->type == NL80211_IFTYPE_STATION) {
- int signal;
- struct ieee80211_sta *sta;
-
-@@ -7215,22 +7219,21 @@ static void rtl8xxxu_watchdog_callback(s
-
- dev_dbg(dev, "%s: no sta found\n", __func__);
- rcu_read_unlock();
-- goto out;
-+ continue;
- }
- rcu_read_unlock();
-
- signal = ieee80211_ave_rssi(vif);
-
-- priv->fops->report_rssi(priv, 0,
-+ priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta),
- rtl8xxxu_signal_to_snr(signal));
-
-- if (priv->fops->set_crystal_cap)
-- rtl8xxxu_track_cfo(priv);
--
- rtl8xxxu_refresh_rate_mask(priv, signal, sta, false);
- }
-
--out:
-+ if (priv->fops->set_crystal_cap)
-+ rtl8xxxu_track_cfo(priv);
-+
- schedule_delayed_work(&priv->ra_watchdog, 2 * HZ);
- }
-
+++ /dev/null
-From eef55f1545c92c7181d5083453dee1296298ad3e Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:35 +0100
-Subject: [PATCH 14/21] wifi: rtl8xxxu: support multiple interfaces in
- {add,remove}_interface()
-
-Add a custom struct to store in vif->drv_priv with a reference to
-port_num and fill it when a new interface is added. Choose a free
-port_num for the newly added interface.
-
-As we only want to support AP mode/sending beacons on port 0, only change
-the beacon settings if a new interface is actually assigned to port 0.
-
-Call set_linktype() and set_mac() with the appropriate port_num.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-15-martin.kaistra@linutronix.de
----
- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 4 ++
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 52 +++++++++++--------
- 2 files changed, 34 insertions(+), 22 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-@@ -1921,6 +1921,10 @@ struct rtl8xxxu_sta_info {
- u8 macid;
- };
-
-+struct rtl8xxxu_vif {
-+ int port_num;
-+};
-+
- struct rtl8xxxu_rx_urb {
- struct urb urb;
- struct ieee80211_hw *hw;
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -6610,28 +6610,33 @@ error:
- static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
- {
-+ struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
-- int ret;
-+ int port_num;
- u8 val8;
-
-- if (!priv->vif) {
-- priv->vif = vif;
-- priv->vifs[0] = vif;
-- } else {
-+ if (!priv->vifs[0])
-+ port_num = 0;
-+ else if (!priv->vifs[1])
-+ port_num = 1;
-+ else
- return -EOPNOTSUPP;
-- }
-
- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
-- rtl8xxxu_stop_tx_beacon(priv);
-+ if (port_num == 0) {
-+ rtl8xxxu_stop_tx_beacon(priv);
-
-- val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
-- val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE |
-- BEACON_DISABLE_TSF_UPDATE;
-- rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
-- ret = 0;
-+ val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
-+ val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE |
-+ BEACON_DISABLE_TSF_UPDATE;
-+ rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
-+ }
- break;
- case NL80211_IFTYPE_AP:
-+ if (port_num == 1)
-+ return -EOPNOTSUPP;
-+
- rtl8xxxu_write8(priv, REG_BEACON_CTRL,
- BEACON_DISABLE_TSF_UPDATE | BEACON_CTRL_MBSSID);
- rtl8xxxu_write8(priv, REG_ATIMWND, 0x0c); /* 12ms */
-@@ -6648,31 +6653,32 @@ static int rtl8xxxu_add_interface(struct
- val8 = rtl8xxxu_read8(priv, REG_CCK_CHECK);
- val8 &= ~BIT_BCN_PORT_SEL;
- rtl8xxxu_write8(priv, REG_CCK_CHECK, val8);
--
-- ret = 0;
- break;
- default:
-- ret = -EOPNOTSUPP;
-+ return -EOPNOTSUPP;
- }
-
-- rtl8xxxu_set_linktype(priv, vif->type, 0);
-+ priv->vifs[port_num] = vif;
-+ priv->vif = vif;
-+ rtlvif->port_num = port_num;
-+
-+ rtl8xxxu_set_linktype(priv, vif->type, port_num);
- ether_addr_copy(priv->mac_addr, vif->addr);
-- rtl8xxxu_set_mac(priv, 0);
-+ rtl8xxxu_set_mac(priv, port_num);
-
-- return ret;
-+ return 0;
- }
-
- static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
- {
-+ struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
-
- dev_dbg(&priv->udev->dev, "%s\n", __func__);
-
-- if (priv->vif) {
-- priv->vif = NULL;
-- priv->vifs[0] = NULL;
-- }
-+ priv->vif = NULL;
-+ priv->vifs[rtlvif->port_num] = NULL;
- }
-
- static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed)
-@@ -7661,6 +7667,8 @@ static int rtl8xxxu_probe(struct usb_int
- if (ret)
- goto err_set_intfdata;
-
-+ hw->vif_data_size = sizeof(struct rtl8xxxu_vif);
-+
- hw->wiphy->max_scan_ssids = 1;
- hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
- if (priv->fops->max_macid_num)
+++ /dev/null
-From 073401c3b6b9eaea027240baf07f2b84dd2d2d26 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:36 +0100
-Subject: [PATCH 15/21] wifi: rtl8xxxu: support multiple interfaces in
- bss_info_changed()
-
-Call set_linktype and set_bssid now with correct port_num. Call
-stop_tx_beacon only for port 0, as we don't support beacons on port 1.
-Explicit changes to BEACON will only happen for AP type interfaces, so
-we don't need an additional check there.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-16-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -4983,6 +4983,7 @@ static void
- rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf, u64 changed)
- {
-+ struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
- struct device *dev = &priv->udev->dev;
- struct ieee80211_sta *sta;
-@@ -4995,7 +4996,7 @@ rtl8xxxu_bss_info_changed(struct ieee802
- if (changed & BSS_CHANGED_ASSOC) {
- dev_dbg(dev, "Changed ASSOC: %i!\n", vif->cfg.assoc);
-
-- rtl8xxxu_set_linktype(priv, vif->type, 0);
-+ rtl8xxxu_set_linktype(priv, vif->type, rtlvif->port_num);
-
- if (vif->cfg.assoc) {
- u32 ramask;
-@@ -5042,7 +5043,8 @@ rtl8xxxu_bss_info_changed(struct ieee802
-
- rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
-
-- rtl8xxxu_stop_tx_beacon(priv);
-+ if (rtlvif->port_num == 0)
-+ rtl8xxxu_stop_tx_beacon(priv);
-
- /* joinbss sequence */
- rtl8xxxu_write16(priv, REG_BCN_PSR_RPT,
-@@ -5084,7 +5086,7 @@ rtl8xxxu_bss_info_changed(struct ieee802
-
- if (changed & BSS_CHANGED_BSSID) {
- dev_dbg(dev, "Changed BSSID!\n");
-- rtl8xxxu_set_bssid(priv, bss_conf->bssid, 0);
-+ rtl8xxxu_set_bssid(priv, bss_conf->bssid, rtlvif->port_num);
- }
-
- if (changed & BSS_CHANGED_BASIC_RATES) {
+++ /dev/null
-From 61fdbd9e2a9d74c716bf4d9684653de5efdee691 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:37 +0100
-Subject: [PATCH 16/21] wifi: rtl8xxxu: support multiple interface in
- start_ap()
-
-Call set_bssid() with the correct port_num now.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-17-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -5111,11 +5111,12 @@ error:
- static int rtl8xxxu_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *link_conf)
- {
-+ struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
- struct device *dev = &priv->udev->dev;
-
- dev_dbg(dev, "Start AP mode\n");
-- rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid, 0);
-+ rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid, rtlvif->port_num);
- rtl8xxxu_write16(priv, REG_BCN_INTERVAL, vif->bss_conf.beacon_int);
- priv->fops->report_connect(priv, RTL8XXXU_BC_MC_MACID, 0, true);
-
+++ /dev/null
-From 5ce0d7e8aee03e73b35f0fe1f1ebbdd4e45776f3 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:38 +0100
-Subject: [PATCH 17/21] wifi: rtl8xxxu: add macids for STA mode
-
-Until now, the driver only assigned a dedicated macid for connections
-made in AP mode, in STA mode the return value of rtl8xxxu_get_macid()
-was simply 0.
-To differentiate between port 0 and 1, when both are in STA mode,
-allocate a second macid (with value 1) and set sta_info->macid according
-to the used port_num in rtl8xxxu_sta_add().
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-18-martin.kaistra@linutronix.de
----
- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 +
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 18 +++++++++++++++++-
- 2 files changed, 18 insertions(+), 1 deletion(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-@@ -1774,6 +1774,7 @@ struct rtl8xxxu_cfo_tracking {
- #define RTL8XXXU_HW_LED_CONTROL 2
- #define RTL8XXXU_MAX_MAC_ID_NUM 128
- #define RTL8XXXU_BC_MC_MACID 0
-+#define RTL8XXXU_BC_MC_MACID1 1
-
- struct rtl8xxxu_priv {
- struct ieee80211_hw *hw;
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -4053,10 +4053,13 @@ static inline u8 rtl8xxxu_get_macid(stru
- {
- struct rtl8xxxu_sta_info *sta_info;
-
-- if (!priv->vif || priv->vif->type == NL80211_IFTYPE_STATION || !sta)
-+ if (!sta)
- return 0;
-
- sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv;
-+ if (!sta_info)
-+ return 0;
-+
- return sta_info->macid;
- }
-
-@@ -4536,6 +4539,7 @@ static int rtl8xxxu_init_device(struct i
- rtl8188e_ra_info_init_all(&priv->ra_info);
-
- set_bit(RTL8XXXU_BC_MC_MACID, priv->mac_id_map);
-+ set_bit(RTL8XXXU_BC_MC_MACID1, priv->mac_id_map);
-
- exit:
- return ret;
-@@ -7375,6 +7379,7 @@ static int rtl8xxxu_sta_add(struct ieee8
- struct ieee80211_sta *sta)
- {
- struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv;
-+ struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
-
- if (vif->type == NL80211_IFTYPE_AP) {
-@@ -7384,6 +7389,17 @@ static int rtl8xxxu_sta_add(struct ieee8
-
- rtl8xxxu_refresh_rate_mask(priv, 0, sta, true);
- priv->fops->report_connect(priv, sta_info->macid, H2C_MACID_ROLE_STA, true);
-+ } else {
-+ switch (rtlvif->port_num) {
-+ case 0:
-+ sta_info->macid = RTL8XXXU_BC_MC_MACID;
-+ break;
-+ case 1:
-+ sta_info->macid = RTL8XXXU_BC_MC_MACID1;
-+ break;
-+ default:
-+ break;
-+ }
- }
-
- return 0;
+++ /dev/null
-From f232e9d91bb84817c60c051a3e3b56dd2721a7b3 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:39 +0100
-Subject: [PATCH 18/21] wifi: rtl8xxxu: remove obsolete priv->vif
-
-Now that all uses of priv->vif have been converted to priv->vifs[]
-remove the old attribute.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-19-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 5 -----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 --
- 2 files changed, 7 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-@@ -1893,11 +1893,6 @@ struct rtl8xxxu_priv {
- u8 rssi_level;
- DECLARE_BITMAP(tx_aggr_started, IEEE80211_NUM_TIDS);
- DECLARE_BITMAP(tid_tx_operational, IEEE80211_NUM_TIDS);
-- /*
-- * Only one virtual interface permitted because only STA mode
-- * is supported and no iface_combinations are provided.
-- */
-- struct ieee80211_vif *vif;
-
- struct ieee80211_vif *vifs[2];
- struct delayed_work ra_watchdog;
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -6666,7 +6666,6 @@ static int rtl8xxxu_add_interface(struct
- }
-
- priv->vifs[port_num] = vif;
-- priv->vif = vif;
- rtlvif->port_num = port_num;
-
- rtl8xxxu_set_linktype(priv, vif->type, port_num);
-@@ -6684,7 +6683,6 @@ static void rtl8xxxu_remove_interface(st
-
- dev_dbg(&priv->udev->dev, "%s\n", __func__);
-
-- priv->vif = NULL;
- priv->vifs[rtlvif->port_num] = NULL;
- }
-
+++ /dev/null
-From b837f78fbffa5f8e7e7c59879db54793abf161ec Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:40 +0100
-Subject: [PATCH 19/21] wifi: rtl8xxxu: add hw crypto support for AP mode
-
-Add a custom function for allocating entries in the sec cam. This allows
-us to store multiple keys with the same keyidx.
-
-The maximum number of sec cam entries for 8188f is 16 according to the
-vendor driver. Add the number to rtl8xxxu_fileops, so that other chips
-which might support more entries, can set a different number there.
-
-Set the bssid as mac address for group keys instead of just using the
-ethernet broadcast address and use BIT(6) in the sec cam ctrl entry
-for differentiating them from pairwise keys like in the vendor driver.
-
-Add the TXDESC_EN_DESC_ID bit and the hw_key_idx to tx
-broadcast/multicast packets in AP mode.
-
-Finally, allow the usage of rtl8xxxu_set_key() for AP mode.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-20-martin.kaistra@linutronix.de
----
- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 5 ++
- .../realtek/rtl8xxxu/rtl8xxxu_8188f.c | 1 +
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 48 +++++++++++++++----
- 3 files changed, 44 insertions(+), 10 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-@@ -498,6 +498,7 @@ struct rtl8xxxu_txdesc40 {
- #define DESC_RATE_ID_SHIFT 16
- #define DESC_RATE_ID_MASK 0xf
- #define TXDESC_NAVUSEHDR BIT(20)
-+#define TXDESC_EN_DESC_ID BIT(21)
- #define TXDESC_SEC_RC4 0x00400000
- #define TXDESC_SEC_AES 0x00c00000
- #define TXDESC_PKT_OFFSET_SHIFT 26
-@@ -1775,6 +1776,7 @@ struct rtl8xxxu_cfo_tracking {
- #define RTL8XXXU_MAX_MAC_ID_NUM 128
- #define RTL8XXXU_BC_MC_MACID 0
- #define RTL8XXXU_BC_MC_MACID1 1
-+#define RTL8XXXU_MAX_SEC_CAM_NUM 64
-
- struct rtl8xxxu_priv {
- struct ieee80211_hw *hw;
-@@ -1908,6 +1910,7 @@ struct rtl8xxxu_priv {
- char led_name[32];
- struct led_classdev led_cdev;
- DECLARE_BITMAP(mac_id_map, RTL8XXXU_MAX_MAC_ID_NUM);
-+ DECLARE_BITMAP(cam_map, RTL8XXXU_MAX_SEC_CAM_NUM);
- };
-
- struct rtl8xxxu_sta_info {
-@@ -1919,6 +1922,7 @@ struct rtl8xxxu_sta_info {
-
- struct rtl8xxxu_vif {
- int port_num;
-+ u8 hw_key_idx;
- };
-
- struct rtl8xxxu_rx_urb {
-@@ -1993,6 +1997,7 @@ struct rtl8xxxu_fileops {
- u16 max_aggr_num;
- u8 supports_ap:1;
- u16 max_macid_num;
-+ u16 max_sec_cam_num;
- u32 adda_1t_init;
- u32 adda_1t_path_on;
- u32 adda_2t_path_on_a;
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c
-@@ -1751,6 +1751,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops =
- .max_aggr_num = 0x0c14,
- .supports_ap = 1,
- .max_macid_num = 16,
-+ .max_sec_cam_num = 16,
- .adda_1t_init = 0x03c00014,
- .adda_1t_path_on = 0x03c00014,
- .trxff_boundary = 0x3f7f,
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -4559,8 +4559,10 @@ static void rtl8xxxu_cam_write(struct rt
- * This is a bit of a hack - the lower bits of the cipher
- * suite selector happens to match the cipher index in the CAM
- */
-- addr = key->keyidx << CAM_CMD_KEY_SHIFT;
-+ addr = key->hw_key_idx << CAM_CMD_KEY_SHIFT;
- ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID;
-+ if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
-+ ctrl |= BIT(6);
-
- for (j = 5; j >= 0; j--) {
- switch (j) {
-@@ -5546,13 +5548,14 @@ static void rtl8xxxu_tx(struct ieee80211
- struct rtl8xxxu_tx_urb *tx_urb;
- struct ieee80211_sta *sta = NULL;
- struct ieee80211_vif *vif = tx_info->control.vif;
-+ struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct device *dev = &priv->udev->dev;
- u32 queue, rts_rate;
- u16 pktlen = skb->len;
- int tx_desc_size = priv->fops->tx_desc_size;
- u8 macid;
- int ret;
-- bool ampdu_enable, sgi = false, short_preamble = false;
-+ bool ampdu_enable, sgi = false, short_preamble = false, bmc = false;
-
- if (skb_headroom(skb) < tx_desc_size) {
- dev_warn(dev,
-@@ -5594,10 +5597,14 @@ static void rtl8xxxu_tx(struct ieee80211
- tx_desc->txdw0 =
- TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT;
- if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
-- is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
-+ is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
- tx_desc->txdw0 |= TXDESC_BROADMULTICAST;
-+ bmc = true;
-+ }
-+
-
- tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT);
-+ macid = rtl8xxxu_get_macid(priv, sta);
-
- if (tx_info->control.hw_key) {
- switch (tx_info->control.hw_key->cipher) {
-@@ -5612,6 +5619,10 @@ static void rtl8xxxu_tx(struct ieee80211
- default:
- break;
- }
-+ if (bmc && rtlvif->hw_key_idx != 0xff) {
-+ tx_desc->txdw1 |= TXDESC_EN_DESC_ID;
-+ macid = rtlvif->hw_key_idx;
-+ }
- }
-
- /* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */
-@@ -5655,7 +5666,6 @@ static void rtl8xxxu_tx(struct ieee80211
- else
- rts_rate = 0;
-
-- macid = rtl8xxxu_get_macid(priv, sta);
- priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble,
- ampdu_enable, rts_rate, macid);
-
-@@ -6667,6 +6677,7 @@ static int rtl8xxxu_add_interface(struct
-
- priv->vifs[port_num] = vif;
- rtlvif->port_num = port_num;
-+ rtlvif->hw_key_idx = 0xff;
-
- rtl8xxxu_set_linktype(priv, vif->type, port_num);
- ether_addr_copy(priv->mac_addr, vif->addr);
-@@ -6843,11 +6854,19 @@ static int rtl8xxxu_set_rts_threshold(st
- return 0;
- }
-
-+static int rtl8xxxu_get_free_sec_cam(struct ieee80211_hw *hw)
-+{
-+ struct rtl8xxxu_priv *priv = hw->priv;
-+
-+ return find_first_zero_bit(priv->cam_map, priv->fops->max_sec_cam_num);
-+}
-+
- static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
- {
-+ struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
- struct device *dev = &priv->udev->dev;
- u8 mac_addr[ETH_ALEN];
-@@ -6859,9 +6878,6 @@ static int rtl8xxxu_set_key(struct ieee8
- dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n",
- __func__, cmd, key->cipher, key->keyidx);
-
-- if (vif->type != NL80211_IFTYPE_STATION)
-- return -EOPNOTSUPP;
--
- if (key->keyidx > 3)
- return -EOPNOTSUPP;
-
-@@ -6885,7 +6901,7 @@ static int rtl8xxxu_set_key(struct ieee8
- ether_addr_copy(mac_addr, sta->addr);
- } else {
- dev_dbg(dev, "%s: group key\n", __func__);
-- eth_broadcast_addr(mac_addr);
-+ ether_addr_copy(mac_addr, vif->bss_conf.bssid);
- }
-
- val16 = rtl8xxxu_read16(priv, REG_CR);
-@@ -6899,16 +6915,28 @@ static int rtl8xxxu_set_key(struct ieee8
-
- switch (cmd) {
- case SET_KEY:
-- key->hw_key_idx = key->keyidx;
-+
-+ retval = rtl8xxxu_get_free_sec_cam(hw);
-+ if (retval < 0)
-+ return -EOPNOTSUPP;
-+
-+ key->hw_key_idx = retval;
-+
-+ if (vif->type == NL80211_IFTYPE_AP && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
-+ rtlvif->hw_key_idx = key->hw_key_idx;
-+
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- rtl8xxxu_cam_write(priv, key, mac_addr);
-+ set_bit(key->hw_key_idx, priv->cam_map);
- retval = 0;
- break;
- case DISABLE_KEY:
- rtl8xxxu_write32(priv, REG_CAM_WRITE, 0x00000000);
- val32 = CAM_CMD_POLLING | CAM_CMD_WRITE |
-- key->keyidx << CAM_CMD_KEY_SHIFT;
-+ key->hw_key_idx << CAM_CMD_KEY_SHIFT;
- rtl8xxxu_write32(priv, REG_CAM_CMD, val32);
-+ rtlvif->hw_key_idx = 0xff;
-+ clear_bit(key->hw_key_idx, priv->cam_map);
- retval = 0;
- break;
- default:
+++ /dev/null
-From 69abad618efd17e50bc6f880332ab36b660b0b34 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:41 +0100
-Subject: [PATCH 20/21] wifi: rtl8xxxu: make supporting AP mode only on port 0
- transparent
-
-When the driver is used for concurrent mode, both virtual interfaces can
-be set to station or AP mode, though only one can be in AP mode at the
-same time.
-
-In order to keep the code simple, use only hw port 0 for AP mode. When
-an interface is added in AP mode which would be assigned to port 1, use
-a switch_port function to transparently swap the mapping between virtual
-interface and hw port.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-21-martin.kaistra@linutronix.de
----
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 91 ++++++++++++++++++-
- 1 file changed, 89 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -6624,6 +6624,91 @@ error:
- return ret;
- }
-
-+static void rtl8xxxu_switch_ports(struct rtl8xxxu_priv *priv)
-+{
-+ u8 macid[ETH_ALEN], bssid[ETH_ALEN], macid_1[ETH_ALEN], bssid_1[ETH_ALEN];
-+ u8 msr, bcn_ctrl, bcn_ctrl_1, atimwnd[2], atimwnd_1[2];
-+ struct rtl8xxxu_vif *rtlvif;
-+ struct ieee80211_vif *vif;
-+ u8 tsftr[8], tsftr_1[8];
-+ int i;
-+
-+ msr = rtl8xxxu_read8(priv, REG_MSR);
-+ bcn_ctrl = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
-+ bcn_ctrl_1 = rtl8xxxu_read8(priv, REG_BEACON_CTRL_1);
-+
-+ for (i = 0; i < ARRAY_SIZE(atimwnd); i++)
-+ atimwnd[i] = rtl8xxxu_read8(priv, REG_ATIMWND + i);
-+ for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++)
-+ atimwnd_1[i] = rtl8xxxu_read8(priv, REG_ATIMWND_1 + i);
-+
-+ for (i = 0; i < ARRAY_SIZE(tsftr); i++)
-+ tsftr[i] = rtl8xxxu_read8(priv, REG_TSFTR + i);
-+ for (i = 0; i < ARRAY_SIZE(tsftr); i++)
-+ tsftr_1[i] = rtl8xxxu_read8(priv, REG_TSFTR1 + i);
-+
-+ for (i = 0; i < ARRAY_SIZE(macid); i++)
-+ macid[i] = rtl8xxxu_read8(priv, REG_MACID + i);
-+
-+ for (i = 0; i < ARRAY_SIZE(bssid); i++)
-+ bssid[i] = rtl8xxxu_read8(priv, REG_BSSID + i);
-+
-+ for (i = 0; i < ARRAY_SIZE(macid_1); i++)
-+ macid_1[i] = rtl8xxxu_read8(priv, REG_MACID1 + i);
-+
-+ for (i = 0; i < ARRAY_SIZE(bssid_1); i++)
-+ bssid_1[i] = rtl8xxxu_read8(priv, REG_BSSID1 + i);
-+
-+ /* disable bcn function, disable update TSF */
-+ rtl8xxxu_write8(priv, REG_BEACON_CTRL, (bcn_ctrl &
-+ (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE);
-+ rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, (bcn_ctrl_1 &
-+ (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE);
-+
-+ /* switch msr */
-+ msr = (msr & 0xf0) | ((msr & 0x03) << 2) | ((msr & 0x0c) >> 2);
-+ rtl8xxxu_write8(priv, REG_MSR, msr);
-+
-+ /* write port0 */
-+ rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1 & ~BEACON_FUNCTION_ENABLE);
-+ for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++)
-+ rtl8xxxu_write8(priv, REG_ATIMWND + i, atimwnd_1[i]);
-+ for (i = 0; i < ARRAY_SIZE(tsftr_1); i++)
-+ rtl8xxxu_write8(priv, REG_TSFTR + i, tsftr_1[i]);
-+ for (i = 0; i < ARRAY_SIZE(macid_1); i++)
-+ rtl8xxxu_write8(priv, REG_MACID + i, macid_1[i]);
-+ for (i = 0; i < ARRAY_SIZE(bssid_1); i++)
-+ rtl8xxxu_write8(priv, REG_BSSID + i, bssid_1[i]);
-+
-+ /* write port1 */
-+ rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl & ~BEACON_FUNCTION_ENABLE);
-+ for (i = 0; i < ARRAY_SIZE(atimwnd); i++)
-+ rtl8xxxu_write8(priv, REG_ATIMWND_1 + i, atimwnd[i]);
-+ for (i = 0; i < ARRAY_SIZE(tsftr); i++)
-+ rtl8xxxu_write8(priv, REG_TSFTR1 + i, tsftr[i]);
-+ for (i = 0; i < ARRAY_SIZE(macid); i++)
-+ rtl8xxxu_write8(priv, REG_MACID1 + i, macid[i]);
-+ for (i = 0; i < ARRAY_SIZE(bssid); i++)
-+ rtl8xxxu_write8(priv, REG_BSSID1 + i, bssid[i]);
-+
-+ /* write bcn ctl */
-+ rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1);
-+ rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl);
-+
-+ vif = priv->vifs[0];
-+ priv->vifs[0] = priv->vifs[1];
-+ priv->vifs[1] = vif;
-+
-+ /* priv->vifs[0] is NULL here, based on how this function is currently
-+ * called from rtl8xxxu_add_interface().
-+ * When this function will be used in the future for a different
-+ * scenario, please check whether vifs[0] or vifs[1] can be NULL and if
-+ * necessary add code to set port_num = 1.
-+ */
-+ rtlvif = (struct rtl8xxxu_vif *)priv->vifs[1]->drv_priv;
-+ rtlvif->port_num = 1;
-+}
-+
- static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
- {
-@@ -6651,8 +6736,10 @@ static int rtl8xxxu_add_interface(struct
- }
- break;
- case NL80211_IFTYPE_AP:
-- if (port_num == 1)
-- return -EOPNOTSUPP;
-+ if (port_num == 1) {
-+ rtl8xxxu_switch_ports(priv);
-+ port_num = 0;
-+ }
-
- rtl8xxxu_write8(priv, REG_BEACON_CTRL,
- BEACON_DISABLE_TSF_UPDATE | BEACON_CTRL_MBSSID);
+++ /dev/null
-From 1cd165adf314f6bf25cde58f02f4ff51d01730b0 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Fri, 22 Dec 2023 11:14:42 +0100
-Subject: [PATCH 21/21] wifi: rtl8xxxu: declare concurrent mode support for
- 8188f
-
-Everything is in place now for concurrent mode, we can tell the system
-that we support it.
-We will allow a maximum of 2 virtual interfaces, one of them can be in
-AP mode.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20231222101442.626837-22-martin.kaistra@linutronix.de
----
- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 +
- .../realtek/rtl8xxxu/rtl8xxxu_8188f.c | 1 +
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 19 +++++++++++++++++++
- 3 files changed, 21 insertions(+)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-@@ -1992,6 +1992,7 @@ struct rtl8xxxu_fileops {
- u8 init_reg_rxfltmap:1;
- u8 init_reg_pkt_life_time:1;
- u8 init_reg_hmtfr:1;
-+ u8 supports_concurrent:1;
- u8 ampdu_max_time;
- u8 ustime_tsf_edca;
- u16 max_aggr_num;
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c
-@@ -1752,6 +1752,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops =
- .supports_ap = 1,
- .max_macid_num = 16,
- .max_sec_cam_num = 16,
-+ .supports_concurrent = 1,
- .adda_1t_init = 0x03c00014,
- .adda_1t_path_on = 0x03c00014,
- .trxff_boundary = 0x3f7f,
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -7665,6 +7665,20 @@ static void rtl8xxxu_deinit_led(struct r
- led_classdev_unregister(led);
- }
-
-+struct ieee80211_iface_limit rtl8xxxu_limits[] = {
-+ { .max = 2, .types = BIT(NL80211_IFTYPE_STATION), },
-+ { .max = 1, .types = BIT(NL80211_IFTYPE_AP), },
-+};
-+
-+struct ieee80211_iface_combination rtl8xxxu_combinations[] = {
-+ {
-+ .limits = rtl8xxxu_limits,
-+ .n_limits = ARRAY_SIZE(rtl8xxxu_limits),
-+ .max_interfaces = 2,
-+ .num_different_channels = 1,
-+ },
-+};
-+
- static int rtl8xxxu_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
- {
-@@ -7810,6 +7824,11 @@ static int rtl8xxxu_probe(struct usb_int
- hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
- hw->queues = 4;
-
-+ if (priv->fops->supports_concurrent) {
-+ hw->wiphy->iface_combinations = rtl8xxxu_combinations;
-+ hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtl8xxxu_combinations);
-+ }
-+
- sband = &rtl8xxxu_supported_band;
- sband->ht_cap.ht_supported = true;
- sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+++ /dev/null
-From 9475cc7ac31503521af95e38151e9d856e8ff30b Mon Sep 17 00:00:00 2001
-From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
-Date: Sun, 31 Dec 2023 00:45:54 +0200
-Subject: [PATCH 1/2] wifi: rtl8xxxu: Fix LED control code of RTL8192FU
-
-Some devices, like the Comfast CF-826F, use LED1, which already works.
-Others, like Asus USB-N13 C1, use LED0, which doesn't work correctly.
-
-Write the right values to the LED control registers to make LED0 work
-as well.
-
-This is unfortunately tested only with the Comfast CF-826F.
-
-Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/7a2c3158-3a45-4466-b11e-fc09802b20e2@gmail.com
----
- .../realtek/rtl8xxxu/rtl8xxxu_8192f.c | 32 +++++++++++++------
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 15 +++++++++
- 2 files changed, 38 insertions(+), 9 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c
-@@ -2014,26 +2014,40 @@ static int rtl8192fu_led_brightness_set(
- struct rtl8xxxu_priv *priv = container_of(led_cdev,
- struct rtl8xxxu_priv,
- led_cdev);
-- u16 ledcfg;
-+ u32 ledcfg;
-
- /* Values obtained by observing the USB traffic from the Windows driver. */
- rtl8xxxu_write32(priv, REG_SW_GPIO_SHARE_CTRL_0, 0x20080);
- rtl8xxxu_write32(priv, REG_SW_GPIO_SHARE_CTRL_1, 0x1b0000);
-
-- ledcfg = rtl8xxxu_read16(priv, REG_LEDCFG0);
-+ ledcfg = rtl8xxxu_read32(priv, REG_LEDCFG0);
-+
-+ /* Comfast CF-826F uses LED1. Asus USB-N13 C1 uses LED0. Set both. */
-+
-+ u32p_replace_bits(&ledcfg, LED_GPIO_ENABLE, LEDCFG0_LED2EN);
-+ u32p_replace_bits(&ledcfg, LED_IO_MODE_OUTPUT, LEDCFG0_LED0_IO_MODE);
-+ u32p_replace_bits(&ledcfg, LED_IO_MODE_OUTPUT, LEDCFG0_LED1_IO_MODE);
-
- if (brightness == LED_OFF) {
-- /* Value obtained like above. */
-- ledcfg = BIT(1) | BIT(7);
-+ u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED0CM);
-+ u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED0SV);
-+ u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED1CM);
-+ u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED1SV);
- } else if (brightness == LED_ON) {
-- /* Value obtained like above. */
-- ledcfg = BIT(1) | BIT(7) | BIT(11);
-+ u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED0CM);
-+ u32p_replace_bits(&ledcfg, LED_SW_ON, LEDCFG0_LED0SV);
-+ u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED1CM);
-+ u32p_replace_bits(&ledcfg, LED_SW_ON, LEDCFG0_LED1SV);
- } else if (brightness == RTL8XXXU_HW_LED_CONTROL) {
-- /* Value obtained by brute force. */
-- ledcfg = BIT(8) | BIT(9);
-+ u32p_replace_bits(&ledcfg, LED_MODE_TX_OR_RX_EVENTS,
-+ LEDCFG0_LED0CM);
-+ u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED0SV);
-+ u32p_replace_bits(&ledcfg, LED_MODE_TX_OR_RX_EVENTS,
-+ LEDCFG0_LED1CM);
-+ u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED1SV);
- }
-
-- rtl8xxxu_write16(priv, REG_LEDCFG0, ledcfg);
-+ rtl8xxxu_write32(priv, REG_LEDCFG0, ledcfg);
-
- return 0;
- }
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h
-@@ -146,6 +146,21 @@
- #define GPIO_INTM_EDGE_TRIG_IRQ BIT(9)
-
- #define REG_LEDCFG0 0x004c
-+#define LEDCFG0_LED0CM GENMASK(2, 0)
-+#define LEDCFG0_LED1CM GENMASK(10, 8)
-+#define LED_MODE_SW_CTRL 0x0
-+#define LED_MODE_TX_OR_RX_EVENTS 0x3
-+#define LEDCFG0_LED0SV BIT(3)
-+#define LEDCFG0_LED1SV BIT(11)
-+#define LED_SW_OFF 0x0
-+#define LED_SW_ON 0x1
-+#define LEDCFG0_LED0_IO_MODE BIT(7)
-+#define LEDCFG0_LED1_IO_MODE BIT(15)
-+#define LED_IO_MODE_OUTPUT 0x0
-+#define LED_IO_MODE_INPUT 0x1
-+#define LEDCFG0_LED2EN BIT(21)
-+#define LED_GPIO_DISABLE 0x0
-+#define LED_GPIO_ENABLE 0x1
- #define LEDCFG0_DPDT_SELECT BIT(23)
- #define REG_LEDCFG1 0x004d
- #define LEDCFG1_HW_LED_CONTROL BIT(1)
+++ /dev/null
-From 80850ca041f2c7ee28fa5e47c5c1b106415f099f Mon Sep 17 00:00:00 2001
-From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
-Date: Tue, 2 Jan 2024 21:33:07 +0200
-Subject: [PATCH 2/2] wifi: rtl8xxxu: Fix off by one initial RTS rate
-
-rtl8xxxu_set_basic_rates() sets the wrong initial RTS rate. It sets the
-next higher rate than the one it should set, e.g. 36M instead of 24M.
-
-The while loop was supposed to find the index of the most significant
-bit which is 1, but it was copied incorrectly from the vendor driver.
-Use __fls() instead.
-
-Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/761e6836-6cd6-4930-91b6-0446834655c5@gmail.com
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 7 +++----
- 1 file changed, 3 insertions(+), 4 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -4870,10 +4870,9 @@ static void rtl8xxxu_set_basic_rates(str
-
- dev_dbg(&priv->udev->dev, "%s: rates %08x\n", __func__, rate_cfg);
-
-- while (rate_cfg) {
-- rate_cfg = (rate_cfg >> 1);
-- rate_idx++;
-- }
-+ if (rate_cfg)
-+ rate_idx = __fls(rate_cfg);
-+
- rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx);
- }
-
+++ /dev/null
-From 1213acb478a7181cd73eeaf00db430f1e45b1361 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Thu, 11 Jan 2024 17:36:27 +0100
-Subject: [PATCH 1/2] wifi: rtl8xxxu: add cancel_work_sync() for c2hcmd_work
-
-The workqueue might still be running, when the driver is stopped. To
-avoid a use-after-free, call cancel_work_sync() in rtl8xxxu_stop().
-
-Fixes: e542e66b7c2e ("rtl8xxxu: add bluetooth co-existence support for single antenna")
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20240111163628.320697-2-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -7480,6 +7480,7 @@ static void rtl8xxxu_stop(struct ieee802
- if (priv->usb_interrupts)
- rtl8xxxu_write32(priv, REG_USB_HIMR, 0);
-
-+ cancel_work_sync(&priv->c2hcmd_work);
- cancel_delayed_work_sync(&priv->ra_watchdog);
-
- rtl8xxxu_free_rx_resources(priv);
+++ /dev/null
-From ece90a8622320bf5a24d3326da1f8e109891573c Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Thu, 11 Jan 2024 17:36:28 +0100
-Subject: [PATCH 2/2] wifi: rtl8xxxu: enable channel switch support
-
-The CSA countdown in the beacon frames, which are sent out by firmware,
-needs to get updated by the driver. To achieve this, convert
-update_beacon_work to delayed_work and schedule it with the beacon
-interval in case CSA is active and the countdown is not complete.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20240111163628.320697-3-martin.kaistra@linutronix.de
----
- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 2 +-
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 19 +++++++++++++++----
- 2 files changed, 16 insertions(+), 5 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-@@ -1900,7 +1900,7 @@ struct rtl8xxxu_priv {
- struct delayed_work ra_watchdog;
- struct work_struct c2hcmd_work;
- struct sk_buff_head c2hcmd_queue;
-- struct work_struct update_beacon_work;
-+ struct delayed_work update_beacon_work;
- struct rtl8xxxu_btcoex bt_coex;
- struct rtl8xxxu_ra_report ra_report;
- struct rtl8xxxu_cfo_tracking cfo_tracking;
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -4605,7 +4605,7 @@ static int rtl8xxxu_set_tim(struct ieee8
- {
- struct rtl8xxxu_priv *priv = hw->priv;
-
-- schedule_work(&priv->update_beacon_work);
-+ schedule_delayed_work(&priv->update_beacon_work, 0);
-
- return 0;
- }
-@@ -5107,7 +5107,7 @@ rtl8xxxu_bss_info_changed(struct ieee802
- }
-
- if (changed & BSS_CHANGED_BEACON)
-- schedule_work(&priv->update_beacon_work);
-+ schedule_delayed_work(&priv->update_beacon_work, 0);
-
- error:
- return;
-@@ -5726,7 +5726,7 @@ static void rtl8xxxu_send_beacon_frame(s
- static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work)
- {
- struct rtl8xxxu_priv *priv =
-- container_of(work, struct rtl8xxxu_priv, update_beacon_work);
-+ container_of(work, struct rtl8xxxu_priv, update_beacon_work.work);
- struct ieee80211_hw *hw = priv->hw;
- struct ieee80211_vif *vif = priv->vifs[0];
-
-@@ -5735,6 +5735,14 @@ static void rtl8xxxu_update_beacon_work_
- return;
- }
-
-+ if (vif->bss_conf.csa_active) {
-+ if (ieee80211_beacon_cntdwn_is_complete(vif)) {
-+ ieee80211_csa_finish(vif);
-+ return;
-+ }
-+ schedule_delayed_work(&priv->update_beacon_work,
-+ msecs_to_jiffies(vif->bss_conf.beacon_int));
-+ }
- rtl8xxxu_send_beacon_frame(hw, vif);
- }
-
-@@ -7482,6 +7490,7 @@ static void rtl8xxxu_stop(struct ieee802
-
- cancel_work_sync(&priv->c2hcmd_work);
- cancel_delayed_work_sync(&priv->ra_watchdog);
-+ cancel_delayed_work_sync(&priv->update_beacon_work);
-
- rtl8xxxu_free_rx_resources(priv);
- rtl8xxxu_free_tx_resources(priv);
-@@ -7763,7 +7772,7 @@ static int rtl8xxxu_probe(struct usb_int
- spin_lock_init(&priv->rx_urb_lock);
- INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work);
- INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback);
-- INIT_WORK(&priv->update_beacon_work, rtl8xxxu_update_beacon_work_callback);
-+ INIT_DELAYED_WORK(&priv->update_beacon_work, rtl8xxxu_update_beacon_work_callback);
- skb_queue_head_init(&priv->c2hcmd_queue);
-
- usb_set_intfdata(interface, hw);
-@@ -7824,6 +7833,8 @@ static int rtl8xxxu_probe(struct usb_int
- hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
- hw->queues = 4;
-
-+ hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-+
- if (priv->fops->supports_concurrent) {
- hw->wiphy->iface_combinations = rtl8xxxu_combinations;
- hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtl8xxxu_combinations);
+++ /dev/null
-From 426e7b4773921d07ab4ab8ba16fbad396d6c9971 Mon Sep 17 00:00:00 2001
-From: Ping-Ke Shih <pkshih@realtek.com>
-Date: Tue, 16 Jan 2024 16:09:44 +0800
-Subject: [PATCH 1/2] wifi: rtl8xxxu: convert EN_DESC_ID of TX descriptor to
- le32 type
-
-Fields of TX descriptor are little-endian order, so correct EN_DESC_ID
-field to le32 type.
-
-Fixes: b837f78fbffa ("wifi: rtl8xxxu: add hw crypto support for AP mode")
-Reported-by: kernel test robot <lkp@intel.com>
-Closes: https://lore.kernel.org/oe-kbuild-all/202401161318.YtXoCkjU-lkp@intel.com/
-Cc: Martin Kaistra <martin.kaistra@linutronix.de>
-Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20240116080945.20172-1-pkshih@realtek.com
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -5619,7 +5619,7 @@ static void rtl8xxxu_tx(struct ieee80211
- break;
- }
- if (bmc && rtlvif->hw_key_idx != 0xff) {
-- tx_desc->txdw1 |= TXDESC_EN_DESC_ID;
-+ tx_desc->txdw1 |= cpu_to_le32(TXDESC_EN_DESC_ID);
- macid = rtlvif->hw_key_idx;
- }
- }
+++ /dev/null
-From 92c7428f942da7dfcdc629b05b5114f80822d7a4 Mon Sep 17 00:00:00 2001
-From: Ping-Ke Shih <pkshih@realtek.com>
-Date: Tue, 16 Jan 2024 16:09:45 +0800
-Subject: [PATCH 2/2] wifi: rtl8xxxu: make instances of iface limit and
- combination to be static const
-
-rtl8xxxu_limits and rtl8xxxu_combinations can be static const, so add
-modifiers as desire. Otherwise, Sparse reports warnings
-
-rtl8xxxu_core.c:7677:30: warning: symbol 'rtl8xxxu_limits' was not declared. Should it be static?
-rtl8xxxu_core.c:7682:36: warning: symbol 'rtl8xxxu_combinations' was not declared. Should it be static?
-
-Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20240116080945.20172-2-pkshih@realtek.com
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -7674,12 +7674,12 @@ static void rtl8xxxu_deinit_led(struct r
- led_classdev_unregister(led);
- }
-
--struct ieee80211_iface_limit rtl8xxxu_limits[] = {
-+static const struct ieee80211_iface_limit rtl8xxxu_limits[] = {
- { .max = 2, .types = BIT(NL80211_IFTYPE_STATION), },
- { .max = 1, .types = BIT(NL80211_IFTYPE_AP), },
- };
-
--struct ieee80211_iface_combination rtl8xxxu_combinations[] = {
-+static const struct ieee80211_iface_combination rtl8xxxu_combinations[] = {
- {
- .limits = rtl8xxxu_limits,
- .n_limits = ARRAY_SIZE(rtl8xxxu_limits),
+++ /dev/null
-From 563d5025cf3b51c7bf20e6966af433ed5f838875 Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Tue, 16 Jan 2024 10:50:01 +0100
-Subject: [PATCH] wifi: rtl8xxxu: add missing number of sec cam entries for all
- variants
-
-Commit b837f78fbffa ("wifi: rtl8xxxu: add hw crypto support for AP
-mode") introduced max_sec_cam_num as a member of rtl8xxxu_fileops.
-It was missed to set this number for all variants except 8188f, which
-caused rtl8xxxu_get_free_sec_cam() to always return 0 and therefore breaking
-encrypted traffic.
-
-Fix it by adding the numbers for all variants. The values are taken from
-the vendor drivers and rtlwifi.
-
-Link: https://lore.kernel.org/linux-wireless/20240111163603.2325-1-zenmchen@gmail.com/
-Fixes: b837f78fbffa ("wifi: rtl8xxxu: add hw crypto support for AP mode")
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20240116095001.399500-1-martin.kaistra@linutronix.de
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c | 1 +
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c | 1 +
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c | 1 +
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c | 1 +
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c | 1 +
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c | 1 +
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 1 +
- 7 files changed, 7 insertions(+)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c
-@@ -1882,6 +1882,7 @@ struct rtl8xxxu_fileops rtl8188eu_fops =
- .has_tx_report = 1,
- .init_reg_pkt_life_time = 1,
- .gen2_thermal_meter = 1,
-+ .max_sec_cam_num = 32,
- .adda_1t_init = 0x0b1b25a0,
- .adda_1t_path_on = 0x0bdb25a0,
- /*
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c
-@@ -613,6 +613,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops =
- .rx_agg_buf_size = 16000,
- .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
- .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
-+ .max_sec_cam_num = 32,
- .adda_1t_init = 0x0b1b25a0,
- .adda_1t_path_on = 0x0bdb25a0,
- .adda_2t_path_on_a = 0x04db25a4,
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c
-@@ -1769,6 +1769,7 @@ struct rtl8xxxu_fileops rtl8192eu_fops =
- .needs_full_init = 1,
- .supports_ap = 1,
- .max_macid_num = 128,
-+ .max_sec_cam_num = 64,
- .adda_1t_init = 0x0fc01616,
- .adda_1t_path_on = 0x0fc01616,
- .adda_2t_path_on_a = 0x0fc01616,
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c
-@@ -2095,6 +2095,7 @@ struct rtl8xxxu_fileops rtl8192fu_fops =
- .max_aggr_num = 0x1f1f,
- .supports_ap = 1,
- .max_macid_num = 128,
-+ .max_sec_cam_num = 64,
- .trxff_boundary = 0x3f3f,
- .pbp_rx = PBP_PAGE_SIZE_256,
- .pbp_tx = PBP_PAGE_SIZE_256,
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c
-@@ -1877,6 +1877,7 @@ struct rtl8xxxu_fileops rtl8710bu_fops =
- .max_aggr_num = 0x0c14,
- .supports_ap = 1,
- .max_macid_num = 16,
-+ .max_sec_cam_num = 32,
- .adda_1t_init = 0x03c00016,
- .adda_1t_path_on = 0x03c00016,
- .trxff_boundary = 0x3f7f,
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c
-@@ -510,6 +510,7 @@ struct rtl8xxxu_fileops rtl8723au_fops =
- .rx_agg_buf_size = 16000,
- .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
- .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
-+ .max_sec_cam_num = 32,
- .adda_1t_init = 0x0b1b25a0,
- .adda_1t_path_on = 0x0bdb25a0,
- .adda_2t_path_on_a = 0x04db25a4,
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c
-@@ -1744,6 +1744,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops =
- .max_aggr_num = 0x0c14,
- .supports_ap = 1,
- .max_macid_num = 128,
-+ .max_sec_cam_num = 64,
- .adda_1t_init = 0x01c00014,
- .adda_1t_path_on = 0x01c00014,
- .adda_2t_path_on_a = 0x01c00014,
+++ /dev/null
-From 17903a283593c1dbf9da041f836004163ca30f7b Mon Sep 17 00:00:00 2001
-From: Dan Carpenter <dan.carpenter@linaro.org>
-Date: Wed, 31 Jan 2024 10:10:07 +0300
-Subject: [PATCH] wifi: rtl8xxxu: fix error messages
-
-The first parameter of WARN_ONCE() is a condition so this code will end
-up printing the function name instead of the proper message.
-
-Fixes: 3ff7a05996f9 ("wifi: rtl8xxxu: support setting bssid register for multiple interfaces")
-Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/7b144531-a8da-4725-8911-9b614a525a35@moroto.mountain
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -3593,7 +3593,7 @@ static int rtl8xxxu_set_mac(struct rtl8x
- reg = REG_MACID1;
- break;
- default:
-- WARN_ONCE("%s: invalid port_num\n", __func__);
-+ WARN_ONCE(1, "%s: invalid port_num\n", __func__);
- return -EINVAL;
- }
-
-@@ -3618,7 +3618,7 @@ static int rtl8xxxu_set_bssid(struct rtl
- reg = REG_BSSID1;
- break;
- default:
-- WARN_ONCE("%s: invalid port_num\n", __func__);
-+ WARN_ONCE(1, "%s: invalid port_num\n", __func__);
- return -EINVAL;
- }
-
+++ /dev/null
-From 1209f487d452ff7e822dec30661fd6b5163fb8cf Mon Sep 17 00:00:00 2001
-From: Chun Qiu <cqca@cock.lu>
-Date: Mon, 29 Jan 2024 13:30:30 +0800
-Subject: [PATCH] wifi: rtl8xxxu: Add TP-Link TL-WN823N V2
-
-TP-Link TL-WN823N V2 (2357:0135) is based on rtl8192fu and has been
-tested to work with the rtl8xxxu driver.
-
-Signed-off-by: Chun Qiu <cqca@cock.lu>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20240129053030.16369-1-cqca@cock.lu
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -7733,7 +7733,7 @@ static int rtl8xxxu_probe(struct usb_int
- untested = 0;
- break;
- case 0x2357:
-- if (id->idProduct == 0x0109)
-+ if (id->idProduct == 0x0109 || id->idProduct == 0x0135)
- untested = 0;
- break;
- case 0x0b05:
-@@ -8025,6 +8025,9 @@ static const struct usb_device_id dev_ta
- .driver_info = (unsigned long)&rtl8192fu_fops},
- {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x318b, 0xff, 0xff, 0xff),
- .driver_info = (unsigned long)&rtl8192fu_fops},
-+/* TP-Link TL-WN823N V2 */
-+{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0135, 0xff, 0xff, 0xff),
-+ .driver_info = (unsigned long)&rtl8192fu_fops},
- #ifdef CPTCFG_RTL8XXXU_UNTESTED
- /* Still supported by rtlwifi */
- {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff),
+++ /dev/null
-From 94dd7ce1885e530a7b10bbe50d5d68ba1bb99e6e Mon Sep 17 00:00:00 2001
-From: Martin Kaistra <martin.kaistra@linutronix.de>
-Date: Mon, 5 Feb 2024 10:30:40 +0100
-Subject: [PATCH] wifi: rtl8xxxu: update rate mask per sta
-
-Until now, rtl8xxxu_watchdog_callback() only fetches RSSI and updates
-the rate mask in station mode. This means, in AP mode only the default
-rate mask is used.
-
-In order to have the rate mask reflect the actual connection quality,
-extend rtl8xxxu_watchdog_callback() to iterate over every sta. Like in
-the rtw88 driver, add a function to collect all currently present stas
-and then iterate over a list of copies to ensure no RCU lock problems
-for register access via USB. Remove the existing RCU lock in
-rtl8xxxu_refresh_rate_mask().
-
-Since the currently used ieee80211_ave_rssi() is only for 'vif', add
-driver-level tracking of RSSI per sta.
-
-Signed-off-by: Martin Kaistra <martin.kaistra@linutronix.de>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20240205093040.1941140-1-martin.kaistra@linutronix.de
----
- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 +-
- .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 188 ++++++++++++++----
- 2 files changed, 158 insertions(+), 38 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
-@@ -6,6 +6,7 @@
- */
-
- #include <asm/byteorder.h>
-+#include <linux/average.h>
-
- #define RTL8XXXU_DEBUG_REG_WRITE 0x01
- #define RTL8XXXU_DEBUG_REG_READ 0x02
-@@ -1858,6 +1859,8 @@ struct rtl8xxxu_priv {
- int next_mbox;
- int nr_out_eps;
-
-+ /* Ensure no added or deleted stas while iterating */
-+ struct mutex sta_mutex;
- struct mutex h2c_mutex;
- /* Protect the indirect register accesses of RTL8710BU. */
- struct mutex syson_indirect_access_mutex;
-@@ -1892,7 +1895,6 @@ struct rtl8xxxu_priv {
- u8 pi_enabled:1;
- u8 no_pape:1;
- u8 int_buf[USB_INTR_CONTENT_LENGTH];
-- u8 rssi_level;
- DECLARE_BITMAP(tx_aggr_started, IEEE80211_NUM_TIDS);
- DECLARE_BITMAP(tid_tx_operational, IEEE80211_NUM_TIDS);
-
-@@ -1913,11 +1915,15 @@ struct rtl8xxxu_priv {
- DECLARE_BITMAP(cam_map, RTL8XXXU_MAX_SEC_CAM_NUM);
- };
-
-+DECLARE_EWMA(rssi, 10, 16);
-+
- struct rtl8xxxu_sta_info {
- struct ieee80211_sta *sta;
- struct ieee80211_vif *vif;
-
- u8 macid;
-+ struct ewma_rssi avg_rssi;
-+ u8 rssi_level;
- };
-
- struct rtl8xxxu_vif {
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -4991,10 +4991,11 @@ rtl8xxxu_bss_info_changed(struct ieee802
- struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
- struct device *dev = &priv->udev->dev;
-+ struct rtl8xxxu_sta_info *sta_info;
- struct ieee80211_sta *sta;
- struct rtl8xxxu_ra_report *rarpt;
-+ u8 val8, macid;
- u32 val32;
-- u8 val8;
-
- rarpt = &priv->ra_report;
-
-@@ -5017,6 +5018,7 @@ rtl8xxxu_bss_info_changed(struct ieee802
- rcu_read_unlock();
- goto error;
- }
-+ macid = rtl8xxxu_get_macid(priv, sta);
-
- if (sta->deflink.ht_cap.ht_supported)
- dev_info(dev, "%s: HT supported\n", __func__);
-@@ -5037,14 +5039,15 @@ rtl8xxxu_bss_info_changed(struct ieee802
- bw = RATE_INFO_BW_40;
- else
- bw = RATE_INFO_BW_20;
-+
-+ sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv;
-+ sta_info->rssi_level = RTL8XXXU_RATR_STA_INIT;
- rcu_read_unlock();
-
- rtl8xxxu_update_ra_report(rarpt, highest_rate, sgi, bw);
-
-- priv->rssi_level = RTL8XXXU_RATR_STA_INIT;
--
- priv->fops->update_rate_mask(priv, ramask, 0, sgi,
-- bw == RATE_INFO_BW_40, 0);
-+ bw == RATE_INFO_BW_40, macid);
-
- rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
-
-@@ -6317,6 +6320,76 @@ static void rtl8188e_c2hcmd_callback(str
- }
- }
-
-+#define rtl8xxxu_iterate_vifs_atomic(priv, iterator, data) \
-+ ieee80211_iterate_active_interfaces_atomic((priv)->hw, \
-+ IEEE80211_IFACE_ITER_NORMAL, iterator, data)
-+
-+struct rtl8xxxu_rx_update_rssi_data {
-+ struct rtl8xxxu_priv *priv;
-+ struct ieee80211_hdr *hdr;
-+ struct ieee80211_rx_status *rx_status;
-+ u8 *bssid;
-+};
-+
-+static void rtl8xxxu_rx_update_rssi_iter(void *data, u8 *mac,
-+ struct ieee80211_vif *vif)
-+{
-+ struct rtl8xxxu_rx_update_rssi_data *iter_data = data;
-+ struct ieee80211_sta *sta;
-+ struct ieee80211_hdr *hdr = iter_data->hdr;
-+ struct rtl8xxxu_priv *priv = iter_data->priv;
-+ struct rtl8xxxu_sta_info *sta_info;
-+ struct ieee80211_rx_status *rx_status = iter_data->rx_status;
-+ u8 *bssid = iter_data->bssid;
-+
-+ if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
-+ return;
-+
-+ if (!(ether_addr_equal(vif->addr, hdr->addr1) ||
-+ ieee80211_is_beacon(hdr->frame_control)))
-+ return;
-+
-+ sta = ieee80211_find_sta_by_ifaddr(priv->hw, hdr->addr2,
-+ vif->addr);
-+ if (!sta)
-+ return;
-+
-+ sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv;
-+ ewma_rssi_add(&sta_info->avg_rssi, -rx_status->signal);
-+}
-+
-+static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
-+{
-+ __le16 fc = hdr->frame_control;
-+ u8 *bssid;
-+
-+ if (ieee80211_has_tods(fc))
-+ bssid = hdr->addr1;
-+ else if (ieee80211_has_fromds(fc))
-+ bssid = hdr->addr2;
-+ else
-+ bssid = hdr->addr3;
-+
-+ return bssid;
-+}
-+
-+static void rtl8xxxu_rx_update_rssi(struct rtl8xxxu_priv *priv,
-+ struct ieee80211_rx_status *rx_status,
-+ struct ieee80211_hdr *hdr)
-+{
-+ struct rtl8xxxu_rx_update_rssi_data data = {};
-+
-+ if (ieee80211_is_ctl(hdr->frame_control))
-+ return;
-+
-+ data.priv = priv;
-+ data.hdr = hdr;
-+ data.rx_status = rx_status;
-+ data.bssid = get_hdr_bssid(hdr);
-+
-+ rtl8xxxu_iterate_vifs_atomic(priv, rtl8xxxu_rx_update_rssi_iter, &data);
-+}
-+
- int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
- {
- struct ieee80211_hw *hw = priv->hw;
-@@ -6376,18 +6449,26 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8x
- skb_queue_tail(&priv->c2hcmd_queue, skb);
- schedule_work(&priv->c2hcmd_work);
- } else {
-+ struct ieee80211_hdr *hdr;
-+
- phy_stats = (struct rtl8723au_phy_stats *)skb->data;
-
- skb_pull(skb, drvinfo_sz + desc_shift);
-
- skb_trim(skb, pkt_len);
-
-- if (rx_desc->phy_stats)
-+ hdr = (struct ieee80211_hdr *)skb->data;
-+ if (rx_desc->phy_stats) {
- priv->fops->parse_phystats(
- priv, rx_status, phy_stats,
- rx_desc->rxmcs,
-- (struct ieee80211_hdr *)skb->data,
-+ hdr,
- rx_desc->crc32 || rx_desc->icverr);
-+ if (!rx_desc->crc32 && !rx_desc->icverr)
-+ rtl8xxxu_rx_update_rssi(priv,
-+ rx_status,
-+ hdr);
-+ }
-
- rx_status->mactime = rx_desc->tsfl;
- rx_status->flag |= RX_FLAG_MACTIME_START;
-@@ -6484,10 +6565,15 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8x
- } else {
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
-- if (rx_desc->phy_stats)
-+ if (rx_desc->phy_stats) {
- priv->fops->parse_phystats(priv, rx_status, phy_stats,
- rx_desc->rxmcs, hdr,
- rx_desc->crc32 || rx_desc->icverr);
-+ if (!rx_desc->crc32 && !rx_desc->icverr)
-+ rtl8xxxu_rx_update_rssi(priv,
-+ rx_status,
-+ hdr);
-+ }
-
- rx_status->mactime = rx_desc->tsfl;
- rx_status->flag |= RX_FLAG_MACTIME_START;
-@@ -7111,6 +7197,7 @@ static void rtl8xxxu_refresh_rate_mask(s
- int signal, struct ieee80211_sta *sta,
- bool force)
- {
-+ struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv;
- struct ieee80211_hw *hw = priv->hw;
- u16 wireless_mode;
- u8 rssi_level, ratr_idx;
-@@ -7119,7 +7206,7 @@ static void rtl8xxxu_refresh_rate_mask(s
- u8 go_up_gap = 5;
- u8 macid = rtl8xxxu_get_macid(priv, sta);
-
-- rssi_level = priv->rssi_level;
-+ rssi_level = sta_info->rssi_level;
- snr = rtl8xxxu_signal_to_snr(signal);
- snr_thresh_high = RTL8XXXU_SNR_THRESH_HIGH;
- snr_thresh_low = RTL8XXXU_SNR_THRESH_LOW;
-@@ -7144,18 +7231,16 @@ static void rtl8xxxu_refresh_rate_mask(s
- else
- rssi_level = RTL8XXXU_RATR_STA_LOW;
-
-- if (rssi_level != priv->rssi_level || force) {
-+ if (rssi_level != sta_info->rssi_level || force) {
- int sgi = 0;
- u32 rate_bitmap = 0;
-
-- rcu_read_lock();
- rate_bitmap = (sta->deflink.supp_rates[0] & 0xfff) |
- (sta->deflink.ht_cap.mcs.rx_mask[0] << 12) |
- (sta->deflink.ht_cap.mcs.rx_mask[1] << 20);
- if (sta->deflink.ht_cap.cap &
- (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))
- sgi = 1;
-- rcu_read_unlock();
-
- wireless_mode = rtl8xxxu_wireless_mode(hw, sta);
- switch (wireless_mode) {
-@@ -7236,7 +7321,7 @@ static void rtl8xxxu_refresh_rate_mask(s
- break;
- }
-
-- priv->rssi_level = rssi_level;
-+ sta_info->rssi_level = rssi_level;
- priv->fops->update_rate_mask(priv, rate_bitmap, ratr_idx, sgi, txbw_40mhz, macid);
- }
- }
-@@ -7329,40 +7414,60 @@ static void rtl8xxxu_track_cfo(struct rt
- rtl8xxxu_set_atc_status(priv, abs(cfo_average) >= CFO_TH_ATC);
- }
-
--static void rtl8xxxu_watchdog_callback(struct work_struct *work)
-+static void rtl8xxxu_ra_iter(void *data, struct ieee80211_sta *sta)
- {
-- struct ieee80211_vif *vif;
-- struct rtl8xxxu_priv *priv;
-- int i;
-+ struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv;
-+ struct rtl8xxxu_priv *priv = data;
-+ int signal = -ewma_rssi_read(&sta_info->avg_rssi);
-
-- priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work);
-- for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) {
-- vif = priv->vifs[i];
-+ priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta),
-+ rtl8xxxu_signal_to_snr(signal));
-+ rtl8xxxu_refresh_rate_mask(priv, signal, sta, false);
-+}
-+
-+struct rtl8xxxu_stas_entry {
-+ struct list_head list;
-+ struct ieee80211_sta *sta;
-+};
-
-- if (!vif || vif->type != NL80211_IFTYPE_STATION)
-- continue;
-+struct rtl8xxxu_iter_stas_data {
-+ struct rtl8xxxu_priv *priv;
-+ struct list_head list;
-+};
-
-- int signal;
-- struct ieee80211_sta *sta;
-+static void rtl8xxxu_collect_sta_iter(void *data, struct ieee80211_sta *sta)
-+{
-+ struct rtl8xxxu_iter_stas_data *iter_stas = data;
-+ struct rtl8xxxu_stas_entry *stas_entry;
-
-- rcu_read_lock();
-- sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
-- if (!sta) {
-- struct device *dev = &priv->udev->dev;
-+ stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC);
-+ if (!stas_entry)
-+ return;
-
-- dev_dbg(dev, "%s: no sta found\n", __func__);
-- rcu_read_unlock();
-- continue;
-- }
-- rcu_read_unlock();
-+ stas_entry->sta = sta;
-+ list_add_tail(&stas_entry->list, &iter_stas->list);
-+}
-
-- signal = ieee80211_ave_rssi(vif);
-+static void rtl8xxxu_watchdog_callback(struct work_struct *work)
-+{
-
-- priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta),
-- rtl8xxxu_signal_to_snr(signal));
-+ struct rtl8xxxu_iter_stas_data iter_data;
-+ struct rtl8xxxu_stas_entry *sta_entry, *tmp;
-+ struct rtl8xxxu_priv *priv;
-
-- rtl8xxxu_refresh_rate_mask(priv, signal, sta, false);
-+ priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work);
-+ iter_data.priv = priv;
-+ INIT_LIST_HEAD(&iter_data.list);
-+
-+ mutex_lock(&priv->sta_mutex);
-+ ieee80211_iterate_stations_atomic(priv->hw, rtl8xxxu_collect_sta_iter,
-+ &iter_data);
-+ list_for_each_entry_safe(sta_entry, tmp, &iter_data.list, list) {
-+ list_del_init(&sta_entry->list);
-+ rtl8xxxu_ra_iter(priv, sta_entry->sta);
-+ kfree(sta_entry);
- }
-+ mutex_unlock(&priv->sta_mutex);
-
- if (priv->fops->set_crystal_cap)
- rtl8xxxu_track_cfo(priv);
-@@ -7504,10 +7609,15 @@ static int rtl8xxxu_sta_add(struct ieee8
- struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
-
-+ mutex_lock(&priv->sta_mutex);
-+ ewma_rssi_init(&sta_info->avg_rssi);
- if (vif->type == NL80211_IFTYPE_AP) {
-+ sta_info->rssi_level = RTL8XXXU_RATR_STA_INIT;
- sta_info->macid = rtl8xxxu_acquire_macid(priv);
-- if (sta_info->macid >= RTL8XXXU_MAX_MAC_ID_NUM)
-+ if (sta_info->macid >= RTL8XXXU_MAX_MAC_ID_NUM) {
-+ mutex_unlock(&priv->sta_mutex);
- return -ENOSPC;
-+ }
-
- rtl8xxxu_refresh_rate_mask(priv, 0, sta, true);
- priv->fops->report_connect(priv, sta_info->macid, H2C_MACID_ROLE_STA, true);
-@@ -7523,6 +7633,7 @@ static int rtl8xxxu_sta_add(struct ieee8
- break;
- }
- }
-+ mutex_unlock(&priv->sta_mutex);
-
- return 0;
- }
-@@ -7534,8 +7645,10 @@ static int rtl8xxxu_sta_remove(struct ie
- struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv;
- struct rtl8xxxu_priv *priv = hw->priv;
-
-+ mutex_lock(&priv->sta_mutex);
- if (vif->type == NL80211_IFTYPE_AP)
- rtl8xxxu_release_macid(priv, sta_info->macid);
-+ mutex_unlock(&priv->sta_mutex);
-
- return 0;
- }
-@@ -7766,6 +7879,7 @@ static int rtl8xxxu_probe(struct usb_int
- mutex_init(&priv->usb_buf_mutex);
- mutex_init(&priv->syson_indirect_access_mutex);
- mutex_init(&priv->h2c_mutex);
-+ mutex_init(&priv->sta_mutex);
- INIT_LIST_HEAD(&priv->tx_urb_free_list);
- spin_lock_init(&priv->tx_urb_lock);
- INIT_LIST_HEAD(&priv->rx_urb_pending_list);
+++ /dev/null
-From 513c559ca9f05394da79fbf20a8f89eec5f53dce Mon Sep 17 00:00:00 2001
-From: Ping-Ke Shih <pkshih@realtek.com>
-Date: Fri, 16 Feb 2024 11:39:23 +0800
-Subject: [PATCH] wifi: rtl8xxxu: check vif before using in rtl8xxxu_tx()
-
-The 'vif' is from tx_info of SKB, and other codes check 'vif' before using,
-which raises smatch warnings:
-
-drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:5656 rtl8xxxu_tx()
- warn: variable dereferenced before check 'vif' (see line 5553)
-
-Compile tested only.
-
-Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/20240216033923.34683-1-pkshih@realtek.com
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -5550,7 +5550,7 @@ static void rtl8xxxu_tx(struct ieee80211
- struct rtl8xxxu_tx_urb *tx_urb;
- struct ieee80211_sta *sta = NULL;
- struct ieee80211_vif *vif = tx_info->control.vif;
-- struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv;
-+ struct rtl8xxxu_vif *rtlvif = vif ? (struct rtl8xxxu_vif *)vif->drv_priv : NULL;
- struct device *dev = &priv->udev->dev;
- u32 queue, rts_rate;
- u16 pktlen = skb->len;
-@@ -5621,7 +5621,7 @@ static void rtl8xxxu_tx(struct ieee80211
- default:
- break;
- }
-- if (bmc && rtlvif->hw_key_idx != 0xff) {
-+ if (bmc && rtlvif && rtlvif->hw_key_idx != 0xff) {
- tx_desc->txdw1 |= cpu_to_le32(TXDESC_EN_DESC_ID);
- macid = rtlvif->hw_key_idx;
- }
+++ /dev/null
-From a7e178259c5bc900da762b33d3a20b7ee1206f07 Mon Sep 17 00:00:00 2001
-From: Shiji Yang <yangshiji66@outlook.com>
-Date: Fri, 23 Feb 2024 21:34:32 +0800
-Subject: [PATCH] wifi: rtl8xxxu: fix mixed declarations in rtl8xxxu_set_aifs()
-
-Moving struct ieee80211_sta *sta variable definition to the front
-of the code to fix the ISO C90 forbids mixed declarations and code
-warning.
-
-Fixes: 43532c050f8e ("wifi: rtl8xxxu: support multiple interfaces in set_aifs()")
-Signed-off-by: Shiji Yang <yangshiji66@outlook.com>
-Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
-Signed-off-by: Kalle Valo <kvalo@kernel.org>
-Link: https://msgid.link/TYAP286MB03157A408E0D69F2F6FBD88ABC552@TYAP286MB0315.JPNP286.PROD.OUTLOOK.COM
----
- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -4919,11 +4919,11 @@ static void rtl8xxxu_set_aifs(struct rtl
- int i;
-
- for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) {
-+ struct ieee80211_sta *sta;
-+
- if (!priv->vifs[i])
- continue;
-
-- struct ieee80211_sta *sta;
--
- rcu_read_lock();
- sta = ieee80211_find_sta(priv->vifs[i], priv->vifs[i]->bss_conf.bssid);
- if (sta)
+++ /dev/null
-From d5b6f6d595b446c1693fdaa6aeb4a65b94d5fc90 Mon Sep 17 00:00:00 2001
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Wed, 20 Dec 2023 13:41:39 +0200
-Subject: [PATCH] wifi: mac80211: rework RX timestamp flags
-
-We only have a single flag free, and before using that for
-another mactime flag, instead refactor the mactime flags
-to use a 2-bit field.
-
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-Reviewed-by: Gregory Greenman <gregory.greenman@intel.com>
-Reviewed-by: Benjamin Berg <benjamin.berg@intel.com>
-Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
-Link: https://msgid.link/20231220133549.d0e664832d14.I20c8900106f9bf81316bed778b1e3ce145785274@changeid
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 +-
- include/net/mac80211.h | 13 +++++++++----
- net/mac80211/ieee80211_i.h | 5 +----
- net/mac80211/util.c | 16 ++++++++++------
- 4 files changed, 21 insertions(+), 15 deletions(-)
-
---- a/drivers/net/wireless/ath/ath10k/htt_rx.c
-+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
-@@ -1294,7 +1294,7 @@ static void ath10k_htt_rx_h_ppdu(struct
- status->encoding = RX_ENC_LEGACY;
- status->bw = RATE_INFO_BW_20;
-
-- status->flag &= ~RX_FLAG_MACTIME_END;
-+ status->flag &= ~RX_FLAG_MACTIME;
- status->flag |= RX_FLAG_NO_SIGNAL_VAL;
-
- status->flag &= ~(RX_FLAG_AMPDU_IS_LAST);
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -1352,6 +1352,9 @@ ieee80211_tx_info_clear_status(struct ie
- * the frame.
- * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
- * the frame.
-+ * @RX_FLAG_MACTIME: The timestamp passed in the RX status (@mactime
-+ * field) is valid if this field is non-zero, and the position
-+ * where the timestamp was sampled depends on the value.
- * @RX_FLAG_MACTIME_START: The timestamp passed in the RX status (@mactime
- * field) is valid and contains the time the first symbol of the MPDU
- * was received. This is useful in monitor mode and for proper IBSS
-@@ -1431,12 +1434,12 @@ ieee80211_tx_info_clear_status(struct ie
- enum mac80211_rx_flags {
- RX_FLAG_MMIC_ERROR = BIT(0),
- RX_FLAG_DECRYPTED = BIT(1),
-- RX_FLAG_MACTIME_PLCP_START = BIT(2),
-+ RX_FLAG_ONLY_MONITOR = BIT(2),
- RX_FLAG_MMIC_STRIPPED = BIT(3),
- RX_FLAG_IV_STRIPPED = BIT(4),
- RX_FLAG_FAILED_FCS_CRC = BIT(5),
- RX_FLAG_FAILED_PLCP_CRC = BIT(6),
-- RX_FLAG_MACTIME_START = BIT(7),
-+ /* one free bit at 7 */
- RX_FLAG_NO_SIGNAL_VAL = BIT(8),
- RX_FLAG_AMPDU_DETAILS = BIT(9),
- RX_FLAG_PN_VALIDATED = BIT(10),
-@@ -1445,8 +1448,10 @@ enum mac80211_rx_flags {
- RX_FLAG_AMPDU_IS_LAST = BIT(13),
- RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(14),
- RX_FLAG_AMPDU_DELIM_CRC_KNOWN = BIT(15),
-- RX_FLAG_MACTIME_END = BIT(16),
-- RX_FLAG_ONLY_MONITOR = BIT(17),
-+ RX_FLAG_MACTIME = BIT(16) | BIT(17),
-+ RX_FLAG_MACTIME_PLCP_START = 1 << 16,
-+ RX_FLAG_MACTIME_START = 2 << 16,
-+ RX_FLAG_MACTIME_END = 3 << 16,
- RX_FLAG_SKIP_MONITOR = BIT(18),
- RX_FLAG_AMSDU_MORE = BIT(19),
- RX_FLAG_RADIOTAP_TLV_AT_END = BIT(20),
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -1807,10 +1807,7 @@ static inline bool txq_has_queue(struct
- static inline bool
- ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
- {
-- WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START &&
-- status->flag & RX_FLAG_MACTIME_END);
-- return !!(status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END |
-- RX_FLAG_MACTIME_PLCP_START));
-+ return status->flag & RX_FLAG_MACTIME;
- }
-
- void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata);
---- a/net/mac80211/util.c
-+++ b/net/mac80211/util.c
-@@ -4174,6 +4174,7 @@ u64 ieee80211_calculate_rx_timestamp(str
- unsigned int mpdu_offset)
- {
- u64 ts = status->mactime;
-+ bool mactime_plcp_start;
- struct rate_info ri;
- u16 rate;
- u8 n_ltf;
-@@ -4181,6 +4182,9 @@ u64 ieee80211_calculate_rx_timestamp(str
- if (WARN_ON(!ieee80211_have_rx_timestamp(status)))
- return 0;
-
-+ mactime_plcp_start = (status->flag & RX_FLAG_MACTIME) ==
-+ RX_FLAG_MACTIME_PLCP_START;
-+
- memset(&ri, 0, sizeof(ri));
-
- ri.bw = status->bw;
-@@ -4195,7 +4199,7 @@ u64 ieee80211_calculate_rx_timestamp(str
- if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
- ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
- /* TODO/FIXME: is this right? handle other PPDUs */
-- if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
-+ if (mactime_plcp_start) {
- mpdu_offset += 2;
- ts += 36;
- }
-@@ -4212,7 +4216,7 @@ u64 ieee80211_calculate_rx_timestamp(str
- * See P802.11ax_D6.0, section 27.3.4 for
- * VHT PPDU format.
- */
-- if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
-+ if (mactime_plcp_start) {
- mpdu_offset += 2;
- ts += 36;
-
-@@ -4236,7 +4240,7 @@ u64 ieee80211_calculate_rx_timestamp(str
- * See P802.11REVmd_D3.0, section 19.3.2 for
- * HT PPDU format.
- */
-- if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
-+ if (mactime_plcp_start) {
- mpdu_offset += 2;
- if (status->enc_flags & RX_ENC_FLAG_HT_GF)
- ts += 24;
-@@ -4264,7 +4268,7 @@ u64 ieee80211_calculate_rx_timestamp(str
- * See P802.11REVmd_D3.0, section 21.3.2 for
- * VHT PPDU format.
- */
-- if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
-+ if (mactime_plcp_start) {
- mpdu_offset += 2;
- ts += 36;
-
-@@ -4298,7 +4302,7 @@ u64 ieee80211_calculate_rx_timestamp(str
- bitrate = sband->bitrates[status->rate_idx].bitrate;
- ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
-
-- if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
-+ if (mactime_plcp_start) {
- if (status->band == NL80211_BAND_5GHZ) {
- ts += 20 << shift;
- mpdu_offset += 2;
-@@ -4320,7 +4324,7 @@ u64 ieee80211_calculate_rx_timestamp(str
- return 0;
-
- /* rewind from end of MPDU */
-- if (status->flag & RX_FLAG_MACTIME_END)
-+ if ((status->flag & RX_FLAG_MACTIME) == RX_FLAG_MACTIME_END)
- ts -= mpdu_len * 8 * 10 / rate;
-
- ts += mpdu_offset * 8 * 10 / rate;
+++ /dev/null
-From 2ae5c9248e06dac2c2360be26b4e25f673238337 Mon Sep 17 00:00:00 2001
-From: Jeff Johnson <quic_jjohnson@quicinc.com>
-Date: Thu, 31 Aug 2023 11:22:58 -0700
-Subject: [PATCH] wifi: mac80211: Use flexible array in struct ieee80211_tim_ie
-
-Currently struct ieee80211_tim_ie defines:
- u8 virtual_map[1];
-
-Per the guidance in [1] change this to be a flexible array.
-
-Per the discussion in [2] wrap the virtual_map in a union with a u8
-item in order to preserve the existing expectation that the
-virtual_map must contain at least one octet (at least when used in a
-non-S1G PPDU). This means that no driver changes are required.
-
-[1] https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays
-[2] https://lore.kernel.org/linux-wireless/202308301529.AC90A9EF98@keescook/
-
-Suggested-by: Kees Cook <keescook@chromium.org>
-Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Reviewed-by: Kees Cook <keescook@chromium.org>
-Link: https://lore.kernel.org/r/20230831-ieee80211_tim_ie-v3-2-e10ff584ab5d@quicinc.com
-[add wifi prefix]
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
- include/linux/ieee80211.h | 13 ++++++++++---
- 1 file changed, 10 insertions(+), 3 deletions(-)
-
---- a/include/linux/ieee80211.h
-+++ b/include/linux/ieee80211.h
-@@ -951,17 +951,24 @@ struct ieee80211_wide_bw_chansw_ie {
- * @dtim_count: DTIM Count
- * @dtim_period: DTIM Period
- * @bitmap_ctrl: Bitmap Control
-+ * @required_octet: "Syntatic sugar" to force the struct size to the
-+ * minimum valid size when carried in a non-S1G PPDU
- * @virtual_map: Partial Virtual Bitmap
- *
- * This structure represents the payload of the "TIM element" as
-- * described in IEEE Std 802.11-2020 section 9.4.2.5.
-+ * described in IEEE Std 802.11-2020 section 9.4.2.5. Note that this
-+ * definition is only applicable when the element is carried in a
-+ * non-S1G PPDU. When the TIM is carried in an S1G PPDU, the Bitmap
-+ * Control and Partial Virtual Bitmap may not be present.
- */
- struct ieee80211_tim_ie {
- u8 dtim_count;
- u8 dtim_period;
- u8 bitmap_ctrl;
-- /* variable size: 1 - 251 bytes */
-- u8 virtual_map[1];
-+ union {
-+ u8 required_octet;
-+ DECLARE_FLEX_ARRAY(u8, virtual_map);
-+ };
- } __packed;
-
- /**
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -1635,7 +1635,6 @@ static int ieee80211_stop_ap(struct wiph
- link_conf->bssid_indicator = 0;
+@@ -1647,12 +1647,6 @@ static int ieee80211_stop_ap(struct wiph
- __sta_info_flush(sdata, true);
-- ieee80211_free_keys(sdata, true);
+ __sta_info_flush(sdata, true, link_id);
+- ieee80211_remove_link_keys(link, &keys);
+- if (!list_empty(&keys)) {
+- synchronize_net();
+- ieee80211_free_key_list(local, &keys);
+- }
+-
link_conf->enable_beacon = false;
sdata->beacon_rate_set = false;
+ sdata->vif.cfg.ssid_len = 0;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -1393,24 +1393,6 @@ int ieee80211_register_hw(struct ieee802
- debugfs_hw_add(local);
- rate_control_add_debugfs(local);
+@@ -1564,24 +1564,6 @@ int ieee80211_register_hw(struct ieee802
+
+ ieee80211_check_wbrf_support(local);
- rtnl_lock();
- wiphy_lock(hw->wiphy);
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2847,6 +2847,8 @@ static int ieee80211_scan(struct wiphy *
+@@ -2844,6 +2844,8 @@ static int ieee80211_scan(struct wiphy *
*/
fallthrough;
case NL80211_IFTYPE_AP:
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -561,6 +561,11 @@ __sta_info_alloc(struct ieee80211_sub_if
+@@ -565,6 +565,11 @@ __sta_info_alloc(struct ieee80211_sub_if
+ spin_lock_init(&sta->ps_lock);
INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
- INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
- mutex_init(&sta->ampdu_mlme.mtx);
+ wiphy_work_init(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
+#if LINUX_VERSION_IS_LESS(6,2,0)
+ sta->ampdu_mlme.dialog_token_allocator = prandom_u32_max(U8_MAX);
+#else
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -92,6 +92,8 @@ extern const u8 ieee80211_ac_to_qos_mask
- */
- #define AIRTIME_ACTIVE_DURATION (HZ / 10)
+@@ -101,6 +101,8 @@ ieee80211_sta_keep_active(struct sta_inf
+ return time_before_eq(jiffies, sta->airtime[ac].last_active + HZ / 10);
+ }
+#define AIRTIME_QUANTUM_SHIFT 3
+
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -4060,7 +4060,7 @@ struct ieee80211_txq *ieee80211_next_txq
+@@ -4082,7 +4082,7 @@ struct ieee80211_txq *ieee80211_next_txq
if (deficit < 0)
sta->airtime[txqi->txq.ac].deficit +=
if (deficit < 0 || !aql_check) {
list_move_tail(&txqi->schedule_order,
-@@ -4203,7 +4203,8 @@ bool ieee80211_txq_may_transmit(struct i
+@@ -4225,7 +4225,8 @@ bool ieee80211_txq_may_transmit(struct i
}
sta = container_of(iter->txq.sta, struct sta_info, sta);
if (ieee80211_sta_deficit(sta, ac) < 0)
list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
}
-@@ -4211,7 +4212,7 @@ bool ieee80211_txq_may_transmit(struct i
+@@ -4233,7 +4234,7 @@ bool ieee80211_txq_may_transmit(struct i
if (sta->airtime[ac].deficit >= 0)
goto out;
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
-@@ -684,8 +684,12 @@ static void ieee80211_do_stop(struct iee
+@@ -693,8 +693,12 @@ static void ieee80211_do_stop(struct iee
fallthrough;
default:
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 30 Jun 2023 13:11:51 +0200
-Subject: [PATCH] mac80211: split mesh fast tx cache into
- local/proxied/forwarded
-
-Depending on the origin of the packets (and their SA), 802.11 + mesh headers
-could be filled in differently. In order to properly deal with that, add a
-new field to the lookup key, indicating the type (local, proxied or
-forwarded). This can fix spurious packet drop issues that depend on the order
-in which nodes/hosts communicate with each other.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/mesh.c
-+++ b/net/mac80211/mesh.c
-@@ -765,6 +765,9 @@ bool ieee80211_mesh_xmit_fast(struct iee
- struct sk_buff *skb, u32 ctrl_flags)
- {
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-+ struct ieee80211_mesh_fast_tx_key key = {
-+ .type = MESH_FAST_TX_TYPE_LOCAL
-+ };
- struct ieee80211_mesh_fast_tx *entry;
- struct ieee80211s_hdr *meshhdr;
- u8 sa[ETH_ALEN] __aligned(2);
-@@ -800,7 +803,10 @@ bool ieee80211_mesh_xmit_fast(struct iee
- return false;
- }
-
-- entry = mesh_fast_tx_get(sdata, skb->data);
-+ ether_addr_copy(key.addr, skb->data);
-+ if (!ether_addr_equal(skb->data + ETH_ALEN, sdata->vif.addr))
-+ key.type = MESH_FAST_TX_TYPE_PROXIED;
-+ entry = mesh_fast_tx_get(sdata, &key);
- if (!entry)
- return false;
-
---- a/net/mac80211/mesh.h
-+++ b/net/mac80211/mesh.h
-@@ -134,9 +134,38 @@ struct mesh_path {
- #define MESH_FAST_TX_CACHE_TIMEOUT 8000 /* msecs */
-
- /**
-+ * enum ieee80211_mesh_fast_tx_type - cached mesh fast tx entry type
-+ *
-+ * @MESH_FAST_TX_TYPE_LOCAL: tx from the local vif address as SA
-+ * @MESH_FAST_TX_TYPE_PROXIED: local tx with a different SA (e.g. bridged)
-+ * @MESH_FAST_TX_TYPE_FORWARDED: forwarded from a different mesh point
-+ * @NUM_MESH_FAST_TX_TYPE: number of entry types
-+ */
-+enum ieee80211_mesh_fast_tx_type {
-+ MESH_FAST_TX_TYPE_LOCAL,
-+ MESH_FAST_TX_TYPE_PROXIED,
-+ MESH_FAST_TX_TYPE_FORWARDED,
-+
-+ /* must be last */
-+ NUM_MESH_FAST_TX_TYPE
-+};
-+
-+
-+/**
-+ * struct ieee80211_mesh_fast_tx_key - cached mesh fast tx entry key
-+ *
-+ * @addr: The Ethernet DA for this entry
-+ * @type: cache entry type
-+ */
-+struct ieee80211_mesh_fast_tx_key {
-+ u8 addr[ETH_ALEN] __aligned(2);
-+ u16 type;
-+};
-+
-+/**
- * struct ieee80211_mesh_fast_tx - cached mesh fast tx entry
- * @rhash: rhashtable pointer
-- * @addr_key: The Ethernet DA which is the key for this entry
-+ * @key: the lookup key for this cache entry
- * @fast_tx: base fast_tx data
- * @hdr: cached mesh and rfc1042 headers
- * @hdrlen: length of mesh + rfc1042
-@@ -147,7 +176,7 @@ struct mesh_path {
- */
- struct ieee80211_mesh_fast_tx {
- struct rhash_head rhash;
-- u8 addr_key[ETH_ALEN] __aligned(2);
-+ struct ieee80211_mesh_fast_tx_key key;
-
- struct ieee80211_fast_tx fast_tx;
- u8 hdr[sizeof(struct ieee80211s_hdr) + sizeof(rfc1042_header)];
-@@ -333,7 +362,8 @@ void mesh_path_tx_root_frame(struct ieee
-
- bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
- struct ieee80211_mesh_fast_tx *
--mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr);
-+mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
-+ struct ieee80211_mesh_fast_tx_key *key);
- bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, u32 ctrl_flags);
- void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
---- a/net/mac80211/mesh_pathtbl.c
-+++ b/net/mac80211/mesh_pathtbl.c
-@@ -36,8 +36,8 @@ static const struct rhashtable_params me
- static const struct rhashtable_params fast_tx_rht_params = {
- .nelem_hint = 10,
- .automatic_shrinking = true,
-- .key_len = ETH_ALEN,
-- .key_offset = offsetof(struct ieee80211_mesh_fast_tx, addr_key),
-+ .key_len = sizeof(struct ieee80211_mesh_fast_tx_key),
-+ .key_offset = offsetof(struct ieee80211_mesh_fast_tx, key),
- .head_offset = offsetof(struct ieee80211_mesh_fast_tx, rhash),
- .hashfn = mesh_table_hash,
- };
-@@ -426,20 +426,21 @@ static void mesh_fast_tx_entry_free(stru
- }
-
- struct ieee80211_mesh_fast_tx *
--mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr)
-+mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
-+ struct ieee80211_mesh_fast_tx_key *key)
- {
- struct ieee80211_mesh_fast_tx *entry;
- struct mesh_tx_cache *cache;
-
- cache = &sdata->u.mesh.tx_cache;
-- entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
-+ entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
- if (!entry)
- return NULL;
-
- if (!(entry->mpath->flags & MESH_PATH_ACTIVE) ||
- mpath_expired(entry->mpath)) {
- spin_lock_bh(&cache->walk_lock);
-- entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
-+ entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
- if (entry)
- mesh_fast_tx_entry_free(cache, entry);
- spin_unlock_bh(&cache->walk_lock);
-@@ -484,18 +485,24 @@ void mesh_fast_tx_cache(struct ieee80211
- if (!sta)
- return;
-
-+ build.key.type = MESH_FAST_TX_TYPE_LOCAL;
- if ((meshhdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6) {
- /* This is required to keep the mppath alive */
- mppath = mpp_path_lookup(sdata, meshhdr->eaddr1);
- if (!mppath)
- return;
- build.mppath = mppath;
-+ if (!ether_addr_equal(meshhdr->eaddr2, sdata->vif.addr))
-+ build.key.type = MESH_FAST_TX_TYPE_PROXIED;
- } else if (ieee80211_has_a4(hdr->frame_control)) {
- mppath = mpath;
- } else {
- return;
- }
-
-+ if (!ether_addr_equal(hdr->addr4, sdata->vif.addr))
-+ build.key.type = MESH_FAST_TX_TYPE_FORWARDED;
-+
- /* rate limit, in case fast xmit can't be enabled */
- if (mppath->fast_tx_check == jiffies)
- return;
-@@ -542,7 +549,7 @@ void mesh_fast_tx_cache(struct ieee80211
- }
- }
-
-- memcpy(build.addr_key, mppath->dst, ETH_ALEN);
-+ memcpy(build.key.addr, mppath->dst, ETH_ALEN);
- build.timestamp = jiffies;
- build.fast_tx.band = info->band;
- build.fast_tx.da_offs = offsetof(struct ieee80211_hdr, addr3);
-@@ -644,13 +651,19 @@ void mesh_fast_tx_flush_addr(struct ieee
- const u8 *addr)
- {
- struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache;
-+ struct ieee80211_mesh_fast_tx_key key = {};
- struct ieee80211_mesh_fast_tx *entry;
-+ int i;
-
-+ ether_addr_copy(key.addr, addr);
- cache = &sdata->u.mesh.tx_cache;
- spin_lock_bh(&cache->walk_lock);
-- entry = rhashtable_lookup_fast(&cache->rht, addr, fast_tx_rht_params);
-- if (entry)
-- mesh_fast_tx_entry_free(cache, entry);
-+ for (i = 0; i < NUM_MESH_FAST_TX_TYPE; i++) {
-+ key.type = i;
-+ entry = rhashtable_lookup_fast(&cache->rht, &key, fast_tx_rht_params);
-+ if (entry)
-+ mesh_fast_tx_entry_free(cache, entry);
-+ }
- spin_unlock_bh(&cache->walk_lock);
- }
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2726,7 +2726,10 @@ ieee80211_rx_mesh_fast_forward(struct ie
- struct sk_buff *skb, int hdrlen)
- {
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-- struct ieee80211_mesh_fast_tx *entry = NULL;
-+ struct ieee80211_mesh_fast_tx_key key = {
-+ .type = MESH_FAST_TX_TYPE_FORWARDED
-+ };
-+ struct ieee80211_mesh_fast_tx *entry;
- struct ieee80211s_hdr *mesh_hdr;
- struct tid_ampdu_tx *tid_tx;
- struct sta_info *sta;
-@@ -2735,9 +2738,13 @@ ieee80211_rx_mesh_fast_forward(struct ie
-
- mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth));
- if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
-- entry = mesh_fast_tx_get(sdata, mesh_hdr->eaddr1);
-+ ether_addr_copy(key.addr, mesh_hdr->eaddr1);
- else if (!(mesh_hdr->flags & MESH_FLAGS_AE))
-- entry = mesh_fast_tx_get(sdata, skb->data);
-+ ether_addr_copy(key.addr, skb->data);
-+ else
-+ return false;
-+
-+ entry = mesh_fast_tx_get(sdata, &key);
- if (!entry)
- return false;
-
+++ /dev/null
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Mon, 28 Aug 2023 09:54:39 +0200
-Subject: [PATCH] wifi: cfg80211: annotate iftype_data pointer with sparse
-
-There were are a number of cases in mac80211 and iwlwifi (at
-least) that used the sband->iftype_data pointer directly,
-instead of using the accessors to find the right array entry
-to use.
-
-Make sparse warn when such a thing is done.
-
-To not have a lot of casts, add two helper functions/macros
-
- - ieee80211_set_sband_iftype_data()
- - for_each_sband_iftype_data()
-
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -5893,8 +5893,9 @@ static void ath11k_mac_setup_he_cap(stru
- ar->mac.iftype[NL80211_BAND_2GHZ],
- NL80211_BAND_2GHZ);
- band = &ar->mac.sbands[NL80211_BAND_2GHZ];
-- band->iftype_data = ar->mac.iftype[NL80211_BAND_2GHZ];
-- band->n_iftype_data = count;
-+ _ieee80211_set_sband_iftype_data(band,
-+ ar->mac.iftype[NL80211_BAND_2GHZ],
-+ count);
- }
-
- if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) {
-@@ -5902,8 +5903,9 @@ static void ath11k_mac_setup_he_cap(stru
- ar->mac.iftype[NL80211_BAND_5GHZ],
- NL80211_BAND_5GHZ);
- band = &ar->mac.sbands[NL80211_BAND_5GHZ];
-- band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ];
-- band->n_iftype_data = count;
-+ _ieee80211_set_sband_iftype_data(band,
-+ ar->mac.iftype[NL80211_BAND_5GHZ],
-+ count);
- }
-
- if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP &&
-@@ -5912,8 +5914,9 @@ static void ath11k_mac_setup_he_cap(stru
- ar->mac.iftype[NL80211_BAND_6GHZ],
- NL80211_BAND_6GHZ);
- band = &ar->mac.sbands[NL80211_BAND_6GHZ];
-- band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ];
-- band->n_iftype_data = count;
-+ _ieee80211_set_sband_iftype_data(band,
-+ ar->mac.iftype[NL80211_BAND_6GHZ],
-+ count);
- }
- }
-
---- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
-+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
-@@ -1078,8 +1078,8 @@ static void iwl_init_he_hw_capab(struct
-
- memcpy(iftype_data, iwl_he_eht_capa, sizeof(iwl_he_eht_capa));
-
-- sband->iftype_data = iftype_data;
-- sband->n_iftype_data = ARRAY_SIZE(iwl_he_eht_capa);
-+ _ieee80211_set_sband_iftype_data(sband, iftype_data,
-+ ARRAY_SIZE(iwl_he_eht_capa));
-
- for (i = 0; i < sband->n_iftype_data; i++)
- iwl_nvm_fixup_sband_iftd(trans, data, sband, &iftype_data[i],
---- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
-+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
-@@ -1127,8 +1127,7 @@ void mt7915_set_stream_he_caps(struct mt
- n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data);
-
- band = &phy->mt76->sband_2g.sband;
-- band->iftype_data = data;
-- band->n_iftype_data = n;
-+ _ieee80211_set_sband_iftype_data(band, data, n);
- }
-
- if (phy->mt76->cap.has_5ghz) {
-@@ -1136,8 +1135,7 @@ void mt7915_set_stream_he_caps(struct mt
- n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data);
-
- band = &phy->mt76->sband_5g.sband;
-- band->iftype_data = data;
-- band->n_iftype_data = n;
-+ _ieee80211_set_sband_iftype_data(band, data, n);
- }
-
- if (phy->mt76->cap.has_6ghz) {
-@@ -1145,8 +1143,7 @@ void mt7915_set_stream_he_caps(struct mt
- n = mt7915_init_he_caps(phy, NL80211_BAND_6GHZ, data);
-
- band = &phy->mt76->sband_6g.sband;
-- band->iftype_data = data;
-- band->n_iftype_data = n;
-+ _ieee80211_set_sband_iftype_data(band, data, n);
- }
- }
-
---- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
-+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
-@@ -196,8 +196,7 @@ void mt7921_set_stream_he_caps(struct mt
- n = mt7921_init_he_caps(phy, NL80211_BAND_2GHZ, data);
-
- band = &phy->mt76->sband_2g.sband;
-- band->iftype_data = data;
-- band->n_iftype_data = n;
-+ _ieee80211_set_sband_iftype_data(band, data, n);
- }
-
- if (phy->mt76->cap.has_5ghz) {
-@@ -205,16 +204,14 @@ void mt7921_set_stream_he_caps(struct mt
- n = mt7921_init_he_caps(phy, NL80211_BAND_5GHZ, data);
-
- band = &phy->mt76->sband_5g.sband;
-- band->iftype_data = data;
-- band->n_iftype_data = n;
-+ _ieee80211_set_sband_iftype_data(band, data, n);
-
- if (phy->mt76->cap.has_6ghz) {
- data = phy->iftype[NL80211_BAND_6GHZ];
- n = mt7921_init_he_caps(phy, NL80211_BAND_6GHZ, data);
-
- band = &phy->mt76->sband_6g.sband;
-- band->iftype_data = data;
-- band->n_iftype_data = n;
-+ _ieee80211_set_sband_iftype_data(band, data, n);
- }
- }
- }
---- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
-+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
-@@ -828,8 +828,7 @@ __mt7996_set_stream_he_eht_caps(struct m
- n++;
- }
-
-- sband->iftype_data = data;
-- sband->n_iftype_data = n;
-+ _ieee80211_set_sband_iftype_data(sband, data, n);
- }
-
- void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy)
---- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
-+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
-@@ -1335,7 +1335,7 @@ static int qtnf_cmd_band_fill_iftype(con
- return -EINVAL;
- }
-
-- kfree(band->iftype_data);
-+ kfree((__force void *)band->iftype_data);
- band->iftype_data = NULL;
- band->n_iftype_data = tlv->n_iftype_data;
- if (band->n_iftype_data == 0)
-@@ -1347,7 +1347,8 @@ static int qtnf_cmd_band_fill_iftype(con
- band->n_iftype_data = 0;
- return -ENOMEM;
- }
-- band->iftype_data = iftype_data;
-+
-+ _ieee80211_set_sband_iftype_data(band, iftype_data, tlv->n_iftype_data);
-
- for (i = 0; i < band->n_iftype_data; i++)
- qtnf_cmd_conv_iftype(iftype_data++, &tlv->iftype_data[i]);
---- a/drivers/net/wireless/quantenna/qtnfmac/core.c
-+++ b/drivers/net/wireless/quantenna/qtnfmac/core.c
-@@ -549,7 +549,7 @@ static void qtnf_core_mac_detach(struct
- if (!wiphy->bands[band])
- continue;
-
-- kfree(wiphy->bands[band]->iftype_data);
-+ kfree((__force void *)wiphy->bands[band]->iftype_data);
- wiphy->bands[band]->n_iftype_data = 0;
-
- kfree(wiphy->bands[band]->channels);
---- a/drivers/net/wireless/realtek/rtw89/core.c
-+++ b/drivers/net/wireless/realtek/rtw89/core.c
-@@ -3359,8 +3359,7 @@ static void rtw89_init_he_cap(struct rtw
- idx++;
- }
-
-- sband->iftype_data = iftype_data;
-- sband->n_iftype_data = idx;
-+ _ieee80211_set_sband_iftype_data(sband, iftype_data, idx);
- }
-
- static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
-@@ -3405,11 +3404,11 @@ err:
- hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
- hw->wiphy->bands[NL80211_BAND_6GHZ] = NULL;
- if (sband_2ghz)
-- kfree(sband_2ghz->iftype_data);
-+ kfree((__force void *)sband_2ghz->iftype_data);
- if (sband_5ghz)
-- kfree(sband_5ghz->iftype_data);
-+ kfree((__force void *)sband_5ghz->iftype_data);
- if (sband_6ghz)
-- kfree(sband_6ghz->iftype_data);
-+ kfree((__force void *)sband_6ghz->iftype_data);
- kfree(sband_2ghz);
- kfree(sband_5ghz);
- kfree(sband_6ghz);
-@@ -3421,11 +3420,11 @@ static void rtw89_core_clr_supported_ban
- struct ieee80211_hw *hw = rtwdev->hw;
-
- if (hw->wiphy->bands[NL80211_BAND_2GHZ])
-- kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
-+ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
- if (hw->wiphy->bands[NL80211_BAND_5GHZ])
-- kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
-+ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
- if (hw->wiphy->bands[NL80211_BAND_6GHZ])
-- kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data);
-+ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data);
- kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]);
- kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
- kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]);
---- a/drivers/net/wireless/realtek/rtw89/regd.c
-+++ b/drivers/net/wireless/realtek/rtw89/regd.c
-@@ -377,7 +377,7 @@ bottom:
- return;
-
- wiphy->bands[NL80211_BAND_6GHZ] = NULL;
-- kfree(sband->iftype_data);
-+ kfree((__force void *)sband->iftype_data);
- kfree(sband);
- }
-
---- a/drivers/net/wireless/virtual/mac80211_hwsim.c
-+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
-@@ -4899,25 +4899,19 @@ static const struct ieee80211_sband_ifty
-
- static void mac80211_hwsim_sband_capab(struct ieee80211_supported_band *sband)
- {
-- u16 n_iftype_data;
--
-- if (sband->band == NL80211_BAND_2GHZ) {
-- n_iftype_data = ARRAY_SIZE(sband_capa_2ghz);
-- sband->iftype_data =
-- (struct ieee80211_sband_iftype_data *)sband_capa_2ghz;
-- } else if (sband->band == NL80211_BAND_5GHZ) {
-- n_iftype_data = ARRAY_SIZE(sband_capa_5ghz);
-- sband->iftype_data =
-- (struct ieee80211_sband_iftype_data *)sband_capa_5ghz;
-- } else if (sband->band == NL80211_BAND_6GHZ) {
-- n_iftype_data = ARRAY_SIZE(sband_capa_6ghz);
-- sband->iftype_data =
-- (struct ieee80211_sband_iftype_data *)sband_capa_6ghz;
-- } else {
-- return;
-+ switch (sband->band) {
-+ case NL80211_BAND_2GHZ:
-+ ieee80211_set_sband_iftype_data(sband, sband_capa_2ghz);
-+ break;
-+ case NL80211_BAND_5GHZ:
-+ ieee80211_set_sband_iftype_data(sband, sband_capa_5ghz);
-+ break;
-+ case NL80211_BAND_6GHZ:
-+ ieee80211_set_sband_iftype_data(sband, sband_capa_6ghz);
-+ break;
-+ default:
-+ break;
- }
--
-- sband->n_iftype_data = n_iftype_data;
- }
-
- #ifdef CPTCFG_MAC80211_MESH
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -415,6 +415,19 @@ struct ieee80211_sta_eht_cap {
- u8 eht_ppe_thres[IEEE80211_EHT_PPE_THRES_MAX_LEN];
- };
-
-+/* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */
-+#ifdef __CHECKER__
-+/*
-+ * This is used to mark the sband->iftype_data pointer which is supposed
-+ * to be an array with special access semantics (per iftype), but a lot
-+ * of code got it wrong in the past, so with this marking sparse will be
-+ * noisy when the pointer is used directly.
-+ */
-+# define __iftd __attribute__((noderef, address_space(__iftype_data)))
-+#else
-+# define __iftd
-+#endif /* __CHECKER__ */
-+
- /**
- * struct ieee80211_sband_iftype_data - sband data per interface type
- *
-@@ -548,10 +561,48 @@ struct ieee80211_supported_band {
- struct ieee80211_sta_s1g_cap s1g_cap;
- struct ieee80211_edmg edmg_cap;
- u16 n_iftype_data;
-- const struct ieee80211_sband_iftype_data *iftype_data;
-+ const struct ieee80211_sband_iftype_data __iftd *iftype_data;
- };
-
- /**
-+ * _ieee80211_set_sband_iftype_data - set sband iftype data array
-+ * @sband: the sband to initialize
-+ * @iftd: the iftype data array pointer
-+ * @n_iftd: the length of the iftype data array
-+ *
-+ * Set the sband iftype data array; use this where the length cannot
-+ * be derived from the ARRAY_SIZE() of the argument, but prefer
-+ * ieee80211_set_sband_iftype_data() where it can be used.
-+ */
-+static inline void
-+_ieee80211_set_sband_iftype_data(struct ieee80211_supported_band *sband,
-+ const struct ieee80211_sband_iftype_data *iftd,
-+ u16 n_iftd)
-+{
-+ sband->iftype_data = (const void __iftd __force *)iftd;
-+ sband->n_iftype_data = n_iftd;
-+}
-+
-+/**
-+ * ieee80211_set_sband_iftype_data - set sband iftype data array
-+ * @sband: the sband to initialize
-+ * @iftd: the iftype data array
-+ */
-+#define ieee80211_set_sband_iftype_data(sband, iftd) \
-+ _ieee80211_set_sband_iftype_data(sband, iftd, ARRAY_SIZE(iftd))
-+
-+/**
-+ * for_each_sband_iftype_data - iterate sband iftype data entries
-+ * @sband: the sband whose iftype_data array to iterate
-+ * @i: iterator counter
-+ * @iftd: iftype data pointer to set
-+ */
-+#define for_each_sband_iftype_data(sband, i, iftd) \
-+ for (i = 0, iftd = (const void __force *)&(sband)->iftype_data[i]; \
-+ i < (sband)->n_iftype_data; \
-+ i++, iftd = (const void __force *)&(sband)->iftype_data[i])
-+
-+/**
- * ieee80211_get_sband_iftype_data - return sband data for a given iftype
- * @sband: the sband to search for the STA on
- * @iftype: enum nl80211_iftype
-@@ -562,6 +613,7 @@ static inline const struct ieee80211_sba
- ieee80211_get_sband_iftype_data(const struct ieee80211_supported_band *sband,
- u8 iftype)
- {
-+ const struct ieee80211_sband_iftype_data *data;
- int i;
-
- if (WARN_ON(iftype >= NL80211_IFTYPE_MAX))
-@@ -570,10 +622,7 @@ ieee80211_get_sband_iftype_data(const st
- if (iftype == NL80211_IFTYPE_AP_VLAN)
- iftype = NL80211_IFTYPE_AP;
-
-- for (i = 0; i < sband->n_iftype_data; i++) {
-- const struct ieee80211_sband_iftype_data *data =
-- &sband->iftype_data[i];
--
-+ for_each_sband_iftype_data(sband, i, data) {
- if (data->types_mask & BIT(iftype))
- return data;
- }
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -1052,6 +1052,7 @@ int ieee80211_register_hw(struct ieee802
- supp_he = false;
- supp_eht = false;
- for (band = 0; band < NUM_NL80211_BANDS; band++) {
-+ const struct ieee80211_sband_iftype_data *iftd;
- struct ieee80211_supported_band *sband;
-
- sband = local->hw.wiphy->bands[band];
-@@ -1098,11 +1099,7 @@ int ieee80211_register_hw(struct ieee802
- supp_ht = supp_ht || sband->ht_cap.ht_supported;
- supp_vht = supp_vht || sband->vht_cap.vht_supported;
-
-- for (i = 0; i < sband->n_iftype_data; i++) {
-- const struct ieee80211_sband_iftype_data *iftd;
--
-- iftd = &sband->iftype_data[i];
--
-+ for_each_sband_iftype_data(sband, i, iftd) {
- supp_he = supp_he || iftd->he_cap.has_he;
- supp_eht = supp_eht || iftd->eht_cap.has_eht;
- }
---- a/net/wireless/chan.c
-+++ b/net/wireless/chan.c
-@@ -6,7 +6,7 @@
- *
- * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2013-2014 Intel Mobile Communications GmbH
-- * Copyright 2018-2022 Intel Corporation
-+ * Copyright 2018-2023 Intel Corporation
- */
-
- #include <linux/export.h>
-@@ -1162,8 +1162,7 @@ bool cfg80211_chandef_usable(struct wiph
- if (!sband)
- return false;
-
-- for (i = 0; i < sband->n_iftype_data; i++) {
-- iftd = &sband->iftype_data[i];
-+ for_each_sband_iftype_data(sband, i, iftd) {
- if (!iftd->eht_cap.has_eht)
- continue;
-
---- a/net/wireless/core.c
-+++ b/net/wireless/core.c
-@@ -5,7 +5,7 @@
- * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2013-2014 Intel Mobile Communications GmbH
- * Copyright 2015-2017 Intel Deutschland GmbH
-- * Copyright (C) 2018-2022 Intel Corporation
-+ * Copyright (C) 2018-2023 Intel Corporation
- */
-
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-@@ -819,6 +819,7 @@ int wiphy_register(struct wiphy *wiphy)
-
- /* sanity check supported bands/channels */
- for (band = 0; band < NUM_NL80211_BANDS; band++) {
-+ const struct ieee80211_sband_iftype_data *iftd;
- u16 types = 0;
- bool have_he = false;
-
-@@ -875,14 +876,11 @@ int wiphy_register(struct wiphy *wiphy)
- return -EINVAL;
- }
-
-- for (i = 0; i < sband->n_iftype_data; i++) {
-- const struct ieee80211_sband_iftype_data *iftd;
-+ for_each_sband_iftype_data(sband, i, iftd) {
- bool has_ap, has_non_ap;
- u32 ap_bits = BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_P2P_GO);
-
-- iftd = &sband->iftype_data[i];
--
- if (WARN_ON(!iftd->types_mask))
- return -EINVAL;
- if (WARN_ON(types & iftd->types_mask))
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -1907,20 +1907,20 @@ static int nl80211_send_band_rateinfo(st
- struct nlattr *nl_iftype_data =
- nla_nest_start_noflag(msg,
- NL80211_BAND_ATTR_IFTYPE_DATA);
-+ const struct ieee80211_sband_iftype_data *iftd;
- int err;
-
- if (!nl_iftype_data)
- return -ENOBUFS;
-
-- for (i = 0; i < sband->n_iftype_data; i++) {
-+ for_each_sband_iftype_data(sband, i, iftd) {
- struct nlattr *iftdata;
-
- iftdata = nla_nest_start_noflag(msg, i + 1);
- if (!iftdata)
- return -ENOBUFS;
-
-- err = nl80211_send_iftype_data(msg, sband,
-- &sband->iftype_data[i]);
-+ err = nl80211_send_iftype_data(msg, sband, iftd);
- if (err)
- return err;
-
+++ /dev/null
-From 30ca8b0c4d6c9fb1d76e5894b1e8bf7c6a12224d Mon Sep 17 00:00:00 2001
-From: Aditya Kumar Singh <quic_adisi@quicinc.com>
-Date: Tue, 12 Sep 2023 10:48:55 +0530
-Subject: [PATCH] wifi: cfg80211: export DFS CAC time and usable state helper
- functions
-
-cfg80211 has cfg80211_chandef_dfs_usable() function to know whether
-at least one channel in the chandef is in usable state or not. Also,
-cfg80211_chandef_dfs_cac_time() function is there which tells the CAC
-time required for the given chandef.
-
-Make these two functions visible to drivers by exporting their symbol
-to global list of kernel symbols.
-
-Lower level drivers can make use of these two functions to be aware
-if CAC is required on the given chandef and for how long. For example
-drivers which maintains the CAC state internally can make use of these.
-
-Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
-Reviewed-by: Jeff Johnson <quic_jjohnson@quicinc.com>
-Link: https://lore.kernel.org/r/20230912051857.2284-2-quic_adisi@quicinc.com
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
- include/net/cfg80211.h | 24 ++++++++++++++++++++++++
- net/wireless/chan.c | 2 ++
- net/wireless/core.h | 17 -----------------
- 3 files changed, 26 insertions(+), 17 deletions(-)
-
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -1008,6 +1008,30 @@ int cfg80211_chandef_dfs_required(struct
- enum nl80211_iftype iftype);
-
- /**
-+ * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable and we
-+ * can/need start CAC on such channel
-+ * @wiphy: the wiphy to validate against
-+ * @chandef: the channel definition to check
-+ *
-+ * Return: true if all channels available and at least
-+ * one channel requires CAC (NL80211_DFS_USABLE)
-+ */
-+bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
-+ const struct cfg80211_chan_def *chandef);
-+
-+/**
-+ * cfg80211_chandef_dfs_cac_time - get the DFS CAC time (in ms) for given
-+ * channel definition
-+ * @wiphy: the wiphy to validate against
-+ * @chandef: the channel definition to check
-+ *
-+ * Returns: DFS CAC time (in ms) which applies for this channel definition
-+ */
-+unsigned int
-+cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
-+ const struct cfg80211_chan_def *chandef);
-+
-+/**
- * nl80211_send_chandef - sends the channel definition.
- * @msg: the msg to send channel definition
- * @chandef: the channel definition to check
---- a/net/wireless/chan.c
-+++ b/net/wireless/chan.c
-@@ -666,6 +666,7 @@ bool cfg80211_chandef_dfs_usable(struct
-
- return (r1 + r2 > 0);
- }
-+EXPORT_SYMBOL(cfg80211_chandef_dfs_usable);
-
- /*
- * Checks if center frequency of chan falls with in the bandwidth
-@@ -965,6 +966,7 @@ cfg80211_chandef_dfs_cac_time(struct wip
-
- return max(t1, t2);
- }
-+EXPORT_SYMBOL(cfg80211_chandef_dfs_cac_time);
-
- static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
- u32 center_freq, u32 bandwidth,
---- a/net/wireless/core.h
-+++ b/net/wireless/core.h
-@@ -476,29 +476,12 @@ int cfg80211_scan(struct cfg80211_regist
-
- extern struct work_struct cfg80211_disconnect_work;
-
--/**
-- * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable
-- * @wiphy: the wiphy to validate against
-- * @chandef: the channel definition to check
-- *
-- * Checks if chandef is usable and we can/need start CAC on such channel.
-- *
-- * Return: true if all channels available and at least
-- * one channel requires CAC (NL80211_DFS_USABLE)
-- */
--bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
-- const struct cfg80211_chan_def *chandef);
--
- void cfg80211_set_dfs_state(struct wiphy *wiphy,
- const struct cfg80211_chan_def *chandef,
- enum nl80211_dfs_state dfs_state);
-
- void cfg80211_dfs_channels_update_work(struct work_struct *work);
-
--unsigned int
--cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
-- const struct cfg80211_chan_def *chandef);
--
- void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
-
- int
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Wed, 3 Jan 2024 15:10:18 +0100
-Subject: [PATCH] wifi: mac80211: fix race condition on enabling fast-xmit
-
-fast-xmit must only be enabled after the sta has been uploaded to the driver,
-otherwise it could end up passing the not-yet-uploaded sta via drv_tx calls
-to the driver, leading to potential crashes because of uninitialized drv_priv
-data.
-Add a missing sta->uploaded check and re-check fast xmit after inserting a sta.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -918,6 +918,7 @@ static int sta_info_insert_finish(struct
-
- if (ieee80211_vif_is_mesh(&sdata->vif))
- mesh_accept_plinks_update(sdata);
-+ ieee80211_check_fast_xmit(sta);
-
- return 0;
- out_remove:
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3034,7 +3034,7 @@ void ieee80211_check_fast_xmit(struct st
- sdata->vif.type == NL80211_IFTYPE_STATION)
- goto out;
-
-- if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-+ if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED) || !sta->uploaded)
- goto out;
-
- if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
-@@ -175,6 +175,8 @@ enum ieee80211_channel_flags {
+@@ -189,6 +189,8 @@ enum ieee80211_channel_flags {
* @dfs_state: current state of this channel. Only relevant if radar is required
* on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
+ * @dfs_state_last_available: timestamp (jiffies) of the last time when the
+ * channel was available.
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
+ * @psd: power spectral density (in dBm)
*/
- struct ieee80211_channel {
-@@ -191,6 +193,7 @@ struct ieee80211_channel {
+@@ -206,6 +208,7 @@ struct ieee80211_channel {
int orig_mag, orig_mpwr;
enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered;
+ unsigned long dfs_state_last_available;
unsigned int dfs_cac_ms;
+ s8 psd;
};
-
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -30,6 +30,9 @@ static int ___cfg80211_stop_ap(struct cf
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
-@@ -461,6 +461,8 @@ static void cfg80211_set_chans_dfs_state
+@@ -560,6 +560,8 @@ static void cfg80211_set_chans_dfs_state
c->dfs_state = dfs_state;
c->dfs_state_entered = jiffies;
}
}
-@@ -874,6 +876,49 @@ static bool cfg80211_get_chans_dfs_avail
+@@ -1049,6 +1051,49 @@ static bool cfg80211_get_chans_dfs_avail
return true;
}
{
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
-@@ -481,6 +481,8 @@ void cfg80211_set_dfs_state(struct wiphy
+@@ -467,6 +467,8 @@ void cfg80211_set_dfs_state(struct wiphy
enum nl80211_dfs_state dfs_state);
void cfg80211_dfs_channels_update_work(struct work_struct *work);
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
-@@ -930,6 +930,8 @@ void cfg80211_dfs_channels_update_work(s
+@@ -1037,6 +1037,8 @@ void cfg80211_dfs_channels_update_work(s
if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
radar_event = NL80211_RADAR_NOP_FINISHED;
} else {
if (regulatory_pre_cac_allowed(wiphy) ||
cfg80211_any_wiphy_oper_chan(wiphy, c))
-@@ -937,11 +939,10 @@ void cfg80211_dfs_channels_update_work(s
+@@ -1044,11 +1046,10 @@ void cfg80211_dfs_channels_update_work(s
time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS;
radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
-@@ -3324,6 +3324,7 @@ enum wiphy_params_flags {
+@@ -3416,6 +3416,7 @@ enum wiphy_params_flags {
/* The per TXQ device queue limit in airtime */
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000
#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -1328,10 +1328,12 @@ struct ieee80211_local {
+@@ -1338,10 +1338,12 @@ struct ieee80211_local {
spinlock_t handle_wake_tx_queue_lock;
u16 airtime_flags;
const struct ieee80211_ops *ops;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
-@@ -788,6 +788,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+@@ -944,6 +944,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
spin_lock_init(&local->rx_path_lock);
spin_lock_init(&local->queue_stop_reason_lock);
spin_lock_init(&local->active_txq_lock[i]);
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -2343,13 +2343,28 @@ EXPORT_SYMBOL(ieee80211_sta_recalc_aggre
+@@ -2357,13 +2357,28 @@ EXPORT_SYMBOL(ieee80211_sta_recalc_aggre
void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
struct sta_info *sta, u8 ac,
atomic_add(tx_airtime,
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -2536,7 +2536,7 @@ static u16 ieee80211_store_ack_skb(struc
+@@ -2554,7 +2554,7 @@ static u16 ieee80211_store_ack_skb(struc
spin_lock_irqsave(&local->ack_status_lock, flags);
id = idr_alloc(&local->ack_status_frames, ack_skb,
spin_unlock_irqrestore(&local->ack_status_lock, flags);
if (id >= 0) {
-@@ -3958,20 +3958,20 @@ begin:
+@@ -3983,20 +3983,20 @@ begin:
encap_out:
- IEEE80211_SKB_CB(skb)->control.vif = vif;
+ info->control.vif = vif;
- if (tx.sta &&
- wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
}
return skb;
-@@ -4026,6 +4026,7 @@ struct ieee80211_txq *ieee80211_next_txq
+@@ -4048,6 +4048,7 @@ struct ieee80211_txq *ieee80211_next_txq
struct ieee80211_txq *ret = NULL;
struct txq_info *txqi = NULL, *head = NULL;
bool found_eligible_txq = false;
spin_lock_bh(&local->active_txq_lock[ac]);
-@@ -4049,26 +4050,26 @@ struct ieee80211_txq *ieee80211_next_txq
+@@ -4071,26 +4072,26 @@ struct ieee80211_txq *ieee80211_next_txq
if (!head)
head = txqi;
if (txqi->schedule_round == local->schedule_round[ac])
goto out;
-@@ -4133,7 +4134,8 @@ bool ieee80211_txq_airtime_check(struct
+@@ -4155,7 +4156,8 @@ bool ieee80211_txq_airtime_check(struct
return true;
if (!txq->sta)
if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
return true;
-@@ -4182,15 +4184,15 @@ bool ieee80211_txq_may_transmit(struct i
+@@ -4204,15 +4206,15 @@ bool ieee80211_txq_may_transmit(struct i
spin_lock_bh(&local->active_txq_lock[ac]);
if (iter == txqi)
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -1116,6 +1116,7 @@ ieee80211_rate_get_vht_nss(const struct
- * link the frame will be transmitted on
- * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC
- * @ack_frame_id: internal frame ID for TX status, used internally
-+ * @tx_time_mc: TX time is for a multicast packet
- * @tx_time_est: TX time estimate in units of 4us, used internally
- * @control: union part for control data
- * @control.rates: TX rates array to try
-@@ -1155,8 +1156,9 @@ struct ieee80211_tx_info {
- /* common information */
- u32 flags;
- u32 band:3,
-- ack_frame_id:13,
-+ ack_frame_id:12,
+@@ -1180,8 +1180,8 @@ struct ieee80211_tx_info {
+ status_data_idr:1,
+ status_data:13,
hw_queue:4,
+ tx_time_mc:1,
tx_time_est:10;
- /* 2 free bits */
+- /* 1 free bit */
+ union {
+ struct {
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -147,7 +147,8 @@ struct airtime_info {
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
-@@ -716,7 +716,7 @@ static void ieee80211_report_used_skb(st
+@@ -717,7 +717,7 @@ static void ieee80211_report_used_skb(st
ieee80211_sta_update_pending_airtime(local, sta,
skb_get_queue_mapping(skb),
tx_time_est,
rcu_read_unlock();
}
-@@ -1127,10 +1127,11 @@ void ieee80211_tx_status_ext(struct ieee
+@@ -1138,10 +1138,11 @@ void ieee80211_tx_status_ext(struct ieee
/* Do this here to avoid the expensive lookup of the sta
* in ieee80211_report_used_skb().
*/
--- /dev/null
+From: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Date: Tue, 26 Mar 2024 08:30:36 +0800
+Subject: [PATCH] wifi: mac80211: extend IEEE80211_KEY_FLAG_GENERATE_MMIE to
+ other ciphers
+
+Extend the flag IEEE80211_KEY_FLAG_GENERATE_MMIE to BIP-CMAC-256,
+BIP-GMAC-128 and BIP-GMAC-256 for the same reason and in the same
+way that the flag was added originally in commit a0b4496a4368
+("mac80211: add IEEE80211_KEY_FLAG_GENERATE_MMIE to ieee80211_key_flags").
+
+Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Link: https://msgid.link/20240326003036.15215-1-michael-cy.lee@mediatek.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -2123,8 +2123,8 @@ static inline bool lockdep_vif_wiphy_mut
+ * @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key.
+ * @IEEE80211_KEY_FLAG_NO_AUTO_TX: Key needs explicit Tx activation.
+ * @IEEE80211_KEY_FLAG_GENERATE_MMIE: This flag should be set by the driver
+- * for a AES_CMAC key to indicate that it requires sequence number
+- * generation only
++ * for a AES_CMAC or a AES_GMAC key to indicate that it requires sequence
++ * number generation only
+ * @IEEE80211_KEY_FLAG_SPP_AMSDU: SPP A-MSDUs can be used with this key
+ * (set by mac80211 from the sta->spp_amsdu flag)
+ */
+--- a/net/mac80211/wpa.c
++++ b/net/mac80211/wpa.c
+@@ -895,7 +895,8 @@ ieee80211_crypto_aes_cmac_256_encrypt(st
+
+ info = IEEE80211_SKB_CB(skb);
+
+- if (info->control.hw_key)
++ if (info->control.hw_key &&
++ !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIE))
+ return TX_CONTINUE;
+
+ if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
+@@ -911,6 +912,9 @@ ieee80211_crypto_aes_cmac_256_encrypt(st
+
+ bip_ipn_set64(mmie->sequence_number, pn64);
+
++ if (info->control.hw_key)
++ return TX_CONTINUE;
++
+ bip_aad(skb, aad);
+
+ /* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128)
+@@ -1040,7 +1044,8 @@ ieee80211_crypto_aes_gmac_encrypt(struct
+
+ info = IEEE80211_SKB_CB(skb);
+
+- if (info->control.hw_key)
++ if (info->control.hw_key &&
++ !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIE))
+ return TX_CONTINUE;
+
+ if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
+@@ -1056,6 +1061,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct
+
+ bip_ipn_set64(mmie->sequence_number, pn64);
+
++ if (info->control.hw_key)
++ return TX_CONTINUE;
++
+ bip_aad(skb, aad);
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Wed, 21 Feb 2024 14:41:40 +0100
-Subject: [PATCH] wifi: mac80211: only call drv_sta_rc_update for uploaded
- stations
-
-When a station has not been uploaded yet, receiving SMPS or channel width
-notification action frames can lead to rate_control_rate_update calling
-drv_sta_rc_update with uninitialized driver private data.
-Fix this by adding a missing check for sta->uploaded.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rate.c
-+++ b/net/mac80211/rate.c
-@@ -119,7 +119,8 @@ void rate_control_rate_update(struct iee
- rcu_read_unlock();
- }
-
-- drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
-+ if (sta->uploaded)
-+ drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
- }
-
- int ieee80211_rate_control_register(const struct rate_control_ops *ops)
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 16 Mar 2024 08:37:21 +0100
-Subject: [PATCH] wifi: mac80211: check/clear fast rx for non-4addr sta VLAN
- changes
-
-When moving a station out of a VLAN and deleting the VLAN afterwards, the
-fast_rx entry still holds a pointer to the VLAN's netdev, which can cause
-use-after-free bugs. Fix this by immediately calling ieee80211_check_fast_rx
-after the VLAN change.
-
-Cc: stable@vger.kernel.org
-Reported-by: ranygh@riseup.net
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -2184,15 +2184,14 @@ static int ieee80211_change_station(stru
- }
-
- if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-- sta->sdata->u.vlan.sta) {
-- ieee80211_clear_fast_rx(sta);
-+ sta->sdata->u.vlan.sta)
- RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
-- }
-
- if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
- ieee80211_vif_dec_num_mcast(sta->sdata);
-
- sta->sdata = vlansdata;
-+ ieee80211_check_fast_rx(sta);
- ieee80211_check_fast_xmit(sta);
-
- if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
+++ /dev/null
-From: Michael-CY Lee <michael-cy.lee@mediatek.com>
-Date: Tue, 26 Mar 2024 08:30:36 +0800
-Subject: [PATCH] wifi: mac80211: extend IEEE80211_KEY_FLAG_GENERATE_MMIE to
- other ciphers
-
-Extend the flag IEEE80211_KEY_FLAG_GENERATE_MMIE to BIP-CMAC-256,
-BIP-GMAC-128 and BIP-GMAC-256 for the same reason and in the same
-way that the flag was added originally in commit a0b4496a4368
-("mac80211: add IEEE80211_KEY_FLAG_GENERATE_MMIE to ieee80211_key_flags").
-
-Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
-Link: https://msgid.link/20240326003036.15215-1-michael-cy.lee@mediatek.com
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -2037,8 +2037,8 @@ static inline bool lockdep_vif_mutex_hel
- * @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key.
- * @IEEE80211_KEY_FLAG_NO_AUTO_TX: Key needs explicit Tx activation.
- * @IEEE80211_KEY_FLAG_GENERATE_MMIE: This flag should be set by the driver
-- * for a AES_CMAC key to indicate that it requires sequence number
-- * generation only
-+ * for a AES_CMAC or a AES_GMAC key to indicate that it requires sequence
-+ * number generation only
- */
- enum ieee80211_key_flags {
- IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
---- a/net/mac80211/wpa.c
-+++ b/net/mac80211/wpa.c
-@@ -882,7 +882,8 @@ ieee80211_crypto_aes_cmac_256_encrypt(st
-
- info = IEEE80211_SKB_CB(skb);
-
-- if (info->control.hw_key)
-+ if (info->control.hw_key &&
-+ !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIE))
- return TX_CONTINUE;
-
- if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
-@@ -898,6 +899,9 @@ ieee80211_crypto_aes_cmac_256_encrypt(st
-
- bip_ipn_set64(mmie->sequence_number, pn64);
-
-+ if (info->control.hw_key)
-+ return TX_CONTINUE;
-+
- bip_aad(skb, aad);
-
- /* MIC = AES-256-CMAC(IGTK, AAD || Management Frame Body || MMIE, 128)
-@@ -1027,7 +1031,8 @@ ieee80211_crypto_aes_gmac_encrypt(struct
-
- info = IEEE80211_SKB_CB(skb);
-
-- if (info->control.hw_key)
-+ if (info->control.hw_key &&
-+ !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIE))
- return TX_CONTINUE;
-
- if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
-@@ -1043,6 +1048,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct
-
- bip_ipn_set64(mmie->sequence_number, pn64);
-
-+ if (info->control.hw_key)
-+ return TX_CONTINUE;
-+
- bip_aad(skb, aad);
-
- hdr = (struct ieee80211_hdr *)skb->data;
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 4 Jun 2024 14:31:09 +0200
+Subject: [PATCH] wifi: nl80211: split helper function from
+ nl80211_put_iface_combinations
+
+Create a helper function that puts the data from struct
+ieee80211_iface_combination to a nl80211 message.
+This will be used for adding per-radio interface combination data.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -1620,71 +1620,78 @@ nla_put_failure:
+ return -ENOBUFS;
+ }
+
+-static int nl80211_put_iface_combinations(struct wiphy *wiphy,
+- struct sk_buff *msg,
+- bool large)
++static int nl80211_put_ifcomb_data(struct sk_buff *msg, bool large, int idx,
++ const struct ieee80211_iface_combination *c)
+ {
+- struct nlattr *nl_combis;
+- int i, j;
++ struct nlattr *nl_combi, *nl_limits;
++ int i;
+
+- nl_combis = nla_nest_start_noflag(msg,
+- NL80211_ATTR_INTERFACE_COMBINATIONS);
+- if (!nl_combis)
++ nl_combi = nla_nest_start_noflag(msg, idx);
++ if (!nl_combi)
+ goto nla_put_failure;
+
+- for (i = 0; i < wiphy->n_iface_combinations; i++) {
+- const struct ieee80211_iface_combination *c;
+- struct nlattr *nl_combi, *nl_limits;
++ nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS);
++ if (!nl_limits)
++ goto nla_put_failure;
+
+- c = &wiphy->iface_combinations[i];
++ for (i = 0; i < c->n_limits; i++) {
++ struct nlattr *nl_limit;
+
+- nl_combi = nla_nest_start_noflag(msg, i + 1);
+- if (!nl_combi)
++ nl_limit = nla_nest_start_noflag(msg, i + 1);
++ if (!nl_limit)
+ goto nla_put_failure;
+-
+- nl_limits = nla_nest_start_noflag(msg,
+- NL80211_IFACE_COMB_LIMITS);
+- if (!nl_limits)
++ if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX, c->limits[i].max))
+ goto nla_put_failure;
++ if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
++ c->limits[i].types))
++ goto nla_put_failure;
++ nla_nest_end(msg, nl_limit);
++ }
+
+- for (j = 0; j < c->n_limits; j++) {
+- struct nlattr *nl_limit;
++ nla_nest_end(msg, nl_limits);
+
+- nl_limit = nla_nest_start_noflag(msg, j + 1);
+- if (!nl_limit)
+- goto nla_put_failure;
+- if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX,
+- c->limits[j].max))
+- goto nla_put_failure;
+- if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
+- c->limits[j].types))
+- goto nla_put_failure;
+- nla_nest_end(msg, nl_limit);
+- }
++ if (c->beacon_int_infra_match &&
++ nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
++ goto nla_put_failure;
++ if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
++ c->num_different_channels) ||
++ nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
++ c->max_interfaces))
++ goto nla_put_failure;
++ if (large &&
++ (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
++ c->radar_detect_widths) ||
++ nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
++ c->radar_detect_regions)))
++ goto nla_put_failure;
++ if (c->beacon_int_min_gcd &&
++ nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
++ c->beacon_int_min_gcd))
++ goto nla_put_failure;
+
+- nla_nest_end(msg, nl_limits);
++ nla_nest_end(msg, nl_combi);
+
+- if (c->beacon_int_infra_match &&
+- nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
+- goto nla_put_failure;
+- if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
+- c->num_different_channels) ||
+- nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
+- c->max_interfaces))
+- goto nla_put_failure;
+- if (large &&
+- (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
+- c->radar_detect_widths) ||
+- nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
+- c->radar_detect_regions)))
+- goto nla_put_failure;
+- if (c->beacon_int_min_gcd &&
+- nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
+- c->beacon_int_min_gcd))
+- goto nla_put_failure;
++ return 0;
++nla_put_failure:
++ return -ENOBUFS;
++}
+
+- nla_nest_end(msg, nl_combi);
+- }
++static int nl80211_put_iface_combinations(struct wiphy *wiphy,
++ struct sk_buff *msg,
++ bool large)
++{
++ struct nlattr *nl_combis;
++ int i;
++
++ nl_combis = nla_nest_start_noflag(msg,
++ NL80211_ATTR_INTERFACE_COMBINATIONS);
++ if (!nl_combis)
++ goto nla_put_failure;
++
++ for (i = 0; i < wiphy->n_iface_combinations; i++)
++ if (nl80211_put_ifcomb_data(msg, large, i + 1,
++ &wiphy->iface_combinations[i]))
++ goto nla_put_failure;
+
+ nla_nest_end(msg, nl_combis);
+
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 22 May 2024 11:42:57 +0200
+Subject: [PATCH] wifi: cfg80211: add support for advertising multiple
+ radios belonging to a wiphy
+
+The prerequisite for MLO support in cfg80211/mac80211 is that all the links
+participating in MLO must be from the same wiphy/ieee80211_hw. To meet this
+expectation, some drivers may need to group multiple discrete hardware each
+acting as a link in MLO under single wiphy.
+
+With this change, supported frequencies and interface combinations of each
+individual radio are reported to user space. This allows user space to figure
+out the limitations of what combination of channels can be used concurrently.
+
+Even for non-MLO devices, this improves support for devices capable of
+running on multiple channels at the same time.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -5045,7 +5045,9 @@ struct ieee80211_iface_limit {
+ * struct ieee80211_iface_combination - possible interface combination
+ *
+ * With this structure the driver can describe which interface
+- * combinations it supports concurrently.
++ * combinations it supports concurrently. When set in a struct wiphy_radio,
++ * the combinations refer to combinations of interfaces currently active on
++ * that radio.
+ *
+ * Examples:
+ *
+@@ -5403,6 +5405,38 @@ struct wiphy_iftype_akm_suites {
+ int n_akm_suites;
+ };
+
++/**
++ * struct wiphy_radio_freq_range - wiphy frequency range
++ * @start_freq: start range edge frequency (kHz)
++ * @end_freq: end range edge frequency (kHz)
++ */
++struct wiphy_radio_freq_range {
++ u32 start_freq;
++ u32 end_freq;
++};
++
++
++/**
++ * struct wiphy_radio - physical radio of a wiphy
++ * This structure describes a physical radio belonging to a wiphy.
++ * It is used to describe concurrent-channel capabilities. Only one channel
++ * can be active on the radio described by struct wiphy_radio.
++ *
++ * @freq_range: frequency range that the radio can operate on.
++ * @n_freq_range: number of elements in @freq_range
++ *
++ * @iface_combinations: Valid interface combinations array, should not
++ * list single interface types.
++ * @n_iface_combinations: number of entries in @iface_combinations array.
++ */
++struct wiphy_radio {
++ const struct wiphy_radio_freq_range *freq_range;
++ int n_freq_range;
++
++ const struct ieee80211_iface_combination *iface_combinations;
++ int n_iface_combinations;
++};
++
+ #define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff
+
+ /**
+@@ -5621,6 +5655,9 @@ struct wiphy_iftype_akm_suites {
+ * A value of %CFG80211_HW_TIMESTAMP_ALL_PEERS indicates the driver
+ * supports enabling HW timestamping for all peers (i.e. no need to
+ * specify a mac address).
++ *
++ * @radio: radios belonging to this wiphy
++ * @n_radio: number of radios
+ */
+ struct wiphy {
+ struct mutex mtx;
+@@ -5771,6 +5808,9 @@ struct wiphy {
+
+ u16 hw_timestamp_max_peers;
+
++ int n_radio;
++ const struct wiphy_radio *radio;
++
+ char priv[] __aligned(NETDEV_ALIGN);
+ };
+
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -2061,6 +2061,10 @@ enum nl80211_commands {
+ * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
+ * interface combinations. In each nested item, it contains attributes
+ * defined in &enum nl80211_if_combination_attrs.
++ * If the wiphy uses multiple radios (@NL80211_ATTR_WIPHY_RADIOS is set),
++ * this attribute contains the interface combinations of the first radio.
++ * See @NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS for the global wiphy
++ * combinations for the sum of all radios.
+ * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
+ * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
+ * are managed in software: interfaces of these types aren't subject to
+@@ -2856,6 +2860,14 @@ enum nl80211_commands {
+ * %NL80211_CMD_ASSOCIATE indicating the SPP A-MSDUs
+ * are used on this connection
+ *
++ * @NL80211_ATTR_WIPHY_RADIOS: Nested attribute describing physical radios
++ * belonging to this wiphy. See &enum nl80211_wiphy_radio_attrs.
++ *
++ * @NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS: Nested attribute listing the
++ * supported interface combinations for all radios combined. In each
++ * nested item, it contains attributes defined in
++ * &enum nl80211_if_combination_attrs.
++ *
+ * @NUM_NL80211_ATTR: total number of nl80211_attrs available
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+@@ -3401,6 +3413,9 @@ enum nl80211_attrs {
+
+ NL80211_ATTR_ASSOC_SPP_AMSDU,
+
++ NL80211_ATTR_WIPHY_RADIOS,
++ NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
++
+ /* add attributes here, update the policy in nl80211.c */
+
+ __NL80211_ATTR_AFTER_LAST,
+@@ -7987,4 +8002,54 @@ enum nl80211_ap_settings_flags {
+ NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1,
+ };
+
++/**
++ * enum nl80211_wiphy_radio_attrs - wiphy radio attributes
++ *
++ * @__NL80211_WIPHY_RADIO_ATTR_INVALID: Invalid
++ *
++ * @NL80211_WIPHY_RADIO_ATTR_INDEX: Index of this radio (u32)
++ * @NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE: Frequency range supported by this
++ * radio. Attribute may be present multiple times.
++ * @NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION: Supported interface
++ * combination for this radio. Attribute may be present multiple times
++ * and contains attributes defined in &enum nl80211_if_combination_attrs.
++ *
++ * @__NL80211_WIPHY_RADIO_ATTR_LAST: Internal
++ * @NL80211_WIPHY_RADIO_ATTR_MAX: Highest attribute
++ */
++enum nl80211_wiphy_radio_attrs {
++ __NL80211_WIPHY_RADIO_ATTR_INVALID,
++
++ NL80211_WIPHY_RADIO_ATTR_INDEX,
++ NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE,
++ NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
++
++ /* keep last */
++ __NL80211_WIPHY_RADIO_ATTR_LAST,
++ NL80211_WIPHY_RADIO_ATTR_MAX = __NL80211_WIPHY_RADIO_ATTR_LAST - 1,
++};
++
++/**
++ * enum nl80211_wiphy_radio_freq_range - wiphy radio frequency range
++ *
++ * @__NL80211_WIPHY_RADIO_FREQ_ATTR_INVALID: Invalid
++ *
++ * @NL80211_WIPHY_RADIO_FREQ_ATTR_START: Frequency range start (u32).
++ * The unit is kHz.
++ * @NL80211_WIPHY_RADIO_FREQ_ATTR_END: Frequency range end (u32).
++ * The unit is kHz.
++ *
++ * @__NL80211_WIPHY_RADIO_FREQ_ATTR_LAST: Internal
++ * @NL80211_WIPHY_RADIO_FREQ_ATTR_MAX: Highest attribute
++ */
++enum nl80211_wiphy_radio_freq_range {
++ __NL80211_WIPHY_RADIO_FREQ_ATTR_INVALID,
++
++ NL80211_WIPHY_RADIO_FREQ_ATTR_START,
++ NL80211_WIPHY_RADIO_FREQ_ATTR_END,
++
++ __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST,
++ NL80211_WIPHY_RADIO_FREQ_ATTR_MAX = __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST - 1,
++};
++
+ #endif /* __LINUX_NL80211_H */
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -1621,16 +1621,18 @@ nla_put_failure:
+ }
+
+ static int nl80211_put_ifcomb_data(struct sk_buff *msg, bool large, int idx,
+- const struct ieee80211_iface_combination *c)
++ const struct ieee80211_iface_combination *c,
++ u16 nested)
+ {
+ struct nlattr *nl_combi, *nl_limits;
+ int i;
+
+- nl_combi = nla_nest_start_noflag(msg, idx);
++ nl_combi = nla_nest_start_noflag(msg, idx | nested);
+ if (!nl_combi)
+ goto nla_put_failure;
+
+- nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS);
++ nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS |
++ nested);
+ if (!nl_limits)
+ goto nla_put_failure;
+
+@@ -1678,19 +1680,26 @@ nla_put_failure:
+
+ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
+ struct sk_buff *msg,
+- bool large)
++ int attr, int radio,
++ bool large, u16 nested)
+ {
++ const struct ieee80211_iface_combination *c;
+ struct nlattr *nl_combis;
+- int i;
++ int i, n;
+
+- nl_combis = nla_nest_start_noflag(msg,
+- NL80211_ATTR_INTERFACE_COMBINATIONS);
++ nl_combis = nla_nest_start_noflag(msg, attr | nested);
+ if (!nl_combis)
+ goto nla_put_failure;
+
+- for (i = 0; i < wiphy->n_iface_combinations; i++)
+- if (nl80211_put_ifcomb_data(msg, large, i + 1,
+- &wiphy->iface_combinations[i]))
++ if (radio >= 0) {
++ c = wiphy->radio[0].iface_combinations;
++ n = wiphy->radio[0].n_iface_combinations;
++ } else {
++ c = wiphy->iface_combinations;
++ n = wiphy->n_iface_combinations;
++ }
++ for (i = 0; i < n; i++)
++ if (nl80211_put_ifcomb_data(msg, large, i + 1, &c[i], nested))
+ goto nla_put_failure;
+
+ nla_nest_end(msg, nl_combis);
+@@ -2397,6 +2406,80 @@ fail:
+ return -ENOBUFS;
+ }
+
++static int nl80211_put_radio(struct wiphy *wiphy, struct sk_buff *msg, int idx)
++{
++ const struct wiphy_radio *r = &wiphy->radio[idx];
++ struct nlattr *radio, *freq;
++ int i;
++
++ radio = nla_nest_start(msg, idx);
++ if (!radio)
++ return -ENOBUFS;
++
++ if (nla_put_u32(msg, NL80211_WIPHY_RADIO_ATTR_INDEX, idx))
++ goto nla_put_failure;
++
++ for (i = 0; i < r->n_freq_range; i++) {
++ const struct wiphy_radio_freq_range *range = &r->freq_range[i];
++
++ freq = nla_nest_start(msg, NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE);
++ if (!freq)
++ goto nla_put_failure;
++
++ if (nla_put_u32(msg, NL80211_WIPHY_RADIO_FREQ_ATTR_START,
++ range->start_freq) ||
++ nla_put_u32(msg, NL80211_WIPHY_RADIO_FREQ_ATTR_END,
++ range->end_freq))
++ goto nla_put_failure;
++
++ nla_nest_end(msg, freq);
++ }
++
++ for (i = 0; i < r->n_iface_combinations; i++)
++ if (nl80211_put_ifcomb_data(msg, true,
++ NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
++ &r->iface_combinations[i],
++ NLA_F_NESTED))
++ goto nla_put_failure;
++
++ nla_nest_end(msg, radio);
++
++ return 0;
++
++nla_put_failure:
++ return -ENOBUFS;
++}
++
++static int nl80211_put_radios(struct wiphy *wiphy, struct sk_buff *msg)
++{
++ struct nlattr *radios;
++ int i;
++
++ if (!wiphy->n_radio)
++ return 0;
++
++ radios = nla_nest_start(msg, NL80211_ATTR_WIPHY_RADIOS);
++ if (!radios)
++ return -ENOBUFS;
++
++ for (i = 0; i < wiphy->n_radio; i++)
++ if (nl80211_put_radio(wiphy, msg, i))
++ goto fail;
++
++ nla_nest_end(msg, radios);
++
++ if (nl80211_put_iface_combinations(wiphy, msg,
++ NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
++ -1, true, NLA_F_NESTED))
++ return -ENOBUFS;
++
++ return 0;
++
++fail:
++ nla_nest_cancel(msg, radios);
++ return -ENOBUFS;
++}
++
+ struct nl80211_dump_wiphy_state {
+ s64 filter_wiphy;
+ long start;
+@@ -2692,7 +2775,9 @@ static int nl80211_send_wiphy(struct cfg
+ goto nla_put_failure;
+
+ if (nl80211_put_iface_combinations(&rdev->wiphy, msg,
+- state->split))
++ NL80211_ATTR_INTERFACE_COMBINATIONS,
++ rdev->wiphy.n_radio ? 0 : -1,
++ state->split, 0))
+ goto nla_put_failure;
+
+ state->split_start++;
+@@ -3006,6 +3091,12 @@ static int nl80211_send_wiphy(struct cfg
+ rdev->wiphy.hw_timestamp_max_peers))
+ goto nla_put_failure;
+
++ state->split_start++;
++ break;
++ case 17:
++ if (nl80211_put_radios(&rdev->wiphy, msg))
++ goto nla_put_failure;
++
+ /* done */
+ state->split_start = 0;
+ break;
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 4 Jun 2024 21:01:50 +0200
+Subject: [PATCH] wifi: cfg80211: extend interface combination check for
+ multi-radio
+
+Add a field in struct iface_combination_params to check per-radio
+interface combinations instead of per-wiphy ones.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -1598,6 +1598,7 @@ struct cfg80211_color_change_settings {
+ *
+ * Used to pass interface combination parameters
+ *
++ * @radio_idx: wiphy radio index or -1 for global
+ * @num_different_channels: the number of different channels we want
+ * to use for verification
+ * @radar_detect: a bitmap where each bit corresponds to a channel
+@@ -1611,6 +1612,7 @@ struct cfg80211_color_change_settings {
+ * the verification
+ */
+ struct iface_combination_params {
++ int radio_idx;
+ int num_different_channels;
+ u8 radar_detect;
+ int iftype_num[NUM_NL80211_IFTYPES];
+@@ -4579,6 +4581,8 @@ struct mgmt_frame_regs {
+ *
+ * @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
+ * @set_ttlm: set the TID to link mapping.
++ * @get_radio_mask: get bitmask of radios in use.
++ * (invoked with the wiphy mutex held)
+ */
+ struct cfg80211_ops {
+ int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
+@@ -4940,6 +4944,7 @@ struct cfg80211_ops {
+ struct cfg80211_set_hw_timestamp *hwts);
+ int (*set_ttlm)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ttlm_params *params);
++ u32 (*get_radio_mask)(struct wiphy *wiphy, struct net_device *dev);
+ };
+
+ /*
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -3930,6 +3930,7 @@ int ieee80211_check_combinations(struct
+ int total = 1;
+ struct iface_combination_params params = {
+ .radar_detect = radar_detect,
++ .radio_idx = -1,
+ };
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+@@ -4020,7 +4021,9 @@ int ieee80211_max_num_channels(struct ie
+ struct ieee80211_chanctx *ctx;
+ u32 max_num_different_channels = 1;
+ int err;
+- struct iface_combination_params params = {0};
++ struct iface_combination_params params = {
++ .radio_idx = -1,
++ };
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+--- a/net/wireless/rdev-ops.h
++++ b/net/wireless/rdev-ops.h
+@@ -1542,4 +1542,16 @@ rdev_set_ttlm(struct cfg80211_registered
+
+ return ret;
+ }
++
++static inline u32
++rdev_get_radio_mask(struct cfg80211_registered_device *rdev,
++ struct net_device *dev)
++{
++ struct wiphy *wiphy = &rdev->wiphy;
++
++ if (!rdev->ops->get_radio_mask)
++ return 0;
++
++ return rdev->ops->get_radio_mask(wiphy, dev);
++}
+ #endif /* __CFG80211_RDEV_OPS */
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -2305,13 +2305,16 @@ static int cfg80211_wdev_bi(struct wirel
+
+ static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
+ u32 *beacon_int_gcd,
+- bool *beacon_int_different)
++ bool *beacon_int_different,
++ int radio_idx)
+ {
++ struct cfg80211_registered_device *rdev;
+ struct wireless_dev *wdev;
+
+ *beacon_int_gcd = 0;
+ *beacon_int_different = false;
+
++ rdev = wiphy_to_rdev(wiphy);
+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
+ int wdev_bi;
+
+@@ -2319,6 +2322,11 @@ static void cfg80211_calculate_bi_data(s
+ if (wdev->valid_links)
+ continue;
+
++ /* skip wdevs not active on the given wiphy radio */
++ if (radio_idx >= 0 &&
++ !(rdev_get_radio_mask(rdev, wdev->netdev) & BIT(radio_idx)))
++ continue;
++
+ wdev_bi = cfg80211_wdev_bi(wdev);
+
+ if (!wdev_bi)
+@@ -2366,14 +2374,19 @@ int cfg80211_iter_combinations(struct wi
+ void *data),
+ void *data)
+ {
++ const struct wiphy_radio *radio = NULL;
++ const struct ieee80211_iface_combination *c, *cs;
+ const struct ieee80211_regdomain *regdom;
+ enum nl80211_dfs_regions region = 0;
+- int i, j, iftype;
++ int i, j, n, iftype;
+ int num_interfaces = 0;
+ u32 used_iftypes = 0;
+ u32 beacon_int_gcd;
+ bool beacon_int_different;
+
++ if (params->radio_idx >= 0)
++ radio = &wiphy->radio[params->radio_idx];
++
+ /*
+ * This is a bit strange, since the iteration used to rely only on
+ * the data given by the driver, but here it now relies on context,
+@@ -2385,7 +2398,8 @@ int cfg80211_iter_combinations(struct wi
+ * interfaces (while being brought up) and channel/radar data.
+ */
+ cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
+- &beacon_int_gcd, &beacon_int_different);
++ &beacon_int_gcd, &beacon_int_different,
++ params->radio_idx);
+
+ if (params->radar_detect) {
+ rcu_read_lock();
+@@ -2402,13 +2416,18 @@ int cfg80211_iter_combinations(struct wi
+ used_iftypes |= BIT(iftype);
+ }
+
+- for (i = 0; i < wiphy->n_iface_combinations; i++) {
+- const struct ieee80211_iface_combination *c;
++ if (radio) {
++ cs = radio->iface_combinations;
++ n = radio->n_iface_combinations;
++ } else {
++ cs = wiphy->iface_combinations;
++ n = wiphy->n_iface_combinations;
++ }
++ for (i = 0; i < n; i++) {
+ struct ieee80211_iface_limit *limits;
+ u32 all_iftypes = 0;
+
+- c = &wiphy->iface_combinations[i];
+-
++ c = &cs[i];
+ if (num_interfaces > c->max_interfaces)
+ continue;
+ if (params->num_different_channels > c->num_different_channels)
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 7 Jun 2024 17:58:54 +0200
+Subject: [PATCH] wifi: cfg80211: add helper for checking if a chandef is
+ valid on a radio
+
+Check if the full channel width is in the radio's frequency range.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -6485,6 +6485,15 @@ static inline bool cfg80211_channel_is_p
+ }
+
+ /**
++ * cfg80211_radio_chandef_valid - Check if the radio supports the chandef
++ *
++ * @radio: wiphy radio
++ * @chandef: chandef for current channel
++ */
++bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio,
++ const struct cfg80211_chan_def *chandef);
++
++/**
+ * ieee80211_get_response_rate - get basic rate for a given rate
+ *
+ * @sband: the band to look for rates in
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -2884,3 +2884,38 @@ cfg80211_get_iftype_ext_capa(struct wiph
+ return NULL;
+ }
+ EXPORT_SYMBOL(cfg80211_get_iftype_ext_capa);
++
++static bool
++ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
++ u32 freq, u32 width)
++{
++ const struct wiphy_radio_freq_range *r;
++ int i;
++
++ for (i = 0; i < radio->n_freq_range; i++) {
++ r = &radio->freq_range[i];
++ if (freq - width / 2 >= r->start_freq &&
++ freq + width / 2 <= r->end_freq)
++ return true;
++ }
++
++ return false;
++}
++
++bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio,
++ const struct cfg80211_chan_def *chandef)
++{
++ u32 freq, width;
++
++ freq = ieee80211_chandef_to_khz(chandef);
++ width = nl80211_chan_width_to_mhz(chandef->width);
++ if (!ieee80211_radio_freq_range_valid(radio, freq, width))
++ return false;
++
++ freq = MHZ_TO_KHZ(chandef->center_freq2);
++ if (freq && !ieee80211_radio_freq_range_valid(radio, freq, width))
++ return false;
++
++ return true;
++}
++EXPORT_SYMBOL(cfg80211_radio_chandef_valid);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 6 Jun 2024 12:19:08 +0200
+Subject: [PATCH] wifi: mac80211: add support for DFS with multiple
+ radios
+
+DFS can be supported with multi-channel combinations, as long as each DFS
+capable radio only supports one channel.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -1084,6 +1084,27 @@ static int ieee80211_init_cipher_suites(
+ return 0;
+ }
+
++static bool
++ieee80211_ifcomb_check(const struct ieee80211_iface_combination *c, int n_comb)
++{
++ int i, j;
++
++ for (i = 0; i < n_comb; i++, c++) {
++ /* DFS is not supported with multi-channel combinations yet */
++ if (c->radar_detect_widths &&
++ c->num_different_channels > 1)
++ return false;
++
++ /* mac80211 doesn't support more than one IBSS interface */
++ for (j = 0; j < c->n_limits; j++)
++ if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
++ c->limits[j].max > 1)
++ return false;
++ }
++
++ return true;
++}
++
+ int ieee80211_register_hw(struct ieee80211_hw *hw)
+ {
+ struct ieee80211_local *local = hw_to_local(hw);
+@@ -1173,17 +1194,20 @@ int ieee80211_register_hw(struct ieee802
+ if (comb->num_different_channels > 1)
+ return -EINVAL;
+ }
+- } else {
+- /* DFS is not supported with multi-channel combinations yet */
+- for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
+- const struct ieee80211_iface_combination *comb;
++ }
+
+- comb = &local->hw.wiphy->iface_combinations[i];
++ if (hw->wiphy->n_radio) {
++ for (i = 0; i < hw->wiphy->n_radio; i++) {
++ const struct wiphy_radio *radio = &hw->wiphy->radio[i];
+
+- if (comb->radar_detect_widths &&
+- comb->num_different_channels > 1)
++ if (!ieee80211_ifcomb_check(radio->iface_combinations,
++ radio->n_iface_combinations))
+ return -EINVAL;
+ }
++ } else {
++ if (!ieee80211_ifcomb_check(hw->wiphy->iface_combinations,
++ hw->wiphy->n_iface_combinations))
++ return -EINVAL;
+ }
+
+ /* Only HW csum features are currently compatible with mac80211 */
+@@ -1313,18 +1337,6 @@ int ieee80211_register_hw(struct ieee802
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+ hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
+
+- /* mac80211 doesn't support more than one IBSS interface right now */
+- for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
+- const struct ieee80211_iface_combination *c;
+- int j;
+-
+- c = &hw->wiphy->iface_combinations[i];
+-
+- for (j = 0; j < c->n_limits; j++)
+- if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
+- c->limits[j].max > 1)
+- return -EINVAL;
+- }
+
+ local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) +
+ sizeof(void *) * channels, GFP_KERNEL);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 5 Jun 2024 10:41:34 +0200
+Subject: [PATCH] wifi: mac80211: add radio index to
+ ieee80211_chanctx_conf
+
+Will be used to explicitly assign a channel context to a wiphy radio.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -250,6 +250,7 @@ struct ieee80211_chan_req {
+ * @min_def: the minimum channel definition currently required.
+ * @ap: the channel definition the AP actually is operating as,
+ * for use with (wider bandwidth) OFDMA
++ * @radio_idx: index of the wiphy radio used used for this channel
+ * @rx_chains_static: The number of RX chains that must always be
+ * active on the channel to receive MIMO transmissions
+ * @rx_chains_dynamic: The number of RX chains that must be enabled
+@@ -264,6 +265,7 @@ struct ieee80211_chanctx_conf {
+ struct cfg80211_chan_def min_def;
+ struct cfg80211_chan_def ap;
+
++ int radio_idx;
+ u8 rx_chains_static, rx_chains_dynamic;
+
+ bool radar_enabled;
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -623,7 +623,8 @@ ieee80211_chanctx_radar_required(struct
+ static struct ieee80211_chanctx *
+ ieee80211_alloc_chanctx(struct ieee80211_local *local,
+ const struct ieee80211_chan_req *chanreq,
+- enum ieee80211_chanctx_mode mode)
++ enum ieee80211_chanctx_mode mode,
++ int radio_idx)
+ {
+ struct ieee80211_chanctx *ctx;
+
+@@ -641,6 +642,7 @@ ieee80211_alloc_chanctx(struct ieee80211
+ ctx->conf.rx_chains_dynamic = 1;
+ ctx->mode = mode;
+ ctx->conf.radar_enabled = false;
++ ctx->conf.radio_idx = radio_idx;
+ _ieee80211_recalc_chanctx_min_def(local, ctx, NULL);
+
+ return ctx;
+@@ -680,7 +682,7 @@ ieee80211_new_chanctx(struct ieee80211_l
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+- ctx = ieee80211_alloc_chanctx(local, chanreq, mode);
++ ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+@@ -1098,7 +1100,7 @@ int ieee80211_link_reserve_chanctx(struc
+ !list_empty(&curr_ctx->reserved_links))
+ return -EBUSY;
+
+- new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode);
++ new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
+ if (!new_ctx)
+ return -ENOMEM;
+
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 4 Jun 2024 21:48:48 +0200
+Subject: [PATCH] wifi: mac80211: extend ifcomb check functions for
+ multi-radio
+
+Add support for counting global and per-radio max/current number of
+channels, as well as checking radio-specific interface combinations.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -263,7 +263,7 @@ static int ieee80211_start_p2p_device(st
+
+ lockdep_assert_wiphy(sdata->local->hw.wiphy);
+
+- ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
++ ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
+ if (ret < 0)
+ return ret;
+
+@@ -285,7 +285,7 @@ static int ieee80211_start_nan(struct wi
+
+ lockdep_assert_wiphy(sdata->local->hw.wiphy);
+
+- ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
++ ret = ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
+ if (ret < 0)
+ return ret;
+
+@@ -3992,7 +3992,7 @@ __ieee80211_channel_switch(struct wiphy
+ goto out;
+
+ /* if reservation is invalid then this will fail */
+- err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0);
++ err = ieee80211_check_combinations(sdata, NULL, chanctx->mode, 0, -1);
+ if (err) {
+ ieee80211_link_unreserve_chanctx(link_data);
+ goto out;
+@@ -5161,4 +5161,5 @@ const struct cfg80211_ops mac80211_confi
+ .del_link_station = ieee80211_del_link_station,
+ .set_hw_timestamp = ieee80211_set_hw_timestamp,
+ .set_ttlm = ieee80211_set_ttlm,
++ .get_radio_mask = ieee80211_get_radio_mask,
+ };
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -47,24 +47,29 @@ int ieee80211_chanctx_refcount(struct ie
+ ieee80211_chanctx_num_reserved(local, ctx);
+ }
+
+-static int ieee80211_num_chanctx(struct ieee80211_local *local)
++static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
+ {
+ struct ieee80211_chanctx *ctx;
+ int num = 0;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+- list_for_each_entry(ctx, &local->chanctx_list, list)
++ list_for_each_entry(ctx, &local->chanctx_list, list) {
++ if (radio_idx >= 0 && ctx->conf.radio_idx != radio_idx)
++ continue;
+ num++;
++ }
+
+ return num;
+ }
+
+-static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
++static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local,
++ int radio_idx)
+ {
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+- return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
++ return ieee80211_num_chanctx(local, radio_idx) <
++ ieee80211_max_num_channels(local, radio_idx);
+ }
+
+ static struct ieee80211_chanctx *
+@@ -1045,7 +1050,7 @@ int ieee80211_link_reserve_chanctx(struc
+
+ new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
+ if (!new_ctx) {
+- if (ieee80211_can_create_new_chanctx(local)) {
++ if (ieee80211_can_create_new_chanctx(local, -1)) {
+ new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
+ if (IS_ERR(new_ctx))
+ return PTR_ERR(new_ctx);
+@@ -1736,7 +1741,7 @@ int ieee80211_link_use_channel(struct ie
+ link->radar_required = ret;
+
+ ret = ieee80211_check_combinations(sdata, &chanreq->oper, mode,
+- radar_detect_width);
++ radar_detect_width, -1);
+ if (ret < 0)
+ goto out;
+
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -1745,7 +1745,7 @@ int ieee80211_ibss_join(struct ieee80211
+ IEEE80211_CHANCTX_SHARED : IEEE80211_CHANCTX_EXCLUSIVE;
+
+ ret = ieee80211_check_combinations(sdata, ¶ms->chandef, chanmode,
+- radar_detect_width);
++ radar_detect_width, -1);
+ if (ret < 0)
+ return ret;
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -2596,8 +2596,9 @@ void ieee80211_recalc_dtim(struct ieee80
+ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_chan_def *chandef,
+ enum ieee80211_chanctx_mode chanmode,
+- u8 radar_detect);
+-int ieee80211_max_num_channels(struct ieee80211_local *local);
++ u8 radar_detect, int radio_idx);
++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);
+
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -397,7 +397,7 @@ static int ieee80211_check_concurrent_if
+ }
+ }
+
+- return ieee80211_check_combinations(sdata, NULL, 0, 0);
++ return ieee80211_check_combinations(sdata, NULL, 0, 0, -1);
+ }
+
+ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -3918,20 +3918,103 @@ static u8 ieee80211_chanctx_radar_detect
+ return radar_detect;
+ }
+
++static u32
++__ieee80211_get_radio_mask(struct ieee80211_sub_if_data *sdata)
++{
++ struct ieee80211_bss_conf *link_conf;
++ struct ieee80211_chanctx_conf *conf;
++ unsigned int link_id;
++ u32 mask = 0;
++
++ for_each_vif_active_link(&sdata->vif, link_conf, link_id) {
++ conf = sdata_dereference(link_conf->chanctx_conf, sdata);
++ if (!conf || conf->radio_idx < 0)
++ continue;
++
++ mask |= BIT(conf->radio_idx);
++ }
++
++ return mask;
++}
++
++u32 ieee80211_get_radio_mask(struct wiphy *wiphy, struct net_device *dev)
++{
++ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++
++ return __ieee80211_get_radio_mask(sdata);
++}
++
++static bool
++ieee80211_sdata_uses_radio(struct ieee80211_sub_if_data *sdata, int radio_idx)
++{
++ if (radio_idx < 0)
++ return true;
++
++ return __ieee80211_get_radio_mask(sdata) & BIT(radio_idx);
++}
++
++static int
++ieee80211_fill_ifcomb_params(struct ieee80211_local *local,
++ struct iface_combination_params *params,
++ const struct cfg80211_chan_def *chandef,
++ struct ieee80211_sub_if_data *sdata)
++{
++ struct ieee80211_sub_if_data *sdata_iter;
++ struct ieee80211_chanctx *ctx;
++ int total = !!sdata;
++
++ list_for_each_entry(ctx, &local->chanctx_list, list) {
++ if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
++ continue;
++
++ if (params->radio_idx >= 0 &&
++ ctx->conf.radio_idx != params->radio_idx)
++ continue;
++
++ params->radar_detect |=
++ ieee80211_chanctx_radar_detect(local, ctx);
++
++ if (chandef && ctx->mode != IEEE80211_CHANCTX_EXCLUSIVE &&
++ cfg80211_chandef_compatible(chandef, &ctx->conf.def))
++ continue;
++
++ params->num_different_channels++;
++ }
++
++ list_for_each_entry(sdata_iter, &local->interfaces, list) {
++ struct wireless_dev *wdev_iter;
++
++ wdev_iter = &sdata_iter->wdev;
++
++ if (sdata_iter == sdata ||
++ !ieee80211_sdata_running(sdata_iter) ||
++ cfg80211_iftype_allowed(local->hw.wiphy,
++ wdev_iter->iftype, 0, 1))
++ continue;
++
++ if (!ieee80211_sdata_uses_radio(sdata_iter, params->radio_idx))
++ continue;
++
++ params->iftype_num[wdev_iter->iftype]++;
++ total++;
++ }
++
++ return total;
++}
++
+ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_chan_def *chandef,
+ enum ieee80211_chanctx_mode chanmode,
+- u8 radar_detect)
++ u8 radar_detect, int radio_idx)
+ {
++ bool shared = chanmode == IEEE80211_CHANCTX_SHARED;
+ struct ieee80211_local *local = sdata->local;
+- struct ieee80211_sub_if_data *sdata_iter;
+ enum nl80211_iftype iftype = sdata->wdev.iftype;
+- struct ieee80211_chanctx *ctx;
+- int total = 1;
+ struct iface_combination_params params = {
+ .radar_detect = radar_detect,
+- .radio_idx = -1,
++ .radio_idx = radio_idx,
+ };
++ int total;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+@@ -3968,37 +4051,9 @@ int ieee80211_check_combinations(struct
+ if (iftype != NL80211_IFTYPE_UNSPECIFIED)
+ params.iftype_num[iftype] = 1;
+
+- list_for_each_entry(ctx, &local->chanctx_list, list) {
+- if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
+- continue;
+- params.radar_detect |=
+- ieee80211_chanctx_radar_detect(local, ctx);
+- if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
+- params.num_different_channels++;
+- continue;
+- }
+- if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
+- cfg80211_chandef_compatible(chandef,
+- &ctx->conf.def))
+- continue;
+- params.num_different_channels++;
+- }
+-
+- list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
+- struct wireless_dev *wdev_iter;
+-
+- wdev_iter = &sdata_iter->wdev;
+-
+- if (sdata_iter == sdata ||
+- !ieee80211_sdata_running(sdata_iter) ||
+- cfg80211_iftype_allowed(local->hw.wiphy,
+- wdev_iter->iftype, 0, 1))
+- continue;
+-
+- params.iftype_num[wdev_iter->iftype]++;
+- total++;
+- }
+-
++ total = ieee80211_fill_ifcomb_params(local, ¶ms,
++ shared ? chandef : NULL,
++ sdata);
+ if (total == 1 && !params.radar_detect)
+ return 0;
+
+@@ -4015,30 +4070,17 @@ ieee80211_iter_max_chans(const struct ie
+ c->num_different_channels);
+ }
+
+-int ieee80211_max_num_channels(struct ieee80211_local *local)
++int ieee80211_max_num_channels(struct ieee80211_local *local, int radio_idx)
+ {
+- struct ieee80211_sub_if_data *sdata;
+- struct ieee80211_chanctx *ctx;
+ u32 max_num_different_channels = 1;
+ int err;
+ struct iface_combination_params params = {
+- .radio_idx = -1,
++ .radio_idx = radio_idx,
+ };
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+- list_for_each_entry(ctx, &local->chanctx_list, list) {
+- if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
+- continue;
+-
+- params.num_different_channels++;
+-
+- params.radar_detect |=
+- ieee80211_chanctx_radar_detect(local, ctx);
+- }
+-
+- list_for_each_entry_rcu(sdata, &local->interfaces, list)
+- params.iftype_num[sdata->wdev.iftype]++;
++ ieee80211_fill_ifcomb_params(local, ¶ms, NULL, NULL);
+
+ err = cfg80211_iter_combinations(local->hw.wiphy, ¶ms,
+ ieee80211_iter_max_chans,
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 5 Jun 2024 10:49:22 +0200
+Subject: [PATCH] wifi: mac80211: move code in
+ ieee80211_link_reserve_chanctx to a helper
+
+Reduces indentation in preparation for further changes
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -1033,6 +1033,71 @@ int ieee80211_link_unreserve_chanctx(str
+ return 0;
+ }
+
++static struct ieee80211_chanctx *
++ieee80211_replace_chanctx(struct ieee80211_local *local,
++ const struct ieee80211_chan_req *chanreq,
++ enum ieee80211_chanctx_mode mode,
++ struct ieee80211_chanctx *curr_ctx)
++{
++ struct ieee80211_chanctx *new_ctx, *ctx;
++
++ if (!curr_ctx || (curr_ctx->replace_state ==
++ IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
++ !list_empty(&curr_ctx->reserved_links)) {
++ /*
++ * Another link already requested this context for a
++ * reservation. Find another one hoping all links assigned
++ * to it will also switch soon enough.
++ *
++ * TODO: This needs a little more work as some cases
++ * (more than 2 chanctx capable devices) may fail which could
++ * otherwise succeed provided some channel context juggling was
++ * performed.
++ *
++ * Consider ctx1..3, link1..6, each ctx has 2 links. link1 and
++ * link2 from ctx1 request new different chandefs starting 2
++ * in-place reserations with ctx4 and ctx5 replacing ctx1 and
++ * ctx2 respectively. Next link5 and link6 from ctx3 reserve
++ * ctx4. If link3 and link4 remain on ctx2 as they are then this
++ * fails unless `replace_ctx` from ctx5 is replaced with ctx3.
++ */
++ list_for_each_entry(ctx, &local->chanctx_list, list) {
++ if (ctx->replace_state !=
++ IEEE80211_CHANCTX_REPLACE_NONE)
++ continue;
++
++ if (!list_empty(&ctx->reserved_links))
++ continue;
++
++ curr_ctx = ctx;
++ break;
++ }
++ }
++
++ /*
++ * If that's true then all available contexts already have reservations
++ * and cannot be used.
++ */
++ if (!curr_ctx || (curr_ctx->replace_state ==
++ IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
++ !list_empty(&curr_ctx->reserved_links))
++ return ERR_PTR(-EBUSY);
++
++ new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
++ if (!new_ctx)
++ return ERR_PTR(-ENOMEM);
++
++ new_ctx->replace_ctx = curr_ctx;
++ new_ctx->replace_state = IEEE80211_CHANCTX_REPLACES_OTHER;
++
++ curr_ctx->replace_ctx = new_ctx;
++ curr_ctx->replace_state = IEEE80211_CHANCTX_WILL_BE_REPLACED;
++
++ list_add_rcu(&new_ctx->list, &local->chanctx_list);
++
++ return new_ctx;
++}
++
+ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
+ const struct ieee80211_chan_req *chanreq,
+ enum ieee80211_chanctx_mode mode,
+@@ -1040,7 +1105,7 @@ int ieee80211_link_reserve_chanctx(struc
+ {
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_local *local = sdata->local;
+- struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx;
++ struct ieee80211_chanctx *new_ctx, *curr_ctx;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+@@ -1050,75 +1115,13 @@ int ieee80211_link_reserve_chanctx(struc
+
+ new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
+ if (!new_ctx) {
+- if (ieee80211_can_create_new_chanctx(local, -1)) {
++ if (ieee80211_can_create_new_chanctx(local, -1))
+ new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
+- if (IS_ERR(new_ctx))
+- return PTR_ERR(new_ctx);
+- } else {
+- if (!curr_ctx ||
+- (curr_ctx->replace_state ==
+- IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
+- !list_empty(&curr_ctx->reserved_links)) {
+- /*
+- * Another link already requested this context
+- * for a reservation. Find another one hoping
+- * all links assigned to it will also switch
+- * soon enough.
+- *
+- * TODO: This needs a little more work as some
+- * cases (more than 2 chanctx capable devices)
+- * may fail which could otherwise succeed
+- * provided some channel context juggling was
+- * performed.
+- *
+- * Consider ctx1..3, link1..6, each ctx has 2
+- * links. link1 and link2 from ctx1 request new
+- * different chandefs starting 2 in-place
+- * reserations with ctx4 and ctx5 replacing
+- * ctx1 and ctx2 respectively. Next link5 and
+- * link6 from ctx3 reserve ctx4. If link3 and
+- * link4 remain on ctx2 as they are then this
+- * fails unless `replace_ctx` from ctx5 is
+- * replaced with ctx3.
+- */
+- list_for_each_entry(ctx, &local->chanctx_list,
+- list) {
+- if (ctx->replace_state !=
+- IEEE80211_CHANCTX_REPLACE_NONE)
+- continue;
+-
+- if (!list_empty(&ctx->reserved_links))
+- continue;
+-
+- curr_ctx = ctx;
+- break;
+- }
+- }
+-
+- /*
+- * If that's true then all available contexts already
+- * have reservations and cannot be used.
+- */
+- if (!curr_ctx ||
+- (curr_ctx->replace_state ==
+- IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
+- !list_empty(&curr_ctx->reserved_links))
+- return -EBUSY;
+-
+- new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
+- if (!new_ctx)
+- return -ENOMEM;
+-
+- new_ctx->replace_ctx = curr_ctx;
+- new_ctx->replace_state =
+- IEEE80211_CHANCTX_REPLACES_OTHER;
+-
+- curr_ctx->replace_ctx = new_ctx;
+- curr_ctx->replace_state =
+- IEEE80211_CHANCTX_WILL_BE_REPLACED;
+-
+- list_add_rcu(&new_ctx->list, &local->chanctx_list);
+- }
++ else
++ new_ctx = ieee80211_replace_chanctx(local, chanreq,
++ mode, curr_ctx);
++ if (IS_ERR(new_ctx))
++ return PTR_ERR(new_ctx);
+ }
+
+ list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 5 Jun 2024 18:39:55 +0200
+Subject: [PATCH] wifi: mac80211: add wiphy radio assignment and
+ validation
+
+Validate number of channels and interface combinations per radio.
+Assign each channel context to a radio.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -680,14 +680,15 @@ static int ieee80211_add_chanctx(struct
+ static struct ieee80211_chanctx *
+ ieee80211_new_chanctx(struct ieee80211_local *local,
+ const struct ieee80211_chan_req *chanreq,
+- enum ieee80211_chanctx_mode mode)
++ enum ieee80211_chanctx_mode mode,
++ int radio_idx)
+ {
+ struct ieee80211_chanctx *ctx;
+ int err;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+- ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
++ ctx = ieee80211_alloc_chanctx(local, chanreq, mode, radio_idx);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+@@ -1040,6 +1041,8 @@ ieee80211_replace_chanctx(struct ieee802
+ struct ieee80211_chanctx *curr_ctx)
+ {
+ struct ieee80211_chanctx *new_ctx, *ctx;
++ struct wiphy *wiphy = local->hw.wiphy;
++ const struct wiphy_radio *radio;
+
+ if (!curr_ctx || (curr_ctx->replace_state ==
+ IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
+@@ -1069,6 +1072,12 @@ ieee80211_replace_chanctx(struct ieee802
+ if (!list_empty(&ctx->reserved_links))
+ continue;
+
++ if (ctx->conf.radio_idx >= 0) {
++ radio = &wiphy->radio[ctx->conf.radio_idx];
++ if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
++ continue;
++ }
++
+ curr_ctx = ctx;
+ break;
+ }
+@@ -1098,6 +1107,34 @@ ieee80211_replace_chanctx(struct ieee802
+ return new_ctx;
+ }
+
++static bool
++ieee80211_find_available_radio(struct ieee80211_local *local,
++ const struct ieee80211_chan_req *chanreq,
++ int *radio_idx)
++{
++ struct wiphy *wiphy = local->hw.wiphy;
++ const struct wiphy_radio *radio;
++ int i;
++
++ *radio_idx = -1;
++ if (!wiphy->n_radio)
++ return true;
++
++ for (i = 0; i < wiphy->n_radio; i++) {
++ radio = &wiphy->radio[i];
++ if (!cfg80211_radio_chandef_valid(radio, &chanreq->oper))
++ continue;
++
++ if (!ieee80211_can_create_new_chanctx(local, i))
++ continue;
++
++ *radio_idx = i;
++ return true;
++ }
++
++ return false;
++}
++
+ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
+ const struct ieee80211_chan_req *chanreq,
+ enum ieee80211_chanctx_mode mode,
+@@ -1106,6 +1143,7 @@ int ieee80211_link_reserve_chanctx(struc
+ struct ieee80211_sub_if_data *sdata = link->sdata;
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx *new_ctx, *curr_ctx;
++ int radio_idx;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+
+@@ -1115,8 +1153,10 @@ int ieee80211_link_reserve_chanctx(struc
+
+ new_ctx = ieee80211_find_reservation_chanctx(local, chanreq, mode);
+ if (!new_ctx) {
+- if (ieee80211_can_create_new_chanctx(local, -1))
+- new_ctx = ieee80211_new_chanctx(local, chanreq, mode);
++ if (ieee80211_can_create_new_chanctx(local, -1) &&
++ ieee80211_find_available_radio(local, chanreq, &radio_idx))
++ new_ctx = ieee80211_new_chanctx(local, chanreq, mode,
++ radio_idx);
+ else
+ new_ctx = ieee80211_replace_chanctx(local, chanreq,
+ mode, curr_ctx);
+@@ -1724,6 +1764,7 @@ int ieee80211_link_use_channel(struct ie
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx *ctx;
+ u8 radar_detect_width = 0;
++ int radio_idx;
+ int ret;
+
+ lockdep_assert_wiphy(local->hw.wiphy);
+@@ -1751,8 +1792,12 @@ int ieee80211_link_use_channel(struct ie
+ __ieee80211_link_release_channel(link);
+
+ ctx = ieee80211_find_chanctx(local, chanreq, mode);
+- if (!ctx)
+- ctx = ieee80211_new_chanctx(local, chanreq, mode);
++ if (!ctx) {
++ if (!ieee80211_find_available_radio(local, chanreq, &radio_idx))
++ ctx = ERR_PTR(-EBUSY);
++ else
++ ctx = ieee80211_new_chanctx(local, chanreq, mode, radio_idx);
++ }
+ if (IS_ERR(ctx)) {
+ ret = PTR_ERR(ctx);
+ goto out;
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 11 Jun 2024 09:02:55 +0200
+Subject: [PATCH] wifi: mac80211_hwsim: add support for multi-radio wiphy
+
+This registers one wiphy radio per supported band. Number of different
+channels is set per radio.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
+@@ -69,6 +69,10 @@ static bool mlo;
+ module_param(mlo, bool, 0444);
+ MODULE_PARM_DESC(mlo, "Support MLO");
+
++static bool multi_radio;
++module_param(multi_radio, bool, 0444);
++MODULE_PARM_DESC(mlo, "Support Multiple Radios per wiphy");
++
+ /**
+ * enum hwsim_regtest - the type of regulatory tests we offer
+ *
+@@ -669,6 +673,10 @@ struct mac80211_hwsim_data {
+ struct ieee80211_iface_limit if_limits[3];
+ int n_if_limits;
+
++ struct ieee80211_iface_combination if_combination_radio;
++ struct wiphy_radio_freq_range radio_range[NUM_NL80211_BANDS];
++ struct wiphy_radio radio[NUM_NL80211_BANDS];
++
+ u32 ciphers[ARRAY_SIZE(hwsim_ciphers)];
+
+ struct mac_address addresses[2];
+@@ -917,6 +925,7 @@ static const struct nla_policy hwsim_gen
+ [HWSIM_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG },
+ [HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy),
+ [HWSIM_ATTR_PMSR_RESULT] = NLA_POLICY_NESTED(hwsim_pmsr_peers_result_policy),
++ [HWSIM_ATTR_MULTI_RADIO] = { .type = NLA_FLAG },
+ };
+
+ #if IS_REACHABLE(CONFIG_VIRTIO)
+@@ -4007,6 +4016,7 @@ struct hwsim_new_radio_params {
+ bool reg_strict;
+ bool p2p_device;
+ bool use_chanctx;
++ bool multi_radio;
+ bool destroy_on_close;
+ const char *hwname;
+ bool no_vif;
+@@ -4083,6 +4093,12 @@ static int append_radio_msg(struct sk_bu
+ return ret;
+ }
+
++ if (param->multi_radio) {
++ ret = nla_put_flag(skb, HWSIM_ATTR_MULTI_RADIO);
++ if (ret < 0)
++ return ret;
++ }
++
+ if (param->hwname) {
+ ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME,
+ strlen(param->hwname), param->hwname);
+@@ -5099,6 +5115,7 @@ static int mac80211_hwsim_new_radio(stru
+ struct net *net;
+ int idx, i;
+ int n_limits = 0;
++ int n_bands = 0;
+
+ if (WARN_ON(param->channels > 1 && !param->use_chanctx))
+ return -EINVAL;
+@@ -5202,22 +5219,22 @@ static int mac80211_hwsim_new_radio(stru
+ n_limits++;
+ }
+
++ data->if_combination.radar_detect_widths =
++ BIT(NL80211_CHAN_WIDTH_5) |
++ BIT(NL80211_CHAN_WIDTH_10) |
++ BIT(NL80211_CHAN_WIDTH_20_NOHT) |
++ BIT(NL80211_CHAN_WIDTH_20) |
++ BIT(NL80211_CHAN_WIDTH_40) |
++ BIT(NL80211_CHAN_WIDTH_80) |
++ BIT(NL80211_CHAN_WIDTH_160);
++
+ if (data->use_chanctx) {
+ hw->wiphy->max_scan_ssids = 255;
+ hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ hw->wiphy->max_remain_on_channel_duration = 1000;
+- data->if_combination.radar_detect_widths = 0;
+ data->if_combination.num_different_channels = data->channels;
+ } else {
+ data->if_combination.num_different_channels = 1;
+- data->if_combination.radar_detect_widths =
+- BIT(NL80211_CHAN_WIDTH_5) |
+- BIT(NL80211_CHAN_WIDTH_10) |
+- BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+- BIT(NL80211_CHAN_WIDTH_20) |
+- BIT(NL80211_CHAN_WIDTH_40) |
+- BIT(NL80211_CHAN_WIDTH_80) |
+- BIT(NL80211_CHAN_WIDTH_160);
+ }
+
+ if (!n_limits) {
+@@ -5333,6 +5350,9 @@ static int mac80211_hwsim_new_radio(stru
+
+ for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
+ struct ieee80211_supported_band *sband = &data->bands[band];
++ struct wiphy_radio_freq_range *radio_range;
++ const struct ieee80211_channel *c;
++ struct wiphy_radio *radio;
+
+ sband->band = band;
+
+@@ -5406,8 +5426,36 @@ static int mac80211_hwsim_new_radio(stru
+ mac80211_hwsim_sband_capab(sband);
+
+ hw->wiphy->bands[band] = sband;
++
++ if (!param->multi_radio)
++ continue;
++
++ c = sband->channels;
++ radio_range = &data->radio_range[n_bands];
++ radio_range->start_freq = ieee80211_channel_to_khz(c) - 10000;
++
++ c += sband->n_channels - 1;
++ radio_range->end_freq = ieee80211_channel_to_khz(c) + 10000;
++
++ radio = &data->radio[n_bands++];
++ radio->freq_range = radio_range;
++ radio->n_freq_range = 1;
++ radio->iface_combinations = &data->if_combination_radio;
++ radio->n_iface_combinations = 1;
+ }
+
++ if (param->multi_radio) {
++ hw->wiphy->radio = data->radio;
++ hw->wiphy->n_radio = n_bands;
++
++ memcpy(&data->if_combination_radio, &data->if_combination,
++ sizeof(data->if_combination));
++ data->if_combination.num_different_channels *= n_bands;
++ }
++
++ if (data->use_chanctx)
++ data->if_combination.radar_detect_widths = 0;
++
+ /* By default all radios belong to the first group */
+ data->group = 1;
+ mutex_init(&data->mutex);
+@@ -6025,6 +6073,9 @@ static int hwsim_new_radio_nl(struct sk_
+ else
+ param.use_chanctx = (param.channels > 1);
+
++ if (info->attrs[HWSIM_ATTR_MULTI_RADIO])
++ param.multi_radio = true;
++
+ if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
+ param.reg_alpha2 =
+ nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
+@@ -6105,7 +6156,7 @@ static int hwsim_new_radio_nl(struct sk_
+
+ param.mlo = info->attrs[HWSIM_ATTR_MLO_SUPPORT];
+
+- if (param.mlo)
++ if (param.mlo || param.multi_radio)
+ param.use_chanctx = true;
+
+ if (info->attrs[HWSIM_ATTR_RADIO_NAME]) {
+@@ -6802,7 +6853,8 @@ static int __init init_mac80211_hwsim(vo
+
+ param.p2p_device = support_p2p_device;
+ param.mlo = mlo;
+- param.use_chanctx = channels > 1 || mlo;
++ param.multi_radio = multi_radio;
++ param.use_chanctx = channels > 1 || mlo || multi_radio;
+ param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK;
+ if (param.p2p_device)
+ param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
+--- a/drivers/net/wireless/virtual/mac80211_hwsim.h
++++ b/drivers/net/wireless/virtual/mac80211_hwsim.h
+@@ -157,6 +157,9 @@ enum hwsim_commands {
+ * to provide details about peer measurement request (nl80211_peer_measurement_attrs)
+ * @HWSIM_ATTR_PMSR_RESULT: nested attributed used with %HWSIM_CMD_REPORT_PMSR
+ * to provide peer measurement result (nl80211_peer_measurement_attrs)
++ * @HWSIM_ATTR_MULTI_RADIO: Register multiple wiphy radios (flag).
++ * Adds one radio for each band. Number of supported channels will be set for
++ * each radio instead of for the wiphy.
+ * @__HWSIM_ATTR_MAX: enum limit
+ */
+ enum hwsim_attrs {
+@@ -189,6 +192,7 @@ enum hwsim_attrs {
+ HWSIM_ATTR_PMSR_SUPPORT,
+ HWSIM_ATTR_PMSR_REQUEST,
+ HWSIM_ATTR_PMSR_RESULT,
++ HWSIM_ATTR_MULTI_RADIO,
+ __HWSIM_ATTR_MAX,
+ };
+ #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -2445,6 +2445,13 @@ static void sta_stats_decode_rate(struct
+@@ -2459,6 +2459,13 @@ static void sta_stats_decode_rate(struct
sband = local->hw.wiphy->bands[band];
--- /dev/null
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -1614,8 +1614,8 @@ EXPORT_SYMBOL_GPL(mt76_get_sar_power);
+ static void
+ __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ {
+- if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
+- ieee80211_csa_finish(vif);
++ if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif, 0))
++ ieee80211_csa_finish(vif, 0);
+ }
+
+ void mt76_csa_finish(struct mt76_dev *dev)
+@@ -1639,7 +1639,7 @@ __mt76_csa_check(void *priv, u8 *mac, st
+ if (!vif->bss_conf.csa_active)
+ return;
+
+- dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
++ dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif, 0);
+ }
+
+ void mt76_csa_check(struct mt76_dev *dev)
+--- a/mt76.h
++++ b/mt76.h
+@@ -1611,6 +1611,18 @@ s8 mt76_get_rate_power_limits(struct mt7
+ struct mt76_power_limits *dest,
+ s8 target_power);
+
++static inline bool mt76_queue_is_rx(struct mt76_dev *dev, struct mt76_queue *q)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) {
++ if (q == &dev->q_rx[i])
++ return true;
++ }
++
++ return false;
++}
++
+ static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q)
+ {
+ return (q->flags & MT_QFLAG_WED) &&
+--- a/mt7603/main.c
++++ b/mt7603/main.c
+@@ -701,6 +701,10 @@ static void mt7603_tx(struct ieee80211_h
+ }
+
+ const struct ieee80211_ops mt7603_ops = {
++ .add_chanctx = ieee80211_emulate_add_chanctx,
++ .remove_chanctx = ieee80211_emulate_remove_chanctx,
++ .change_chanctx = ieee80211_emulate_change_chanctx,
++ .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
+ .tx = mt7603_tx,
+ .start = mt7603_start,
+ .stop = mt7603_stop,
+@@ -728,6 +732,7 @@ const struct ieee80211_ops mt7603_ops =
+ .set_sar_specs = mt7603_set_sar_specs,
+ };
+
++MODULE_DESCRIPTION("MediaTek MT7603E and MT76x8 wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+
+ static int __init mt7603_init(void)
+--- a/mt7615/Kconfig
++++ b/mt7615/Kconfig
+@@ -11,7 +11,7 @@ config MT7615E
+ depends on MAC80211
+ depends on PCI
+ help
+- This adds support for MT7615-based wireless PCIe devices,
++ This adds support for MT7615-based PCIe wireless devices,
+ which support concurrent dual-band operation at both 5GHz
+ and 2.4GHz, IEEE 802.11ac 4x4:4SS 1733Mbps PHY rate, wave2
+ MU-MIMO up to 4 users/group and 160MHz channels.
+--- a/mt7615/main.c
++++ b/mt7615/main.c
+@@ -1326,6 +1326,10 @@ static void mt7615_set_rekey_data(struct
+ #endif /* CONFIG_PM */
+
+ const struct ieee80211_ops mt7615_ops = {
++ .add_chanctx = ieee80211_emulate_add_chanctx,
++ .remove_chanctx = ieee80211_emulate_remove_chanctx,
++ .change_chanctx = ieee80211_emulate_change_chanctx,
++ .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
+ .tx = mt7615_tx,
+ .start = mt7615_start,
+ .stop = mt7615_stop,
+@@ -1375,4 +1379,5 @@ const struct ieee80211_ops mt7615_ops =
+ };
+ EXPORT_SYMBOL_GPL(mt7615_ops);
+
++MODULE_DESCRIPTION("MediaTek MT7615E and MT7663E wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7615/mcu.c
++++ b/mt7615/mcu.c
+@@ -353,7 +353,7 @@ static void
+ mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ {
+ if (vif->bss_conf.csa_active)
+- ieee80211_csa_finish(vif);
++ ieee80211_csa_finish(vif, 0);
+ }
+
+ static void
+--- a/mt7615/mmio.c
++++ b/mt7615/mmio.c
+@@ -270,4 +270,5 @@ static void __exit mt7615_exit(void)
+
+ module_init(mt7615_init);
+ module_exit(mt7615_exit);
++MODULE_DESCRIPTION("MediaTek MT7615E MMIO helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7615/sdio.c
++++ b/mt7615/sdio.c
+@@ -180,7 +180,6 @@ static void mt7663s_remove(struct sdio_f
+ mt76_free_device(&dev->mt76);
+ }
+
+-#ifdef CONFIG_PM
+ static int mt7663s_suspend(struct device *dev)
+ {
+ struct sdio_func *func = dev_to_sdio_func(dev);
+@@ -235,31 +234,24 @@ static int mt7663s_resume(struct device
+ return err;
+ }
+
+-static const struct dev_pm_ops mt7663s_pm_ops = {
+- .suspend = mt7663s_suspend,
+- .resume = mt7663s_resume,
+-};
+-#endif
+-
+ MODULE_DEVICE_TABLE(sdio, mt7663s_table);
+ MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9);
+ MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH);
+ MODULE_FIRMWARE(MT7663_FIRMWARE_N9);
+ MODULE_FIRMWARE(MT7663_ROM_PATCH);
+
++static DEFINE_SIMPLE_DEV_PM_OPS(mt7663s_pm_ops, mt7663s_suspend, mt7663s_resume);
++
+ static struct sdio_driver mt7663s_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = mt7663s_probe,
+ .remove = mt7663s_remove,
+ .id_table = mt7663s_table,
+-#ifdef CONFIG_PM
+- .drv = {
+- .pm = &mt7663s_pm_ops,
+- }
+-#endif
++ .drv.pm = pm_sleep_ptr(&mt7663s_pm_ops),
+ };
+ module_sdio_driver(mt7663s_driver);
+
+ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
++MODULE_DESCRIPTION("MediaTek MT7663S (SDIO) wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7615/usb.c
++++ b/mt7615/usb.c
+@@ -281,4 +281,5 @@ module_usb_driver(mt7663u_driver);
+
+ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
++MODULE_DESCRIPTION("MediaTek MT7663U (USB) wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7615/usb_sdio.c
++++ b/mt7615/usb_sdio.c
+@@ -349,4 +349,5 @@ EXPORT_SYMBOL_GPL(mt7663_usb_sdio_regist
+
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
++MODULE_DESCRIPTION("MediaTek MT7663 SDIO/USB helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -3171,4 +3171,5 @@ exit:
+ EXPORT_SYMBOL_GPL(mt76_connac2_mcu_fill_message);
+
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
++MODULE_DESCRIPTION("MediaTek MT76x connac layer helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -128,7 +128,7 @@ struct mt76_connac2_mcu_rxd {
+ u8 rsv1[2];
+ u8 s2d_index;
+
+- u8 tlv[0];
++ u8 tlv[];
+ };
+
+ struct mt76_connac2_patch_hdr {
+@@ -1460,7 +1460,7 @@ struct mt76_connac_beacon_loss_event {
+ } __packed;
+
+ struct mt76_connac_rssi_notify_event {
+- s32 rssi[4];
++ __le32 rssi[4];
+ } __packed;
+
+ struct mt76_connac_mcu_bss_event {
+--- a/mt76x0/eeprom.c
++++ b/mt76x0/eeprom.c
+@@ -342,4 +342,5 @@ int mt76x0_eeprom_init(struct mt76x02_de
+ return 0;
+ }
+
++MODULE_DESCRIPTION("MediaTek MT76x EEPROM helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt76x0/pci.c
++++ b/mt76x0/pci.c
+@@ -59,6 +59,10 @@ mt76x0e_flush(struct ieee80211_hw *hw, s
+ }
+
+ static const struct ieee80211_ops mt76x0e_ops = {
++ .add_chanctx = ieee80211_emulate_add_chanctx,
++ .remove_chanctx = ieee80211_emulate_remove_chanctx,
++ .change_chanctx = ieee80211_emulate_change_chanctx,
++ .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
+ .tx = mt76x02_tx,
+ .start = mt76x0e_start,
+ .stop = mt76x0e_stop,
+@@ -302,6 +306,7 @@ static const struct pci_device_id mt76x0
+ MODULE_DEVICE_TABLE(pci, mt76x0e_device_table);
+ MODULE_FIRMWARE(MT7610E_FIRMWARE);
+ MODULE_FIRMWARE(MT7650E_FIRMWARE);
++MODULE_DESCRIPTION("MediaTek MT76x0E (PCIe) wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+
+ static struct pci_driver mt76x0e_driver = {
+--- a/mt76x0/usb.c
++++ b/mt76x0/usb.c
+@@ -118,6 +118,10 @@ static int mt76x0u_start(struct ieee8021
+ }
+
+ static const struct ieee80211_ops mt76x0u_ops = {
++ .add_chanctx = ieee80211_emulate_add_chanctx,
++ .remove_chanctx = ieee80211_emulate_remove_chanctx,
++ .change_chanctx = ieee80211_emulate_change_chanctx,
++ .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
+ .tx = mt76x02_tx,
+ .start = mt76x0u_start,
+ .stop = mt76x0u_stop,
+@@ -336,6 +340,7 @@ err:
+ MODULE_DEVICE_TABLE(usb, mt76x0_device_table);
+ MODULE_FIRMWARE(MT7610E_FIRMWARE);
+ MODULE_FIRMWARE(MT7610U_FIRMWARE);
++MODULE_DESCRIPTION("MediaTek MT76x0U (USB) wireless driver");
+ MODULE_LICENSE("GPL");
+
+ static struct usb_driver mt76x0_driver = {
+--- a/mt76x02_usb_mcu.c
++++ b/mt76x02_usb_mcu.c
+@@ -293,4 +293,5 @@ void mt76x02u_init_mcu(struct mt76_dev *
+ EXPORT_SYMBOL_GPL(mt76x02u_init_mcu);
+
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
++MODULE_DESCRIPTION("MediaTek MT76x02 MCU helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt76x02_util.c
++++ b/mt76x02_util.c
+@@ -696,4 +696,5 @@ void mt76x02_config_mac_addr_list(struct
+ }
+ EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list);
+
++MODULE_DESCRIPTION("MediaTek MT76x02 helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt76x2/eeprom.c
++++ b/mt76x2/eeprom.c
+@@ -506,4 +506,5 @@ int mt76x2_eeprom_init(struct mt76x02_de
+ }
+ EXPORT_SYMBOL_GPL(mt76x2_eeprom_init);
+
++MODULE_DESCRIPTION("MediaTek MT76x2 EEPROM helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt76x2/pci.c
++++ b/mt76x2/pci.c
+@@ -165,6 +165,7 @@ mt76x2e_resume(struct pci_dev *pdev)
+ MODULE_DEVICE_TABLE(pci, mt76x2e_device_table);
+ MODULE_FIRMWARE(MT7662_FIRMWARE);
+ MODULE_FIRMWARE(MT7662_ROM_PATCH);
++MODULE_DESCRIPTION("MediaTek MT76x2E (PCIe) wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+
+ static struct pci_driver mt76pci_driver = {
+--- a/mt76x2/pci_main.c
++++ b/mt76x2/pci_main.c
+@@ -132,6 +132,10 @@ static int mt76x2_set_antenna(struct iee
+ }
+
+ const struct ieee80211_ops mt76x2_ops = {
++ .add_chanctx = ieee80211_emulate_add_chanctx,
++ .remove_chanctx = ieee80211_emulate_remove_chanctx,
++ .change_chanctx = ieee80211_emulate_change_chanctx,
++ .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
+ .tx = mt76x02_tx,
+ .start = mt76x2_start,
+ .stop = mt76x2_stop,
+--- a/mt76x2/usb.c
++++ b/mt76x2/usb.c
+@@ -148,4 +148,5 @@ static struct usb_driver mt76x2u_driver
+ module_usb_driver(mt76x2u_driver);
+
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
++MODULE_DESCRIPTION("MediaTek MT76x2U (USB) wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt76x2/usb_main.c
++++ b/mt76x2/usb_main.c
+@@ -103,6 +103,10 @@ mt76x2u_config(struct ieee80211_hw *hw,
+ }
+
+ const struct ieee80211_ops mt76x2u_ops = {
++ .add_chanctx = ieee80211_emulate_add_chanctx,
++ .remove_chanctx = ieee80211_emulate_remove_chanctx,
++ .change_chanctx = ieee80211_emulate_change_chanctx,
++ .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
+ .tx = mt76x02_tx,
+ .start = mt76x2u_start,
+ .stop = mt76x2u_stop,
+--- a/mt7915/Kconfig
++++ b/mt7915/Kconfig
+@@ -7,7 +7,7 @@ config MT7915E
+ depends on PCI
+ select RELAY
+ help
+- This adds support for MT7915-based wireless PCIe devices,
++ This adds support for MT7915-based PCIe wireless devices,
+ which support concurrent dual-band operation at both 5GHz
+ and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels,
+ OFDMA, spatial reuse and dual carrier modulation.
+--- a/mt7915/init.c
++++ b/mt7915/init.c
+@@ -4,6 +4,7 @@
+ #include <linux/etherdevice.h>
+ #include <linux/hwmon.h>
+ #include <linux/hwmon-sysfs.h>
++#include <linux/of.h>
+ #include <linux/thermal.h>
+ #include "mt7915.h"
+ #include "mac.h"
+@@ -1151,8 +1152,7 @@ void mt7915_set_stream_he_caps(struct mt
+ n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data);
+
+ band = &phy->mt76->sband_2g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+
+ if (phy->mt76->cap.has_5ghz) {
+@@ -1160,8 +1160,7 @@ void mt7915_set_stream_he_caps(struct mt
+ n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data);
+
+ band = &phy->mt76->sband_5g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+
+ if (phy->mt76->cap.has_6ghz) {
+@@ -1169,8 +1168,7 @@ void mt7915_set_stream_he_caps(struct mt
+ n = mt7915_init_he_caps(phy, NL80211_BAND_6GHZ, data);
+
+ band = &phy->mt76->sband_6g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+ }
+
+--- a/mt7915/main.c
++++ b/mt7915/main.c
+@@ -1661,6 +1661,10 @@ mt7915_net_fill_forward_path(struct ieee
+ #endif
+
+ const struct ieee80211_ops mt7915_ops = {
++ .add_chanctx = ieee80211_emulate_add_chanctx,
++ .remove_chanctx = ieee80211_emulate_remove_chanctx,
++ .change_chanctx = ieee80211_emulate_change_chanctx,
++ .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
+ .tx = mt7915_tx,
+ .start = mt7915_start,
+ .stop = mt7915_stop,
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -228,7 +228,7 @@ mt7915_mcu_csa_finish(void *priv, u8 *ma
+ if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION)
+ return;
+
+- ieee80211_csa_finish(vif);
++ ieee80211_csa_finish(vif, 0);
+ }
+
+ static void
+@@ -463,10 +463,10 @@ static bool mt7915_check_he_obss_narrow_
+ .tolerated = true,
+ };
+
+- if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR))
++ if (!(vif->bss_conf.chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR))
+ return false;
+
+- cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef,
++ cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chanreq.oper,
+ mt7915_check_he_obss_narrow_bw_ru_iter,
+ &iter_data);
+
+--- a/mt7915/mmio.c
++++ b/mt7915/mmio.c
+@@ -993,4 +993,5 @@ static void __exit mt7915_exit(void)
+
+ module_init(mt7915_init);
+ module_exit(mt7915_exit);
++MODULE_DESCRIPTION("MediaTek MT7915E MMIO helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7921/main.c
++++ b/mt7921/main.c
+@@ -196,8 +196,7 @@ void mt7921_set_stream_he_caps(struct mt
+ n = mt7921_init_he_caps(phy, NL80211_BAND_2GHZ, data);
+
+ band = &phy->mt76->sband_2g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+
+ if (phy->mt76->cap.has_5ghz) {
+@@ -205,16 +204,14 @@ void mt7921_set_stream_he_caps(struct mt
+ n = mt7921_init_he_caps(phy, NL80211_BAND_5GHZ, data);
+
+ band = &phy->mt76->sband_5g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+
+ if (phy->mt76->cap.has_6ghz) {
+ data = phy->iftype[NL80211_BAND_6GHZ];
+ n = mt7921_init_he_caps(phy, NL80211_BAND_6GHZ, data);
+
+ band = &phy->mt76->sband_6g.sband;
+- band->iftype_data = data;
+- band->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(band, data, n);
+ }
+ }
+ }
+@@ -1464,5 +1461,6 @@ const struct ieee80211_ops mt7921_ops =
+ };
+ EXPORT_SYMBOL_GPL(mt7921_ops);
+
++MODULE_DESCRIPTION("MediaTek MT7921 core driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+--- a/mt7921/pci.c
++++ b/mt7921/pci.c
+@@ -570,4 +570,5 @@ MODULE_FIRMWARE(MT7922_FIRMWARE_WM);
+ MODULE_FIRMWARE(MT7922_ROM_PATCH);
+ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
++MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7921/sdio.c
++++ b/mt7921/sdio.c
+@@ -201,7 +201,6 @@ static void mt7921s_remove(struct sdio_f
+ mt7921s_unregister_device(dev);
+ }
+
+-#ifdef CONFIG_PM
+ static int mt7921s_suspend(struct device *__dev)
+ {
+ struct sdio_func *func = dev_to_sdio_func(__dev);
+@@ -312,27 +311,20 @@ failed:
+ return err;
+ }
+
+-static const struct dev_pm_ops mt7921s_pm_ops = {
+- .suspend = mt7921s_suspend,
+- .resume = mt7921s_resume,
+-};
+-#endif
+-
+ MODULE_DEVICE_TABLE(sdio, mt7921s_table);
+ MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
+ MODULE_FIRMWARE(MT7921_ROM_PATCH);
+
++static DEFINE_SIMPLE_DEV_PM_OPS(mt7921s_pm_ops, mt7921s_suspend, mt7921s_resume);
++
+ static struct sdio_driver mt7921s_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = mt7921s_probe,
+ .remove = mt7921s_remove,
+ .id_table = mt7921s_table,
+-#ifdef CONFIG_PM
+- .drv = {
+- .pm = &mt7921s_pm_ops,
+- }
+-#endif
++ .drv.pm = pm_sleep_ptr(&mt7921s_pm_ops),
+ };
+ module_sdio_driver(mt7921s_driver);
++MODULE_DESCRIPTION("MediaTek MT7921S (SDIO) wireless driver");
+ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7921/usb.c
++++ b/mt7921/usb.c
+@@ -336,5 +336,6 @@ static struct usb_driver mt7921u_driver
+ };
+ module_usb_driver(mt7921u_driver);
+
++MODULE_DESCRIPTION("MediaTek MT7921U (USB) wireless driver");
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7925/main.c
++++ b/mt7925/main.c
+@@ -14,7 +14,7 @@
+ static void
+ mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band,
+ struct ieee80211_sband_iftype_data *data,
+- enum nl80211_iftype iftype)
++ enum nl80211_iftype iftype)
+ {
+ struct ieee80211_sta_he_cap *he_cap = &data->he_cap;
+ struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem;
+@@ -53,7 +53,7 @@ mt7925_init_he_caps(struct mt792x_phy *p
+ IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
+ IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
+
+- switch (i) {
++ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ he_cap_elem->mac_cap_info[2] |=
+ IEEE80211_HE_MAC_CAP2_BSR;
+@@ -1470,4 +1470,5 @@ const struct ieee80211_ops mt7925_ops =
+ EXPORT_SYMBOL_GPL(mt7925_ops);
+
+ MODULE_AUTHOR("Deren Wu <deren.wu@mediatek.com>");
++MODULE_DESCRIPTION("MediaTek MT7925 core driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7925/pci.c
++++ b/mt7925/pci.c
+@@ -586,4 +586,5 @@ MODULE_FIRMWARE(MT7925_FIRMWARE_WM);
+ MODULE_FIRMWARE(MT7925_ROM_PATCH);
+ MODULE_AUTHOR("Deren Wu <deren.wu@mediatek.com>");
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
++MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt7925/usb.c
++++ b/mt7925/usb.c
+@@ -329,4 +329,5 @@ static struct usb_driver mt7925u_driver
+ module_usb_driver(mt7925u_driver);
+
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
++MODULE_DESCRIPTION("MediaTek MT7925U (USB) wireless driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/mt792x_core.c
++++ b/mt792x_core.c
+@@ -685,9 +685,10 @@ mt792x_get_mac80211_ops(struct device *d
+ if (!(*fw_features & MT792x_FW_CAP_CNM)) {
+ ops->remain_on_channel = NULL;
+ ops->cancel_remain_on_channel = NULL;
+- ops->add_chanctx = NULL;
+- ops->remove_chanctx = NULL;
+- ops->change_chanctx = NULL;
++ ops->add_chanctx = ieee80211_emulate_add_chanctx;
++ ops->remove_chanctx = ieee80211_emulate_remove_chanctx;
++ ops->change_chanctx = ieee80211_emulate_change_chanctx;
++ ops->switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx;
+ ops->assign_vif_chanctx = NULL;
+ ops->unassign_vif_chanctx = NULL;
+ ops->mgd_prepare_tx = NULL;
+@@ -863,5 +864,6 @@ int mt792x_load_firmware(struct mt792x_d
+ }
+ EXPORT_SYMBOL_GPL(mt792x_load_firmware);
+
++MODULE_DESCRIPTION("MediaTek MT792x core driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+--- a/mt792x_usb.c
++++ b/mt792x_usb.c
+@@ -312,5 +312,6 @@ void mt792xu_disconnect(struct usb_inter
+ }
+ EXPORT_SYMBOL_GPL(mt792xu_disconnect);
+
++MODULE_DESCRIPTION("MediaTek MT792x USB helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -4,9 +4,10 @@
+ */
+
+ #include <linux/etherdevice.h>
+-#include <linux/thermal.h>
++#include <linux/of.h>
+ #include <linux/hwmon.h>
+ #include <linux/hwmon-sysfs.h>
++#include <linux/thermal.h>
+ #include "mt7996.h"
+ #include "mac.h"
+ #include "mcu.h"
+@@ -1278,8 +1279,7 @@ __mt7996_set_stream_he_eht_caps(struct m
+ n++;
+ }
+
+- sband->iftype_data = data;
+- sband->n_iftype_data = n;
++ _ieee80211_set_sband_iftype_data(sband, data, n);
+ }
+
+ void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy)
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -1467,6 +1467,10 @@ mt7996_net_fill_forward_path(struct ieee
+ #endif
+
+ const struct ieee80211_ops mt7996_ops = {
++ .add_chanctx = ieee80211_emulate_add_chanctx,
++ .remove_chanctx = ieee80211_emulate_remove_chanctx,
++ .change_chanctx = ieee80211_emulate_change_chanctx,
++ .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,
+ .tx = mt7996_tx,
+ .start = mt7996_start,
+ .stop = mt7996_stop,
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -341,7 +341,7 @@ mt7996_mcu_csa_finish(void *priv, u8 *ma
+ if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION)
+ return;
+
+- ieee80211_csa_finish(vif);
++ ieee80211_csa_finish(vif, 0);
+ }
+
+ static void
+--- a/mt7996/mmio.c
++++ b/mt7996/mmio.c
+@@ -670,4 +670,5 @@ static void __exit mt7996_exit(void)
+
+ module_init(mt7996_init);
+ module_exit(mt7996_exit);
++MODULE_DESCRIPTION("MediaTek MT7996 MMIO helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/sdio.c
++++ b/sdio.c
+@@ -677,4 +677,5 @@ EXPORT_SYMBOL_GPL(mt76s_init);
+
+ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
++MODULE_DESCRIPTION("MediaTek MT76x SDIO helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/usb.c
++++ b/usb.c
+@@ -286,8 +286,7 @@ static bool mt76u_check_sg(struct mt76_d
+ struct usb_device *udev = interface_to_usbdev(uintf);
+
+ return (!disable_usb_sg && udev->bus->sg_tablesize > 0 &&
+- (udev->bus->no_sg_constraint ||
+- udev->speed == USB_SPEED_WIRELESS));
++ udev->bus->no_sg_constraint);
+ }
+
+ static int
+@@ -1136,4 +1135,5 @@ int mt76u_init(struct mt76_dev *dev, str
+ EXPORT_SYMBOL_GPL(mt76u_init);
+
+ MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
++MODULE_DESCRIPTION("MediaTek MT76x USB helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
+--- a/util.c
++++ b/util.c
+@@ -138,4 +138,5 @@ int __mt76_worker_fn(void *ptr)
+ }
+ EXPORT_SYMBOL_GPL(__mt76_worker_fn);
+
++MODULE_DESCRIPTION("MediaTek MT76x helpers");
+ MODULE_LICENSE("Dual BSD/GPL");
--- a/core.c
+++ b/core.c
-@@ -718,7 +718,7 @@ static void mwl_chnl_switch_event(struct
+@@ -718,8 +718,8 @@ static void mwl_chnl_switch_event(struct
vif = container_of((void *)mwl_vif, struct ieee80211_vif,
drv_priv);
- if (vif->csa_active)
+- ieee80211_csa_finish(vif);
+ if (vif->bss_conf.csa_active)
- ieee80211_csa_finish(vif);
++ ieee80211_csa_finish(vif, 0);
}
spin_unlock_bh(&priv->vif_lock);
+
--- a/debugfs.c
+++ b/debugfs.c
@@ -498,9 +498,9 @@ static ssize_t mwl_debugfs_vif_read(stru
if (priv->chip_type == MWL8997)
ether_addr_copy(pcmd->start_cmd.bssid, mwl_vif->bssid);
pcmd->start_cmd.bss_type = 1;
+@@ -674,7 +678,7 @@ static int mwl_fwcmd_set_ap_beacon(struc
+ phy_ds_param_set = &pcmd->start_cmd.phy_param_set.ds_param_set;
+ phy_ds_param_set->elem_id = WLAN_EID_DS_PARAMS;
+ phy_ds_param_set->len = sizeof(phy_ds_param_set->current_chnl);
+- phy_ds_param_set->current_chnl = bss_conf->chandef.chan->hw_value;
++ phy_ds_param_set->current_chnl = bss_conf->chanreq.oper.chan->hw_value;
+
+ pcmd->start_cmd.probe_delay = cpu_to_le16(10);
+ pcmd->start_cmd.cap_info = cpu_to_le16(mwl_vif->beacon_info.cap_info);
+@@ -768,9 +772,9 @@ static int mwl_fwcmd_set_country_code(st
+ bool enable = false;
+
+ if (b_inf->ie_country_ptr) {
+- if (bss_conf->chandef.chan->band == NL80211_BAND_2GHZ)
++ if (bss_conf->chanreq.oper.chan->band == NL80211_BAND_2GHZ)
+ a_band = false;
+- else if (bss_conf->chandef.chan->band == NL80211_BAND_5GHZ)
++ else if (bss_conf->chanreq.oper.chan->band == NL80211_BAND_5GHZ)
+ a_band = true;
+ else
+ return -EINVAL;
@@ -2090,7 +2094,7 @@ int mwl_fwcmd_set_beacon(struct ieee8021
if (mwl_fwcmd_set_wsc_ie(hw, b_inf->ie_wsc_len, b_inf->ie_wsc_ptr))
goto err;
}
--- a/hif/pcie/8864/tx.c
+++ b/hif/pcie/8864/tx.c
+@@ -490,7 +490,7 @@ static void pcie_non_pfu_tx_done(struct
+ } else
+ memmove(dma_data->data - hdrlen, &dma_data->wh, hdrlen);
+ skb_pull(done_skb, sizeof(*dma_data) - hdrlen);
+- ieee80211_tx_status(priv->hw, done_skb);
++ ieee80211_tx_status_skb(priv->hw, done_skb);
+ dev_kfree_skb_any(done_skb);
+ done_skb = NULL;
+ }
@@ -743,7 +743,7 @@ void pcie_8864_tx_xmit(struct ieee80211_
index = SYSADPT_TX_WMM_QUEUES - index - 1;
txpriority = index;
!(xmitcontrol & EAGLE_TXD_XMITCTRL_USE_MC_RATE) &&
ieee80211_is_data_qos(wh->frame_control)) {
tid = qos & 0xf;
+@@ -925,4 +925,4 @@ void pcie_8864_tx_del_sta_amsdu_pkts(str
+ }
+ }
+ spin_unlock_bh(&sta_info->amsdu_lock);
+-}
+\ No newline at end of file
++}
--- a/hif/pcie/8964/tx_ndp.c
+++ b/hif/pcie/8964/tx_ndp.c
-@@ -607,7 +607,7 @@ void pcie_tx_xmit_ndp(struct ieee80211_h
+@@ -287,7 +287,7 @@ static inline int pcie_tx_skb_ndp(struct
+ skb_get(tx_skb);
+ pcie_tx_prepare_info(priv, tx_ctrl->rate, tx_info);
+ tx_ctrl->flags |= TX_CTRL_TYPE_DATA;
+- ieee80211_tx_status(priv->hw, tx_skb);
++ ieee80211_tx_status_skb(priv->hw, tx_skb);
+ }
+
+ if (++tx_send_head_new >= MAX_NUM_TX_DESC)
+@@ -488,7 +488,7 @@ void pcie_tx_done_ndp(struct ieee80211_h
+ }
+
+ pcie_tx_prepare_info(priv, 0, tx_info);
+- ieee80211_tx_status(hw, skb);
++ ieee80211_tx_status_skb(hw, skb);
+
+ bypass_ack:
+ if (++tx_done_tail >= MAX_TX_RING_DONE_SIZE)
+@@ -601,13 +601,13 @@ void pcie_tx_xmit_ndp(struct ieee80211_h
+ ack_skb = skb_copy(skb, GFP_ATOMIC);
+ ack_info = IEEE80211_SKB_CB(ack_skb);
+ pcie_tx_prepare_info(priv, 0, ack_info);
+- ieee80211_tx_status(hw, ack_skb);
++ ieee80211_tx_status_skb(hw, ack_skb);
+ }
+
pcie_tx_encapsulate_frame(priv, skb, k_conf);
} else {
tid = qos & 0x7;
pcie_priv->txbd_ring_size);
for (num = 0; num < PCIE_MAX_TXRX_BD; num++) {
+@@ -444,7 +444,7 @@ static void pcie_pfu_tx_done(struct mwl_
+ } else
+ memmove(dma_data->data - hdrlen, &dma_data->wh, hdrlen);
+ skb_pull(done_skb, sizeof(*pfu_dma) - hdrlen);
+- ieee80211_tx_status(priv->hw, done_skb);
++ ieee80211_tx_status_skb(priv->hw, done_skb);
+ }
+ }
+ next:
@@ -694,7 +694,7 @@ void pcie_8997_tx_xmit(struct ieee80211_
index = SYSADPT_TX_WMM_QUEUES - index - 1;
txpriority = index;
!(xmitcontrol & EAGLE_TXD_XMITCTRL_USE_MC_RATE) &&
ieee80211_is_data_qos(wh->frame_control)) {
tid = qos & 0xf;
+@@ -875,4 +875,4 @@ void pcie_8997_tx_del_sta_amsdu_pkts(str
+ }
+ }
+ spin_unlock_bh(&sta_info->amsdu_lock);
+-}
+\ No newline at end of file
++}
--- a/mac80211.c
+++ b/mac80211.c
@@ -368,15 +368,15 @@ static void mwl_mac80211_bss_info_change