aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches')
-rw-r--r--package/kernel/mac80211/patches/ath11k/0037-wifi-ath11k-allow-system-suspend-to-survive-ath11k.patch43
-rw-r--r--package/kernel/mac80211/patches/ath11k/0038-wifi-ath11k-modify-accessor-macros-to-match-index-si.patch61
-rw-r--r--package/kernel/mac80211/patches/ath11k/0039-wifi-ath11k-push-MU-MIMO-params-from-hostapd-to-hard.patch300
-rw-r--r--package/kernel/mac80211/patches/ath11k/0040-wifi-ath11k-move-HE-MCS-mapper-to-a-separate-functio.patch67
-rw-r--r--package/kernel/mac80211/patches/ath11k/0041-wifi-ath11k-generate-rx-and-tx-mcs-maps-for-supporte.patch64
-rw-r--r--package/kernel/mac80211/patches/ath11k/0042-wifi-ath11k-Add-tx-ack-signal-support-for-management.patch150
-rw-r--r--package/kernel/mac80211/patches/ath11k/0043-wifi-ath11k-use-proper-regulatory-reference-for-band.patch216
-rw-r--r--package/kernel/mac80211/patches/ath11k/0044-wifi-ath11k-add-support-to-parse-new-WMI-event-for-6.patch844
-rw-r--r--package/kernel/mac80211/patches/ath11k/0045-wifi-ath11k-add-debug-prints-in-regulatory-WMI-event.patch567
-rw-r--r--package/kernel/mac80211/patches/ath11k/0046-wifi-ath11k-Replace-fake-flex-array-with-flexible-ar.patch246
-rw-r--r--package/kernel/mac80211/patches/ath11k/0047-wifi-ath11k-fix-deinitialization-of-firmware-resourc.patch79
11 files changed, 2637 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/ath11k/0037-wifi-ath11k-allow-system-suspend-to-survive-ath11k.patch b/package/kernel/mac80211/patches/ath11k/0037-wifi-ath11k-allow-system-suspend-to-survive-ath11k.patch
new file mode 100644
index 0000000000..cd8ab3dc4e
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0037-wifi-ath11k-allow-system-suspend-to-survive-ath11k.patch
@@ -0,0 +1,43 @@
+From 7c15430822e71e90203d87e6d0cfe83fa058b0dc Mon Sep 17 00:00:00 2001
+From: Len Brown <len.brown@intel.com>
+Date: Wed, 1 Feb 2023 12:32:01 -0600
+Subject: [PATCH] wifi: ath11k: allow system suspend to survive ath11k
+
+When ath11k runs into internal errors upon suspend,
+it returns an error code to pci_pm_suspend, which
+aborts the entire system suspend.
+
+The driver should not abort system suspend, but should
+keep its internal errors to itself, and allow the system
+to suspend. Otherwise, a user can suspend a laptop
+by closing the lid and sealing it into a case, assuming
+that is will suspend, rather than heating up and draining
+the battery when in transit.
+
+In practice, the ath11k device seems to have plenty of transient
+errors, and subsequent suspend cycles after this failure
+often succeed.
+
+https://bugzilla.kernel.org/show_bug.cgi?id=216968
+
+Fixes: d1b0c33850d29 ("ath11k: implement suspend for QCA6390 PCI devices")
+
+Signed-off-by: Len Brown <len.brown@intel.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/20230201183201.14431-1-len.brown@intel.com
+---
+ drivers/net/wireless/ath/ath11k/pci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -981,7 +981,7 @@ static __maybe_unused int ath11k_pci_pm_
+ if (ret)
+ ath11k_warn(ab, "failed to suspend core: %d\n", ret);
+
+- return ret;
++ return 0;
+ }
+
+ static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
diff --git a/package/kernel/mac80211/patches/ath11k/0038-wifi-ath11k-modify-accessor-macros-to-match-index-si.patch b/package/kernel/mac80211/patches/ath11k/0038-wifi-ath11k-modify-accessor-macros-to-match-index-si.patch
new file mode 100644
index 0000000000..42bf170a03
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0038-wifi-ath11k-modify-accessor-macros-to-match-index-si.patch
@@ -0,0 +1,61 @@
+From a96f10422e74cde27c100b321b127ec32ae75747 Mon Sep 17 00:00:00 2001
+From: Muna Sinada <quic_msinada@quicinc.com>
+Date: Fri, 24 Feb 2023 12:28:03 +0200
+Subject: [PATCH] wifi: ath11k: modify accessor macros to match index size
+
+HE PHY is only 11 bytes, therefore it should be using byte indexes
+instead of dword. Change corresponding macros to reflect this.
+
+Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/1666128501-12364-2-git-send-email-quic_msinada@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/wmi.h | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/wmi.h
++++ b/drivers/net/wireless/ath/ath11k/wmi.h
+@@ -2859,30 +2859,32 @@ struct rx_reorder_queue_remove_params {
+ #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2)
+ #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
+
+-#define HECAP_PHYDWORD_0 0
+-#define HECAP_PHYDWORD_1 1
+-#define HECAP_PHYDWORD_2 2
++#define HE_PHYCAP_BYTE_0 0
++#define HE_PHYCAP_BYTE_1 1
++#define HE_PHYCAP_BYTE_2 2
++#define HE_PHYCAP_BYTE_3 3
++#define HE_PHYCAP_BYTE_4 4
+
+-#define HECAP_PHY_SU_BFER BIT(31)
++#define HECAP_PHY_SU_BFER BIT(7)
+ #define HECAP_PHY_SU_BFEE BIT(0)
+ #define HECAP_PHY_MU_BFER BIT(1)
+-#define HECAP_PHY_UL_MUMIMO BIT(22)
+-#define HECAP_PHY_UL_MUOFDMA BIT(23)
++#define HECAP_PHY_UL_MUMIMO BIT(6)
++#define HECAP_PHY_UL_MUOFDMA BIT(7)
+
+ #define HECAP_PHY_SUBFMR_GET(hecap_phy) \
+- FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HECAP_PHYDWORD_0])
++ FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HE_PHYCAP_BYTE_3])
+
+ #define HECAP_PHY_SUBFME_GET(hecap_phy) \
+- FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HECAP_PHYDWORD_1])
++ FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HE_PHYCAP_BYTE_4])
+
+ #define HECAP_PHY_MUBFMR_GET(hecap_phy) \
+- FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HECAP_PHYDWORD_1])
++ FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HE_PHYCAP_BYTE_4])
+
+ #define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \
+- FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HECAP_PHYDWORD_0])
++ FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HE_PHYCAP_BYTE_2])
+
+ #define HECAP_PHY_ULOFDMA_GET(hecap_phy) \
+- FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HECAP_PHYDWORD_0])
++ FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HE_PHYCAP_BYTE_2])
+
+ #define HE_MODE_SU_TX_BFEE BIT(0)
+ #define HE_MODE_SU_TX_BFER BIT(1)
diff --git a/package/kernel/mac80211/patches/ath11k/0039-wifi-ath11k-push-MU-MIMO-params-from-hostapd-to-hard.patch b/package/kernel/mac80211/patches/ath11k/0039-wifi-ath11k-push-MU-MIMO-params-from-hostapd-to-hard.patch
new file mode 100644
index 0000000000..298ce1a612
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0039-wifi-ath11k-push-MU-MIMO-params-from-hostapd-to-hard.patch
@@ -0,0 +1,300 @@
+From 38dfe775d0abf511341f37c1cb77b919a3ad410b Mon Sep 17 00:00:00 2001
+From: Muna Sinada <quic_msinada@quicinc.com>
+Date: Fri, 24 Feb 2023 12:28:04 +0200
+Subject: [PATCH] wifi: ath11k: push MU-MIMO params from hostapd to hardware
+
+In the previous behaviour only HE IE in management frames are changed
+regarding MU-MIMO configurations and not in hardware. Adding push of
+MU-MIMO configurations to the hardware as well.
+
+Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-00356-QCAHKSWPL_SILICONZ-1
+
+Co-developed-by: Anilkumar Kolli <quic_akolli@quicinc.com>
+Signed-off-by: Anilkumar Kolli <quic_akolli@quicinc.com>
+Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/1666128501-12364-3-git-send-email-quic_msinada@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/mac.c | 200 ++++++++++++++++----------
+ drivers/net/wireless/ath/ath11k/wmi.h | 3 +
+ 2 files changed, 130 insertions(+), 73 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -2699,6 +2699,117 @@ static int ath11k_setup_peer_smps(struct
+ ath11k_smps_map[smps]);
+ }
+
++static bool ath11k_mac_set_he_txbf_conf(struct ath11k_vif *arvif)
++{
++ struct ath11k *ar = arvif->ar;
++ u32 param, value;
++ int ret;
++
++ if (!arvif->vif->bss_conf.he_support)
++ return true;
++
++ param = WMI_VDEV_PARAM_SET_HEMU_MODE;
++ value = 0;
++ if (arvif->vif->bss_conf.he_su_beamformer) {
++ value |= FIELD_PREP(HE_MODE_SU_TX_BFER, HE_SU_BFER_ENABLE);
++ if (arvif->vif->bss_conf.he_mu_beamformer &&
++ arvif->vdev_type == WMI_VDEV_TYPE_AP)
++ value |= FIELD_PREP(HE_MODE_MU_TX_BFER, HE_MU_BFER_ENABLE);
++ }
++
++ if (arvif->vif->type != NL80211_IFTYPE_MESH_POINT) {
++ value |= FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) |
++ FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE);
++
++ if (arvif->vif->bss_conf.he_full_ul_mumimo)
++ value |= FIELD_PREP(HE_MODE_UL_MUMIMO, HE_UL_MUMIMO_ENABLE);
++
++ if (arvif->vif->bss_conf.he_su_beamformee)
++ value |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE);
++ }
++
++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, value);
++ if (ret) {
++ ath11k_warn(ar->ab, "failed to set vdev %d HE MU mode: %d\n",
++ arvif->vdev_id, ret);
++ return false;
++ }
++
++ param = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE;
++ value = FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) |
++ FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE,
++ HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE);
++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
++ param, value);
++ if (ret) {
++ ath11k_warn(ar->ab, "failed to set vdev %d sounding mode: %d\n",
++ arvif->vdev_id, ret);
++ return false;
++ }
++ return true;
++}
++
++static bool ath11k_mac_vif_recalc_sta_he_txbf(struct ath11k *ar,
++ struct ieee80211_vif *vif,
++ struct ieee80211_sta_he_cap *he_cap)
++{
++ struct ath11k_vif *arvif = (void *)vif->drv_priv;
++ struct ieee80211_he_cap_elem he_cap_elem = {0};
++ struct ieee80211_sta_he_cap *cap_band = NULL;
++ struct cfg80211_chan_def def;
++ u32 param = WMI_VDEV_PARAM_SET_HEMU_MODE;
++ u32 hemode = 0;
++ int ret;
++
++ if (!vif->bss_conf.he_support)
++ return true;
++
++ if (vif->type != NL80211_IFTYPE_STATION)
++ return false;
++
++ if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
++ return false;
++
++ if (def.chan->band == NL80211_BAND_2GHZ)
++ cap_band = &ar->mac.iftype[NL80211_BAND_2GHZ][vif->type].he_cap;
++ else
++ cap_band = &ar->mac.iftype[NL80211_BAND_5GHZ][vif->type].he_cap;
++
++ memcpy(&he_cap_elem, &cap_band->he_cap_elem, sizeof(he_cap_elem));
++
++ if (HECAP_PHY_SUBFME_GET(he_cap_elem.phy_cap_info)) {
++ if (HECAP_PHY_SUBFMR_GET(he_cap->he_cap_elem.phy_cap_info))
++ hemode |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE);
++ if (HECAP_PHY_MUBFMR_GET(he_cap->he_cap_elem.phy_cap_info))
++ hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE);
++ }
++
++ if (vif->type != NL80211_IFTYPE_MESH_POINT) {
++ hemode |= FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) |
++ FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE);
++
++ if (HECAP_PHY_ULMUMIMO_GET(he_cap_elem.phy_cap_info))
++ if (HECAP_PHY_ULMUMIMO_GET(he_cap->he_cap_elem.phy_cap_info))
++ hemode |= FIELD_PREP(HE_MODE_UL_MUMIMO,
++ HE_UL_MUMIMO_ENABLE);
++
++ if (FIELD_GET(HE_MODE_MU_TX_BFEE, hemode))
++ hemode |= FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE);
++
++ if (FIELD_GET(HE_MODE_MU_TX_BFER, hemode))
++ hemode |= FIELD_PREP(HE_MODE_SU_TX_BFER, HE_SU_BFER_ENABLE);
++ }
++
++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, hemode);
++ if (ret) {
++ ath11k_warn(ar->ab, "failed to submit vdev param txbf 0x%x: %d\n",
++ hemode, ret);
++ return false;
++ }
++
++ return true;
++}
++
+ static void ath11k_bss_assoc(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf)
+@@ -2709,6 +2820,7 @@ static void ath11k_bss_assoc(struct ieee
+ struct ieee80211_sta *ap_sta;
+ struct ath11k_peer *peer;
+ bool is_auth = false;
++ struct ieee80211_sta_he_cap he_cap;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+@@ -2726,6 +2838,9 @@ static void ath11k_bss_assoc(struct ieee
+ return;
+ }
+
++ /* he_cap here is updated at assoc success for sta mode only */
++ he_cap = ap_sta->deflink.he_cap;
++
+ ath11k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false);
+
+ rcu_read_unlock();
+@@ -2753,6 +2868,12 @@ static void ath11k_bss_assoc(struct ieee
+ return;
+ }
+
++ if (!ath11k_mac_vif_recalc_sta_he_txbf(ar, vif, &he_cap)) {
++ ath11k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM\n",
++ arvif->vdev_id, bss_conf->bssid);
++ return;
++ }
++
+ WARN_ON(arvif->is_up);
+
+ arvif->aid = vif->cfg.aid;
+@@ -3202,6 +3323,8 @@ static void ath11k_mac_op_bss_info_chang
+ ether_addr_copy(arvif->bssid, info->bssid);
+
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
++ if (info->enable_beacon)
++ ath11k_mac_set_he_txbf_conf(arvif);
+ ath11k_control_beaconing(arvif, info);
+
+ if (arvif->is_up && vif->bss_conf.he_support &&
+@@ -5392,6 +5515,10 @@ static int ath11k_mac_copy_he_cap(struct
+
+ he_cap_elem->mac_cap_info[1] &=
+ IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
++ he_cap_elem->phy_cap_info[0] &=
++ ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
++ he_cap_elem->phy_cap_info[0] &=
++ ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
+
+ he_cap_elem->phy_cap_info[5] &=
+ ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
+@@ -6026,69 +6153,6 @@ ath11k_mac_setup_vdev_create_params(stru
+ }
+ }
+
+-static u32
+-ath11k_mac_prepare_he_mode(struct ath11k_pdev *pdev, u32 viftype)
+-{
+- struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
+- struct ath11k_band_cap *cap_band = NULL;
+- u32 *hecap_phy_ptr = NULL;
+- u32 hemode = 0;
+-
+- if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP)
+- cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];
+- else
+- cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];
+-
+- hecap_phy_ptr = &cap_band->he_cap_phy_info[0];
+-
+- hemode = FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE) |
+- FIELD_PREP(HE_MODE_SU_TX_BFER, HECAP_PHY_SUBFMR_GET(hecap_phy_ptr)) |
+- FIELD_PREP(HE_MODE_UL_MUMIMO, HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr));
+-
+- /* TODO WDS and other modes */
+- if (viftype == NL80211_IFTYPE_AP) {
+- hemode |= FIELD_PREP(HE_MODE_MU_TX_BFER,
+- HECAP_PHY_MUBFMR_GET(hecap_phy_ptr)) |
+- FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) |
+- FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE);
+- } else {
+- hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE);
+- }
+-
+- return hemode;
+-}
+-
+-static int ath11k_set_he_mu_sounding_mode(struct ath11k *ar,
+- struct ath11k_vif *arvif)
+-{
+- u32 param_id, param_value;
+- struct ath11k_base *ab = ar->ab;
+- int ret = 0;
+-
+- param_id = WMI_VDEV_PARAM_SET_HEMU_MODE;
+- param_value = ath11k_mac_prepare_he_mode(ar->pdev, arvif->vif->type);
+- ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+- param_id, param_value);
+- if (ret) {
+- ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n",
+- arvif->vdev_id, ret, param_value);
+- return ret;
+- }
+- param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE;
+- param_value =
+- FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) |
+- FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE,
+- HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE);
+- ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+- param_id, param_value);
+- if (ret) {
+- ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d\n",
+- arvif->vdev_id, ret);
+- return ret;
+- }
+- return ret;
+-}
+-
+ static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+ {
+@@ -6757,7 +6821,6 @@ ath11k_mac_vdev_start_restart(struct ath
+ struct ath11k_base *ab = ar->ab;
+ struct wmi_vdev_start_req_arg arg = {};
+ const struct cfg80211_chan_def *chandef = &ctx->def;
+- int he_support = arvif->vif->bss_conf.he_support;
+ int ret = 0;
+
+ lockdep_assert_held(&ar->conf_mutex);
+@@ -6798,15 +6861,6 @@ ath11k_mac_vdev_start_restart(struct ath
+ spin_lock_bh(&ab->base_lock);
+ arg.regdomain = ar->ab->dfs_region;
+ spin_unlock_bh(&ab->base_lock);
+-
+- if (he_support) {
+- ret = ath11k_set_he_mu_sounding_mode(ar, arvif);
+- if (ret) {
+- ath11k_warn(ar->ab, "failed to set he mode vdev %i\n",
+- arg.vdev_id);
+- return ret;
+- }
+- }
+ }
+
+ arg.channel.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR);
+--- a/drivers/net/wireless/ath/ath11k/wmi.h
++++ b/drivers/net/wireless/ath/ath11k/wmi.h
+@@ -2897,8 +2897,11 @@ struct rx_reorder_queue_remove_params {
+ #define HE_DL_MUOFDMA_ENABLE 1
+ #define HE_UL_MUOFDMA_ENABLE 1
+ #define HE_DL_MUMIMO_ENABLE 1
++#define HE_UL_MUMIMO_ENABLE 1
+ #define HE_MU_BFEE_ENABLE 1
+ #define HE_SU_BFEE_ENABLE 1
++#define HE_MU_BFER_ENABLE 1
++#define HE_SU_BFER_ENABLE 1
+
+ #define HE_VHT_SOUNDING_MODE_ENABLE 1
+ #define HE_SU_MU_SOUNDING_MODE_ENABLE 1
diff --git a/package/kernel/mac80211/patches/ath11k/0040-wifi-ath11k-move-HE-MCS-mapper-to-a-separate-functio.patch b/package/kernel/mac80211/patches/ath11k/0040-wifi-ath11k-move-HE-MCS-mapper-to-a-separate-functio.patch
new file mode 100644
index 0000000000..6bc9880e10
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0040-wifi-ath11k-move-HE-MCS-mapper-to-a-separate-functio.patch
@@ -0,0 +1,67 @@
+From 8077c1bbbc28e527fb29143c46f32c6a9d6cadf0 Mon Sep 17 00:00:00 2001
+From: Muna Sinada <quic_msinada@quicinc.com>
+Date: Fri, 24 Feb 2023 12:28:04 +0200
+Subject: [PATCH] wifi: ath11k: move HE MCS mapper to a separate function
+
+Move HE MCS mapper to a separate function and call new function
+in ath11k_mac_copy_he_cap().
+
+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>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/1666128501-12364-4-git-send-email-quic_msinada@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/mac.c | 34 +++++++++++++++++----------
+ 1 file changed, 22 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -5483,6 +5483,27 @@ static __le16 ath11k_mac_setup_he_6ghz_c
+ return cpu_to_le16(bcap->he_6ghz_capa);
+ }
+
++static void ath11k_mac_set_hemcsmap(struct ath11k *ar,
++ struct ath11k_pdev_cap *cap,
++ struct ieee80211_sta_he_cap *he_cap,
++ int band)
++{
++ struct ath11k_band_cap *band_cap = &cap->band[band];
++
++ he_cap->he_mcs_nss_supp.rx_mcs_80 =
++ cpu_to_le16(band_cap->he_mcs & 0xffff);
++ he_cap->he_mcs_nss_supp.tx_mcs_80 =
++ cpu_to_le16(band_cap->he_mcs & 0xffff);
++ he_cap->he_mcs_nss_supp.rx_mcs_160 =
++ cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++ he_cap->he_mcs_nss_supp.tx_mcs_160 =
++ cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++ he_cap->he_mcs_nss_supp.rx_mcs_80p80 =
++ cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++ he_cap->he_mcs_nss_supp.tx_mcs_80p80 =
++ cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++}
++
+ static int ath11k_mac_copy_he_cap(struct ath11k *ar,
+ struct ath11k_pdev_cap *cap,
+ struct ieee80211_sband_iftype_data *data,
+@@ -5544,18 +5565,7 @@ static int ath11k_mac_copy_he_cap(struct
+ break;
+ }
+
+- he_cap->he_mcs_nss_supp.rx_mcs_80 =
+- cpu_to_le16(band_cap->he_mcs & 0xffff);
+- he_cap->he_mcs_nss_supp.tx_mcs_80 =
+- cpu_to_le16(band_cap->he_mcs & 0xffff);
+- he_cap->he_mcs_nss_supp.rx_mcs_160 =
+- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+- he_cap->he_mcs_nss_supp.tx_mcs_160 =
+- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+- he_cap->he_mcs_nss_supp.rx_mcs_80p80 =
+- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
+- he_cap->he_mcs_nss_supp.tx_mcs_80p80 =
+- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++ ath11k_mac_set_hemcsmap(ar, cap, he_cap, band);
+
+ memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
+ if (he_cap_elem->phy_cap_info[6] &
diff --git a/package/kernel/mac80211/patches/ath11k/0041-wifi-ath11k-generate-rx-and-tx-mcs-maps-for-supporte.patch b/package/kernel/mac80211/patches/ath11k/0041-wifi-ath11k-generate-rx-and-tx-mcs-maps-for-supporte.patch
new file mode 100644
index 0000000000..5cb7801b29
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0041-wifi-ath11k-generate-rx-and-tx-mcs-maps-for-supporte.patch
@@ -0,0 +1,64 @@
+From ebf82988f844dd98e6b007cffcc5e95986056995 Mon Sep 17 00:00:00 2001
+From: Muna Sinada <quic_msinada@quicinc.com>
+Date: Fri, 24 Feb 2023 12:28:04 +0200
+Subject: [PATCH] wifi: ath11k: generate rx and tx mcs maps for supported HE
+ mcs
+
+Generate rx and tx mcs maps in ath11k_mac_set_hemcsmap() and set them
+in supported mcs/nss for HE capabilities.
+
+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>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/1666128501-12364-5-git-send-email-quic_msinada@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/mac.c | 30 ++++++++++++++++++++-------
+ 1 file changed, 23 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -5488,20 +5488,36 @@ static void ath11k_mac_set_hemcsmap(stru
+ struct ieee80211_sta_he_cap *he_cap,
+ int band)
+ {
+- struct ath11k_band_cap *band_cap = &cap->band[band];
++ u16 txmcs_map, rxmcs_map;
++ u32 i;
+
++ rxmcs_map = 0;
++ txmcs_map = 0;
++ for (i = 0; i < 8; i++) {
++ if (i < ar->num_tx_chains &&
++ (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i))
++ txmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2);
++ else
++ txmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2);
++
++ if (i < ar->num_rx_chains &&
++ (ar->cfg_rx_chainmask >> cap->tx_chain_mask_shift) & BIT(i))
++ rxmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2);
++ else
++ rxmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2);
++ }
+ he_cap->he_mcs_nss_supp.rx_mcs_80 =
+- cpu_to_le16(band_cap->he_mcs & 0xffff);
++ cpu_to_le16(rxmcs_map & 0xffff);
+ he_cap->he_mcs_nss_supp.tx_mcs_80 =
+- cpu_to_le16(band_cap->he_mcs & 0xffff);
++ cpu_to_le16(txmcs_map & 0xffff);
+ he_cap->he_mcs_nss_supp.rx_mcs_160 =
+- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++ cpu_to_le16(rxmcs_map & 0xffff);
+ he_cap->he_mcs_nss_supp.tx_mcs_160 =
+- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++ cpu_to_le16(txmcs_map & 0xffff);
+ he_cap->he_mcs_nss_supp.rx_mcs_80p80 =
+- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++ cpu_to_le16(rxmcs_map & 0xffff);
+ he_cap->he_mcs_nss_supp.tx_mcs_80p80 =
+- cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
++ cpu_to_le16(txmcs_map & 0xffff);
+ }
+
+ static int ath11k_mac_copy_he_cap(struct ath11k *ar,
diff --git a/package/kernel/mac80211/patches/ath11k/0042-wifi-ath11k-Add-tx-ack-signal-support-for-management.patch b/package/kernel/mac80211/patches/ath11k/0042-wifi-ath11k-Add-tx-ack-signal-support-for-management.patch
new file mode 100644
index 0000000000..8d41657311
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0042-wifi-ath11k-Add-tx-ack-signal-support-for-management.patch
@@ -0,0 +1,150 @@
+From 01c6c9fccbd51c1d9eab0f5794b0271b026178df Mon Sep 17 00:00:00 2001
+From: Abinaya Kalaiselvan <quic_akalaise@quicinc.com>
+Date: Mon, 19 Dec 2022 11:08:44 +0530
+Subject: [PATCH] wifi: ath11k: Add tx ack signal support for management
+ packets
+
+Add support to notify tx ack signal values for management
+packets to userspace through nl80211 interface.
+
+Advertise NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT flag
+to enable this feature and it will be used for data
+packets as well.
+
+Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Abinaya Kalaiselvan <quic_akalaise@quicinc.com>
+Signed-off-by: Maharaja Kennadyrajan <quic_mkenna@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/20221219053844.4084486-1-quic_mkenna@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/hw.c | 1 +
+ drivers/net/wireless/ath/ath11k/mac.c | 5 +++++
+ drivers/net/wireless/ath/ath11k/wmi.c | 27 ++++++++++++++++-----------
+ drivers/net/wireless/ath/ath11k/wmi.h | 3 +++
+ 4 files changed, 25 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/hw.c
++++ b/drivers/net/wireless/ath/ath11k/hw.c
+@@ -201,6 +201,7 @@ static void ath11k_init_wmi_config_ipq80
+ config->twt_ap_pdev_count = ab->num_radios;
+ config->twt_ap_sta_count = 1000;
+ config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64;
++ config->flag1 |= WMI_RSRC_CFG_FLAG1_ACK_RSSI;
+ }
+
+ static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw,
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -9174,6 +9174,11 @@ static int __ath11k_mac_register(struct
+ goto err_free_if_combs;
+ }
+
++ if (test_bit(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI,
++ ar->ab->wmi_ab.svc_map))
++ wiphy_ext_feature_set(ar->hw->wiphy,
++ NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
++
+ ar->hw->queues = ATH11K_HW_MAX_QUEUES;
+ ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN;
+ ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1;
+--- a/drivers/net/wireless/ath/ath11k/wmi.c
++++ b/drivers/net/wireless/ath/ath11k/wmi.c
+@@ -5229,8 +5229,8 @@ static int ath11k_pull_mgmt_rx_params_tl
+ return 0;
+ }
+
+-static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
+- u32 status)
++static int wmi_process_mgmt_tx_comp(struct ath11k *ar,
++ struct wmi_mgmt_tx_compl_event *tx_compl_param)
+ {
+ struct sk_buff *msdu;
+ struct ieee80211_tx_info *info;
+@@ -5238,24 +5238,29 @@ static int wmi_process_mgmt_tx_comp(stru
+ int num_mgmt;
+
+ spin_lock_bh(&ar->txmgmt_idr_lock);
+- msdu = idr_find(&ar->txmgmt_idr, desc_id);
++ msdu = idr_find(&ar->txmgmt_idr, tx_compl_param->desc_id);
+
+ if (!msdu) {
+ ath11k_warn(ar->ab, "received mgmt tx compl for invalid msdu_id: %d\n",
+- desc_id);
++ tx_compl_param->desc_id);
+ spin_unlock_bh(&ar->txmgmt_idr_lock);
+ return -ENOENT;
+ }
+
+- idr_remove(&ar->txmgmt_idr, desc_id);
++ idr_remove(&ar->txmgmt_idr, tx_compl_param->desc_id);
+ spin_unlock_bh(&ar->txmgmt_idr_lock);
+
+ skb_cb = ATH11K_SKB_CB(msdu);
+ dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+
+ info = IEEE80211_SKB_CB(msdu);
+- if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status)
++ if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) &&
++ !tx_compl_param->status) {
+ info->flags |= IEEE80211_TX_STAT_ACK;
++ if (test_bit(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI,
++ ar->ab->wmi_ab.svc_map))
++ info->status.ack_signal = tx_compl_param->ack_rssi;
++ }
+
+ ieee80211_tx_status_irqsafe(ar->hw, msdu);
+
+@@ -5267,7 +5272,7 @@ static int wmi_process_mgmt_tx_comp(stru
+
+ ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+ "wmi mgmt tx comp pending %d desc id %d\n",
+- num_mgmt, desc_id);
++ num_mgmt, tx_compl_param->desc_id);
+
+ if (!num_mgmt)
+ wake_up(&ar->txmgmt_empty_waitq);
+@@ -5300,6 +5305,7 @@ static int ath11k_pull_mgmt_tx_compl_par
+ param->pdev_id = ev->pdev_id;
+ param->desc_id = ev->desc_id;
+ param->status = ev->status;
++ param->ack_rssi = ev->ack_rssi;
+
+ kfree(tb);
+ return 0;
+@@ -7070,13 +7076,12 @@ static void ath11k_mgmt_tx_compl_event(s
+ goto exit;
+ }
+
+- wmi_process_mgmt_tx_comp(ar, tx_compl_param.desc_id,
+- tx_compl_param.status);
++ wmi_process_mgmt_tx_comp(ar, &tx_compl_param);
+
+ ath11k_dbg(ab, ATH11K_DBG_MGMT,
+- "mgmt tx compl ev pdev_id %d, desc_id %d, status %d",
++ "mgmt tx compl ev pdev_id %d, desc_id %d, status %d ack_rssi %d",
+ tx_compl_param.pdev_id, tx_compl_param.desc_id,
+- tx_compl_param.status);
++ tx_compl_param.status, tx_compl_param.ack_rssi);
+
+ exit:
+ rcu_read_unlock();
+--- a/drivers/net/wireless/ath/ath11k/wmi.h
++++ b/drivers/net/wireless/ath/ath11k/wmi.h
+@@ -2311,6 +2311,7 @@ struct wmi_init_cmd {
+ } __packed;
+
+ #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5)
++#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18)
+
+ struct wmi_resource_config {
+ u32 tlv_header;
+@@ -4550,6 +4551,8 @@ struct wmi_mgmt_tx_compl_event {
+ u32 desc_id;
+ u32 status;
+ u32 pdev_id;
++ u32 ppdu_id;
++ u32 ack_rssi;
+ } __packed;
+
+ struct wmi_scan_event {
diff --git a/package/kernel/mac80211/patches/ath11k/0043-wifi-ath11k-use-proper-regulatory-reference-for-band.patch b/package/kernel/mac80211/patches/ath11k/0043-wifi-ath11k-use-proper-regulatory-reference-for-band.patch
new file mode 100644
index 0000000000..5bc195528e
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0043-wifi-ath11k-use-proper-regulatory-reference-for-band.patch
@@ -0,0 +1,216 @@
+From 25e289e1f52e1f4fb1d07622c6a24f8d8a8e420d Mon Sep 17 00:00:00 2001
+From: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Date: Wed, 1 Mar 2023 16:20:58 +0200
+Subject: [PATCH] wifi: ath11k: use proper regulatory reference for bands
+
+Currently, during regulatory event, 2 GHz/5 GHz is referred
+to as 2G/5G including variable names. However, there is no
+such entity as 2G or 5G.
+
+Re-name such occurences to its proper name. No functional changes.
+
+Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/20230110121024.14051-2-quic_adisi@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/reg.c | 20 ++++-----
+ drivers/net/wireless/ath/ath11k/wmi.c | 58 ++++++++++++++-------------
+ drivers/net/wireless/ath/ath11k/wmi.h | 28 ++++++-------
+ 3 files changed, 54 insertions(+), 52 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/reg.c
++++ b/drivers/net/wireless/ath/ath11k/reg.c
+@@ -619,7 +619,7 @@ ath11k_reg_build_regd(struct ath11k_base
+ u32 flags;
+ char alpha2[3];
+
+- num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
++ num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules;
+
+ if (!num_rules)
+ goto ret;
+@@ -644,20 +644,20 @@ ath11k_reg_build_regd(struct ath11k_base
+ alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region),
+ reg_info->dfs_region, num_rules);
+ /* Update reg_rules[] below. Firmware is expected to
+- * send these rules in order(2G rules first and then 5G)
++ * send these rules in order(2 GHz rules first and then 5 GHz)
+ */
+ for (; i < num_rules; i++) {
+- if (reg_info->num_2g_reg_rules &&
+- (i < reg_info->num_2g_reg_rules)) {
+- reg_rule = reg_info->reg_rules_2g_ptr + i;
++ if (reg_info->num_2ghz_reg_rules &&
++ (i < reg_info->num_2ghz_reg_rules)) {
++ reg_rule = reg_info->reg_rules_2ghz_ptr + i;
+ max_bw = min_t(u16, reg_rule->max_bw,
+- reg_info->max_bw_2g);
++ reg_info->max_bw_2ghz);
+ flags = 0;
+- } else if (reg_info->num_5g_reg_rules &&
+- (j < reg_info->num_5g_reg_rules)) {
+- reg_rule = reg_info->reg_rules_5g_ptr + j++;
++ } else if (reg_info->num_5ghz_reg_rules &&
++ (j < reg_info->num_5ghz_reg_rules)) {
++ reg_rule = reg_info->reg_rules_5ghz_ptr + j++;
+ max_bw = min_t(u16, reg_rule->max_bw,
+- reg_info->max_bw_5g);
++ reg_info->max_bw_5ghz);
+
+ /* FW doesn't pass NL80211_RRF_AUTO_BW flag for
+ * BW Auto correction, we can enable this by default
+--- a/drivers/net/wireless/ath/ath11k/wmi.c
++++ b/drivers/net/wireless/ath/ath11k/wmi.c
+@@ -4959,7 +4959,7 @@ static int ath11k_pull_reg_chan_list_upd
+ const void **tb;
+ const struct wmi_reg_chan_list_cc_event *chan_list_event_hdr;
+ struct wmi_regulatory_rule_struct *wmi_reg_rule;
+- u32 num_2g_reg_rules, num_5g_reg_rules;
++ u32 num_2ghz_reg_rules, num_5ghz_reg_rules;
+ int ret;
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory channel list\n");
+@@ -4978,10 +4978,10 @@ static int ath11k_pull_reg_chan_list_upd
+ return -EPROTO;
+ }
+
+- reg_info->num_2g_reg_rules = chan_list_event_hdr->num_2g_reg_rules;
+- reg_info->num_5g_reg_rules = chan_list_event_hdr->num_5g_reg_rules;
++ reg_info->num_2ghz_reg_rules = chan_list_event_hdr->num_2ghz_reg_rules;
++ reg_info->num_5ghz_reg_rules = chan_list_event_hdr->num_5ghz_reg_rules;
+
+- if (!(reg_info->num_2g_reg_rules + reg_info->num_5g_reg_rules)) {
++ if (!(reg_info->num_2ghz_reg_rules + reg_info->num_5ghz_reg_rules)) {
+ ath11k_warn(ab, "No regulatory rules available in the event info\n");
+ kfree(tb);
+ return -EINVAL;
+@@ -5008,46 +5008,48 @@ static int ath11k_pull_reg_chan_list_upd
+ else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_FAIL)
+ reg_info->status_code = REG_SET_CC_STATUS_FAIL;
+
+- reg_info->min_bw_2g = chan_list_event_hdr->min_bw_2g;
+- reg_info->max_bw_2g = chan_list_event_hdr->max_bw_2g;
+- reg_info->min_bw_5g = chan_list_event_hdr->min_bw_5g;
+- reg_info->max_bw_5g = chan_list_event_hdr->max_bw_5g;
++ reg_info->min_bw_2ghz = chan_list_event_hdr->min_bw_2ghz;
++ reg_info->max_bw_2ghz = chan_list_event_hdr->max_bw_2ghz;
++ reg_info->min_bw_5ghz = chan_list_event_hdr->min_bw_5ghz;
++ reg_info->max_bw_5ghz = chan_list_event_hdr->max_bw_5ghz;
+
+- num_2g_reg_rules = reg_info->num_2g_reg_rules;
+- num_5g_reg_rules = reg_info->num_5g_reg_rules;
++ num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules;
++ num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules;
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
+- "%s:cc %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",
++ "%s:cc %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
+ __func__, reg_info->alpha2, reg_info->dfs_region,
+- reg_info->min_bw_2g, reg_info->max_bw_2g,
+- reg_info->min_bw_5g, reg_info->max_bw_5g);
++ reg_info->min_bw_2ghz, reg_info->max_bw_2ghz,
++ reg_info->min_bw_5ghz, reg_info->max_bw_5ghz);
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
+- "%s: num_2g_reg_rules %d num_5g_reg_rules %d", __func__,
+- num_2g_reg_rules, num_5g_reg_rules);
++ "%s: num_2ghz_reg_rules %d num_5ghz_reg_rules %d", __func__,
++ num_2ghz_reg_rules, num_5ghz_reg_rules);
+
+ wmi_reg_rule =
+ (struct wmi_regulatory_rule_struct *)((u8 *)chan_list_event_hdr
+ + sizeof(*chan_list_event_hdr)
+ + sizeof(struct wmi_tlv));
+
+- if (num_2g_reg_rules) {
+- reg_info->reg_rules_2g_ptr = create_reg_rules_from_wmi(num_2g_reg_rules,
+- wmi_reg_rule);
+- if (!reg_info->reg_rules_2g_ptr) {
++ if (num_2ghz_reg_rules) {
++ reg_info->reg_rules_2ghz_ptr =
++ create_reg_rules_from_wmi(num_2ghz_reg_rules,
++ wmi_reg_rule);
++ if (!reg_info->reg_rules_2ghz_ptr) {
+ kfree(tb);
+- ath11k_warn(ab, "Unable to Allocate memory for 2g rules\n");
++ ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n");
+ return -ENOMEM;
+ }
+ }
+
+- if (num_5g_reg_rules) {
+- wmi_reg_rule += num_2g_reg_rules;
+- reg_info->reg_rules_5g_ptr = create_reg_rules_from_wmi(num_5g_reg_rules,
+- wmi_reg_rule);
+- if (!reg_info->reg_rules_5g_ptr) {
++ if (num_5ghz_reg_rules) {
++ wmi_reg_rule += num_2ghz_reg_rules;
++ reg_info->reg_rules_5ghz_ptr =
++ create_reg_rules_from_wmi(num_5ghz_reg_rules,
++ wmi_reg_rule);
++ if (!reg_info->reg_rules_5ghz_ptr) {
+ kfree(tb);
+- ath11k_warn(ab, "Unable to Allocate memory for 5g rules\n");
++ ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n");
+ return -ENOMEM;
+ }
+ }
+@@ -6619,8 +6621,8 @@ fallback:
+ WARN_ON(1);
+ mem_free:
+ if (reg_info) {
+- kfree(reg_info->reg_rules_2g_ptr);
+- kfree(reg_info->reg_rules_5g_ptr);
++ kfree(reg_info->reg_rules_2ghz_ptr);
++ kfree(reg_info->reg_rules_5ghz_ptr);
+ kfree(reg_info);
+ }
+ return ret;
+--- a/drivers/net/wireless/ath/ath11k/wmi.h
++++ b/drivers/net/wireless/ath/ath11k/wmi.h
+@@ -4129,14 +4129,14 @@ struct cur_regulatory_info {
+ u8 alpha2[REG_ALPHA2_LEN + 1];
+ u32 dfs_region;
+ u32 phybitmap;
+- u32 min_bw_2g;
+- u32 max_bw_2g;
+- u32 min_bw_5g;
+- u32 max_bw_5g;
+- u32 num_2g_reg_rules;
+- u32 num_5g_reg_rules;
+- struct cur_reg_rule *reg_rules_2g_ptr;
+- struct cur_reg_rule *reg_rules_5g_ptr;
++ u32 min_bw_2ghz;
++ u32 max_bw_2ghz;
++ u32 min_bw_5ghz;
++ u32 max_bw_5ghz;
++ u32 num_2ghz_reg_rules;
++ u32 num_5ghz_reg_rules;
++ struct cur_reg_rule *reg_rules_2ghz_ptr;
++ struct cur_reg_rule *reg_rules_5ghz_ptr;
+ };
+
+ struct wmi_reg_chan_list_cc_event {
+@@ -4148,12 +4148,12 @@ struct wmi_reg_chan_list_cc_event {
+ u32 domain_code;
+ u32 dfs_region;
+ u32 phybitmap;
+- u32 min_bw_2g;
+- u32 max_bw_2g;
+- u32 min_bw_5g;
+- u32 max_bw_5g;
+- u32 num_2g_reg_rules;
+- u32 num_5g_reg_rules;
++ u32 min_bw_2ghz;
++ u32 max_bw_2ghz;
++ u32 min_bw_5ghz;
++ u32 max_bw_5ghz;
++ u32 num_2ghz_reg_rules;
++ u32 num_5ghz_reg_rules;
+ } __packed;
+
+ struct wmi_regulatory_rule_struct {
diff --git a/package/kernel/mac80211/patches/ath11k/0044-wifi-ath11k-add-support-to-parse-new-WMI-event-for-6.patch b/package/kernel/mac80211/patches/ath11k/0044-wifi-ath11k-add-support-to-parse-new-WMI-event-for-6.patch
new file mode 100644
index 0000000000..e165c09dc4
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0044-wifi-ath11k-add-support-to-parse-new-WMI-event-for-6.patch
@@ -0,0 +1,844 @@
+From 91fa00fa69224aae5afb720c5e68b22e4c4f7333 Mon Sep 17 00:00:00 2001
+From: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Date: Wed, 1 Mar 2023 16:20:59 +0200
+Subject: [PATCH] wifi: ath11k: add support to parse new WMI event for 6 GHz
+
+In order to support different power levels of 6 GHz AP and client,
+new WMI event for regulatory - WMI_REG_CHAN_LIST_CC_EXT_EVENTID is
+added in firmware. This event provides new parameters required for
+6 GHz regulatory rules.
+
+Add support for parsing 2.4 GHz, 5 GHz and 6 GHz reg rules and other
+parameters from WMI_REG_CHAN_LIST_CC_EXT_EVENTID.
+
+Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Lavanya Suresh <quic_lavaks@quicinc.com>
+Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
+Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/20230110121024.14051-3-quic_adisi@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/reg.c | 37 ++-
+ drivers/net/wireless/ath/ath11k/wmi.c | 418 +++++++++++++++++++++++++-
+ drivers/net/wireless/ath/ath11k/wmi.h | 163 +++++++++-
+ 3 files changed, 584 insertions(+), 34 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/reg.c
++++ b/drivers/net/wireless/ath/ath11k/reg.c
+@@ -613,7 +613,7 @@ ath11k_reg_build_regd(struct ath11k_base
+ {
+ struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
+ struct cur_reg_rule *reg_rule;
+- u8 i = 0, j = 0;
++ u8 i = 0, j = 0, k = 0;
+ u8 num_rules;
+ u16 max_bw;
+ u32 flags;
+@@ -621,6 +621,12 @@ ath11k_reg_build_regd(struct ath11k_base
+
+ num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules;
+
++ /* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list.
++ * This can be updated after complete 6 GHz regulatory support is added.
++ */
++ if (reg_info->is_ext_reg_event)
++ num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP];
++
+ if (!num_rules)
+ goto ret;
+
+@@ -666,6 +672,14 @@ ath11k_reg_build_regd(struct ath11k_base
+ * per other BW rule flags we pass from here
+ */
+ flags = NL80211_RRF_AUTO_BW;
++ } else if (reg_info->is_ext_reg_event &&
++ reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] &&
++ (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) {
++ reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] +
++ k++;
++ max_bw = min_t(u16, reg_rule->max_bw,
++ reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]);
++ flags = NL80211_RRF_AUTO_BW;
+ } else {
+ break;
+ }
+@@ -693,12 +707,21 @@ ath11k_reg_build_regd(struct ath11k_base
+ continue;
+ }
+
+- ath11k_dbg(ab, ATH11K_DBG_REG,
+- "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
+- i + 1, reg_rule->start_freq, reg_rule->end_freq,
+- max_bw, reg_rule->ant_gain, reg_rule->reg_power,
+- tmp_regd->reg_rules[i].dfs_cac_ms,
+- flags);
++ if (reg_info->is_ext_reg_event) {
++ ath11k_dbg(ab, ATH11K_DBG_REG,
++ "\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->reg_rules[i].dfs_cac_ms, flags,
++ reg_rule->psd_flag, reg_rule->psd_eirp);
++ } else {
++ ath11k_dbg(ab, ATH11K_DBG_REG,
++ "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
++ i + 1, reg_rule->start_freq, reg_rule->end_freq,
++ max_bw, reg_rule->ant_gain, reg_rule->reg_power,
++ tmp_regd->reg_rules[i].dfs_cac_ms,
++ flags);
++ }
+ }
+
+ tmp_regd->n_reg_rules = i;
+--- a/drivers/net/wireless/ath/ath11k/wmi.c
++++ b/drivers/net/wireless/ath/ath11k/wmi.c
+@@ -105,6 +105,8 @@ static const struct wmi_tlv_policy wmi_t
+ = { .min_len = sizeof(struct wmi_vdev_stopped_event) },
+ [WMI_TAG_REG_CHAN_LIST_CC_EVENT]
+ = { .min_len = sizeof(struct wmi_reg_chan_list_cc_event) },
++ [WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]
++ = { .min_len = sizeof(struct wmi_reg_chan_list_cc_ext_event) },
+ [WMI_TAG_MGMT_RX_HDR]
+ = { .min_len = sizeof(struct wmi_mgmt_rx_hdr) },
+ [WMI_TAG_MGMT_TX_COMPL_EVENT]
+@@ -3974,6 +3976,10 @@ ath11k_wmi_copy_resource_config(struct w
+ wmi_cfg->sched_params = tg_cfg->sched_params;
+ wmi_cfg->twt_ap_pdev_count = tg_cfg->twt_ap_pdev_count;
+ wmi_cfg->twt_ap_sta_count = tg_cfg->twt_ap_sta_count;
++ wmi_cfg->host_service_flags &=
++ ~(1 << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
++ wmi_cfg->host_service_flags |= (tg_cfg->is_reg_cc_ext_event_supported <<
++ WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
+ }
+
+ static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi,
+@@ -4192,6 +4198,10 @@ int ath11k_wmi_cmd_init(struct ath11k_ba
+
+ ab->hw_params.hw_ops->wmi_init_config(ab, &config);
+
++ if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT,
++ ab->wmi_ab.svc_map))
++ config.is_reg_cc_ext_event_supported = 1;
++
+ memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config));
+
+ init_param.res_cfg = &wmi_sc->wlan_resource_config;
+@@ -4995,18 +5005,11 @@ static int ath11k_pull_reg_chan_list_upd
+ reg_info->phy_id = chan_list_event_hdr->phy_id;
+ reg_info->ctry_code = chan_list_event_hdr->country_id;
+ reg_info->reg_dmn_pair = chan_list_event_hdr->domain_code;
+- if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_PASS)
+- reg_info->status_code = REG_SET_CC_STATUS_PASS;
+- else if (chan_list_event_hdr->status_code == WMI_REG_CURRENT_ALPHA2_NOT_FOUND)
+- reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND;
+- else if (chan_list_event_hdr->status_code == WMI_REG_INIT_ALPHA2_NOT_FOUND)
+- reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND;
+- else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_CHANGE_NOT_ALLOWED)
+- reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED;
+- else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_NO_MEMORY)
+- reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY;
+- else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_FAIL)
+- reg_info->status_code = REG_SET_CC_STATUS_FAIL;
++
++ reg_info->status_code =
++ ath11k_wmi_cc_setting_code_to_reg(chan_list_event_hdr->status_code);
++
++ reg_info->is_ext_reg_event = false;
+
+ reg_info->min_bw_2ghz = chan_list_event_hdr->min_bw_2ghz;
+ reg_info->max_bw_2ghz = chan_list_event_hdr->max_bw_2ghz;
+@@ -5060,6 +5063,372 @@ static int ath11k_pull_reg_chan_list_upd
+ return 0;
+ }
+
++static struct cur_reg_rule
++*create_ext_reg_rules_from_wmi(u32 num_reg_rules,
++ struct wmi_regulatory_ext_rule *wmi_reg_rule)
++{
++ struct cur_reg_rule *reg_rule_ptr;
++ u32 count;
++
++ reg_rule_ptr = kcalloc(num_reg_rules, sizeof(*reg_rule_ptr), GFP_ATOMIC);
++
++ if (!reg_rule_ptr)
++ return NULL;
++
++ for (count = 0; count < num_reg_rules; count++) {
++ reg_rule_ptr[count].start_freq =
++ u32_get_bits(wmi_reg_rule[count].freq_info,
++ REG_RULE_START_FREQ);
++ reg_rule_ptr[count].end_freq =
++ u32_get_bits(wmi_reg_rule[count].freq_info,
++ REG_RULE_END_FREQ);
++ reg_rule_ptr[count].max_bw =
++ u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
++ REG_RULE_MAX_BW);
++ reg_rule_ptr[count].reg_power =
++ u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
++ REG_RULE_REG_PWR);
++ reg_rule_ptr[count].ant_gain =
++ u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
++ REG_RULE_ANT_GAIN);
++ reg_rule_ptr[count].flags =
++ u32_get_bits(wmi_reg_rule[count].flag_info,
++ REG_RULE_FLAGS);
++ reg_rule_ptr[count].psd_flag =
++ u32_get_bits(wmi_reg_rule[count].psd_power_info,
++ REG_RULE_PSD_INFO);
++ reg_rule_ptr[count].psd_eirp =
++ u32_get_bits(wmi_reg_rule[count].psd_power_info,
++ REG_RULE_PSD_EIRP);
++ }
++
++ return reg_rule_ptr;
++}
++
++static u8
++ath11k_invalid_5ghz_reg_ext_rules_from_wmi(u32 num_reg_rules,
++ const struct wmi_regulatory_ext_rule *rule)
++{
++ u8 num_invalid_5ghz_rules = 0;
++ u32 count, start_freq;
++
++ for (count = 0; count < num_reg_rules; count++) {
++ start_freq = u32_get_bits(rule[count].freq_info,
++ REG_RULE_START_FREQ);
++
++ if (start_freq >= ATH11K_MIN_6G_FREQ)
++ num_invalid_5ghz_rules++;
++ }
++
++ return num_invalid_5ghz_rules;
++}
++
++static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab,
++ struct sk_buff *skb,
++ struct cur_regulatory_info *reg_info)
++{
++ const void **tb;
++ const struct wmi_reg_chan_list_cc_ext_event *ext_chan_list_event_hdr;
++ struct wmi_regulatory_ext_rule *ext_wmi_reg_rule;
++ u32 num_2ghz_reg_rules, num_5ghz_reg_rules;
++ u32 num_6ghz_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
++ u32 num_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
++ u32 total_reg_rules = 0;
++ int ret, i, j, num_invalid_5ghz_ext_rules = 0;
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory ext channel list\n");
++
++ tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
++ if (IS_ERR(tb)) {
++ ret = PTR_ERR(tb);
++ ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
++ return ret;
++ }
++
++ ext_chan_list_event_hdr = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT];
++ if (!ext_chan_list_event_hdr) {
++ ath11k_warn(ab, "failed to fetch reg chan list ext update ev\n");
++ kfree(tb);
++ return -EPROTO;
++ }
++
++ reg_info->num_2ghz_reg_rules =
++ ext_chan_list_event_hdr->num_2ghz_reg_rules;
++ reg_info->num_5ghz_reg_rules =
++ ext_chan_list_event_hdr->num_5ghz_reg_rules;
++ reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] =
++ ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_lpi;
++ reg_info->num_6ghz_rules_ap[WMI_REG_STANDARD_POWER_AP] =
++ ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_sp;
++ reg_info->num_6ghz_rules_ap[WMI_REG_VERY_LOW_POWER_AP] =
++ ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_vlp;
++
++ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
++ reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i] =
++ ext_chan_list_event_hdr->num_6ghz_reg_rules_client_lpi[i];
++ reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i] =
++ ext_chan_list_event_hdr->num_6ghz_reg_rules_client_sp[i];
++ reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] =
++ ext_chan_list_event_hdr->num_6ghz_reg_rules_client_vlp[i];
++ }
++
++ num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules;
++ num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules;
++
++ total_reg_rules += num_2ghz_reg_rules;
++ total_reg_rules += num_5ghz_reg_rules;
++
++ if ((num_2ghz_reg_rules > MAX_REG_RULES) ||
++ (num_5ghz_reg_rules > MAX_REG_RULES)) {
++ ath11k_warn(ab, "Num reg rules for 2.4 GHz/5 GHz exceeds max limit (num_2ghz_reg_rules: %d num_5ghz_reg_rules: %d max_rules: %d)\n",
++ num_2ghz_reg_rules, num_5ghz_reg_rules, MAX_REG_RULES);
++ kfree(tb);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
++ num_6ghz_reg_rules_ap[i] = reg_info->num_6ghz_rules_ap[i];
++
++ if (num_6ghz_reg_rules_ap[i] > MAX_6GHZ_REG_RULES) {
++ ath11k_warn(ab, "Num 6 GHz reg rules for AP mode(%d) exceeds max limit (num_6ghz_reg_rules_ap: %d, max_rules: %d)\n",
++ i, num_6ghz_reg_rules_ap[i], MAX_6GHZ_REG_RULES);
++ kfree(tb);
++ return -EINVAL;
++ }
++
++ total_reg_rules += num_6ghz_reg_rules_ap[i];
++ }
++
++ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
++ num_6ghz_client[WMI_REG_INDOOR_AP][i] =
++ reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i];
++ total_reg_rules += num_6ghz_client[WMI_REG_INDOOR_AP][i];
++
++ num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
++ reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i];
++ total_reg_rules += num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i];
++
++ num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
++ reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i];
++ total_reg_rules += num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i];
++
++ if ((num_6ghz_client[WMI_REG_INDOOR_AP][i] > MAX_6GHZ_REG_RULES) ||
++ (num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] >
++ MAX_6GHZ_REG_RULES) ||
++ (num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] >
++ MAX_6GHZ_REG_RULES)) {
++ ath11k_warn(ab,
++ "Num 6 GHz client reg rules exceeds max limit, for client(type: %d)\n",
++ i);
++ kfree(tb);
++ return -EINVAL;
++ }
++ }
++
++ if (!total_reg_rules) {
++ ath11k_warn(ab, "No reg rules available\n");
++ kfree(tb);
++ return -EINVAL;
++ }
++
++ memcpy(reg_info->alpha2, &ext_chan_list_event_hdr->alpha2,
++ REG_ALPHA2_LEN);
++
++ reg_info->dfs_region = ext_chan_list_event_hdr->dfs_region;
++ reg_info->phybitmap = ext_chan_list_event_hdr->phybitmap;
++ reg_info->num_phy = ext_chan_list_event_hdr->num_phy;
++ reg_info->phy_id = ext_chan_list_event_hdr->phy_id;
++ reg_info->ctry_code = ext_chan_list_event_hdr->country_id;
++ reg_info->reg_dmn_pair = ext_chan_list_event_hdr->domain_code;
++
++ reg_info->status_code =
++ ath11k_wmi_cc_setting_code_to_reg(ext_chan_list_event_hdr->status_code);
++
++ reg_info->is_ext_reg_event = true;
++
++ reg_info->min_bw_2ghz = ext_chan_list_event_hdr->min_bw_2ghz;
++ reg_info->max_bw_2ghz = ext_chan_list_event_hdr->max_bw_2ghz;
++ reg_info->min_bw_5ghz = ext_chan_list_event_hdr->min_bw_5ghz;
++ reg_info->max_bw_5ghz = ext_chan_list_event_hdr->max_bw_5ghz;
++
++ reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP] =
++ ext_chan_list_event_hdr->min_bw_6ghz_ap_lpi;
++ reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP] =
++ ext_chan_list_event_hdr->max_bw_6ghz_ap_lpi;
++ reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
++ ext_chan_list_event_hdr->min_bw_6ghz_ap_sp;
++ reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
++ ext_chan_list_event_hdr->max_bw_6ghz_ap_sp;
++ reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
++ ext_chan_list_event_hdr->min_bw_6ghz_ap_vlp;
++ reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
++ ext_chan_list_event_hdr->max_bw_6ghz_ap_vlp;
++
++ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
++ reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i] =
++ ext_chan_list_event_hdr->min_bw_6ghz_client_lpi[i];
++ reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i] =
++ ext_chan_list_event_hdr->max_bw_6ghz_client_lpi[i];
++ reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
++ ext_chan_list_event_hdr->min_bw_6ghz_client_sp[i];
++ reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
++ ext_chan_list_event_hdr->max_bw_6ghz_client_sp[i];
++ reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
++ ext_chan_list_event_hdr->min_bw_6ghz_client_vlp[i];
++ reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
++ ext_chan_list_event_hdr->max_bw_6ghz_client_vlp[i];
++ }
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "%s:cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
++ __func__, 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);
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "num_2ghz_reg_rules %d num_5ghz_reg_rules %d",
++ num_2ghz_reg_rules, num_5ghz_reg_rules);
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "num_6ghz_reg_rules_ap_lpi: %d num_6ghz_reg_rules_ap_sp: %d num_6ghz_reg_rules_ap_vlp: %d",
++ num_6ghz_reg_rules_ap[WMI_REG_INDOOR_AP],
++ num_6ghz_reg_rules_ap[WMI_REG_STANDARD_POWER_AP],
++ num_6ghz_reg_rules_ap[WMI_REG_VERY_LOW_POWER_AP]);
++
++ j = WMI_REG_DEFAULT_CLIENT;
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "6 GHz Regular client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d",
++ num_6ghz_client[WMI_REG_INDOOR_AP][j],
++ num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j],
++ num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]);
++
++ j = WMI_REG_SUBORDINATE_CLIENT;
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "6 GHz Subordinate client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d",
++ num_6ghz_client[WMI_REG_INDOOR_AP][j],
++ num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j],
++ num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]);
++
++ ext_wmi_reg_rule =
++ (struct wmi_regulatory_ext_rule *)((u8 *)ext_chan_list_event_hdr
++ + sizeof(*ext_chan_list_event_hdr)
++ + sizeof(struct wmi_tlv));
++ if (num_2ghz_reg_rules) {
++ reg_info->reg_rules_2ghz_ptr =
++ create_ext_reg_rules_from_wmi(num_2ghz_reg_rules,
++ ext_wmi_reg_rule);
++
++ if (!reg_info->reg_rules_2ghz_ptr) {
++ kfree(tb);
++ ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n");
++ return -ENOMEM;
++ }
++ }
++
++ ext_wmi_reg_rule += num_2ghz_reg_rules;
++
++ /* Firmware might include 6 GHz reg rule in 5 GHz rule list
++ * for few countries along with separate 6 GHz rule.
++ * Having same 6 GHz reg rule in 5 GHz and 6 GHz rules list
++ * causes intersect check to be true, and same rules will be
++ * shown multiple times in iw cmd.
++ * Hence, avoid parsing 6 GHz rule from 5 GHz reg rule list
++ */
++ num_invalid_5ghz_ext_rules =
++ ath11k_invalid_5ghz_reg_ext_rules_from_wmi(num_5ghz_reg_rules,
++ ext_wmi_reg_rule);
++
++ if (num_invalid_5ghz_ext_rules) {
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "CC: %s 5 GHz reg rules number %d from fw, %d number of invalid 5 GHz rules",
++ reg_info->alpha2, reg_info->num_5ghz_reg_rules,
++ num_invalid_5ghz_ext_rules);
++
++ num_5ghz_reg_rules = num_5ghz_reg_rules - num_invalid_5ghz_ext_rules;
++ reg_info->num_5ghz_reg_rules = num_5ghz_reg_rules;
++ }
++
++ if (num_5ghz_reg_rules) {
++ reg_info->reg_rules_5ghz_ptr =
++ create_ext_reg_rules_from_wmi(num_5ghz_reg_rules,
++ ext_wmi_reg_rule);
++
++ if (!reg_info->reg_rules_5ghz_ptr) {
++ kfree(tb);
++ ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n");
++ return -ENOMEM;
++ }
++ }
++
++ /* We have adjusted the number of 5 GHz reg rules above. But still those
++ * many rules needs to be adjusted in ext_wmi_reg_rule.
++ *
++ * NOTE: num_invalid_5ghz_ext_rules will be 0 for rest other cases.
++ */
++ ext_wmi_reg_rule += (num_5ghz_reg_rules + num_invalid_5ghz_ext_rules);
++
++ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
++ reg_info->reg_rules_6ghz_ap_ptr[i] =
++ create_ext_reg_rules_from_wmi(num_6ghz_reg_rules_ap[i],
++ ext_wmi_reg_rule);
++
++ if (!reg_info->reg_rules_6ghz_ap_ptr[i]) {
++ kfree(tb);
++ ath11k_warn(ab, "Unable to Allocate memory for 6 GHz AP rules\n");
++ return -ENOMEM;
++ }
++
++ ext_wmi_reg_rule += num_6ghz_reg_rules_ap[i];
++ }
++
++ for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
++ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
++ reg_info->reg_rules_6ghz_client_ptr[j][i] =
++ create_ext_reg_rules_from_wmi(num_6ghz_client[j][i],
++ ext_wmi_reg_rule);
++
++ if (!reg_info->reg_rules_6ghz_client_ptr[j][i]) {
++ kfree(tb);
++ ath11k_warn(ab, "Unable to Allocate memory for 6 GHz client rules\n");
++ return -ENOMEM;
++ }
++
++ ext_wmi_reg_rule += num_6ghz_client[j][i];
++ }
++ }
++
++ reg_info->client_type = ext_chan_list_event_hdr->client_type;
++ reg_info->rnr_tpe_usable = ext_chan_list_event_hdr->rnr_tpe_usable;
++ reg_info->unspecified_ap_usable =
++ ext_chan_list_event_hdr->unspecified_ap_usable;
++ reg_info->domain_code_6ghz_ap[WMI_REG_INDOOR_AP] =
++ ext_chan_list_event_hdr->domain_code_6ghz_ap_lpi;
++ reg_info->domain_code_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
++ ext_chan_list_event_hdr->domain_code_6ghz_ap_sp;
++ reg_info->domain_code_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
++ ext_chan_list_event_hdr->domain_code_6ghz_ap_vlp;
++
++ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
++ reg_info->domain_code_6ghz_client[WMI_REG_INDOOR_AP][i] =
++ ext_chan_list_event_hdr->domain_code_6ghz_client_lpi[i];
++ reg_info->domain_code_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
++ ext_chan_list_event_hdr->domain_code_6ghz_client_sp[i];
++ reg_info->domain_code_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
++ ext_chan_list_event_hdr->domain_code_6ghz_client_vlp[i];
++ }
++
++ reg_info->domain_code_6ghz_super_id =
++ ext_chan_list_event_hdr->domain_code_6ghz_super_id;
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI, "6 GHz client_type: %d domain_code_6ghz_super_id: %d",
++ reg_info->client_type, reg_info->domain_code_6ghz_super_id);
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory ext channel list\n");
++
++ kfree(tb);
++ return 0;
++}
++
+ static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *skb,
+ struct wmi_peer_delete_resp_event *peer_del_resp)
+ {
+@@ -6507,12 +6876,14 @@ static bool ath11k_reg_is_world_alpha(ch
+ return false;
+ }
+
+-static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb)
++static int ath11k_reg_chan_list_event(struct ath11k_base *ab,
++ struct sk_buff *skb,
++ enum wmi_reg_chan_list_cmd_type id)
+ {
+ struct cur_regulatory_info *reg_info = NULL;
+ struct ieee80211_regdomain *regd = NULL;
+ bool intersect = false;
+- int ret = 0, pdev_idx;
++ int ret = 0, pdev_idx, i, j;
+ struct ath11k *ar;
+
+ reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
+@@ -6521,7 +6892,11 @@ static int ath11k_reg_chan_list_event(st
+ goto fallback;
+ }
+
+- ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info);
++ if (id == WMI_REG_CHAN_LIST_CC_ID)
++ ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info);
++ else
++ ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);
++
+ if (ret) {
+ ath11k_warn(ab, "failed to extract regulatory info from received event\n");
+ goto fallback;
+@@ -6623,6 +6998,14 @@ mem_free:
+ if (reg_info) {
+ kfree(reg_info->reg_rules_2ghz_ptr);
+ kfree(reg_info->reg_rules_5ghz_ptr);
++ if (reg_info->is_ext_reg_event) {
++ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)
++ kfree(reg_info->reg_rules_6ghz_ap_ptr[i]);
++
++ for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++)
++ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++)
++ kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]);
++ }
+ kfree(reg_info);
+ }
+ return ret;
+@@ -8054,7 +8437,10 @@ static void ath11k_wmi_tlv_op_rx(struct
+ ath11k_service_ready_ext2_event(ab, skb);
+ break;
+ case WMI_REG_CHAN_LIST_CC_EVENTID:
+- ath11k_reg_chan_list_event(ab, skb);
++ ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_ID);
++ break;
++ case WMI_REG_CHAN_LIST_CC_EXT_EVENTID:
++ ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_EXT_ID);
+ break;
+ case WMI_READY_EVENTID:
+ ath11k_ready_event(ab, skb);
+--- a/drivers/net/wireless/ath/ath11k/wmi.h
++++ b/drivers/net/wireless/ath/ath11k/wmi.h
+@@ -797,6 +797,7 @@ enum wmi_tlv_event_id {
+ WMI_RMC_NEW_LEADER_EVENTID = WMI_TLV_CMD(WMI_GRP_RMC),
+ WMI_REG_CHAN_LIST_CC_EVENTID = WMI_TLV_CMD(WMI_GRP_REGULATORY),
+ WMI_11D_NEW_COUNTRY_EVENTID,
++ WMI_REG_CHAN_LIST_CC_EXT_EVENTID,
+ WMI_NDI_CAP_RSP_EVENTID = WMI_TLV_CMD(WMI_GRP_PROTOTYPE),
+ WMI_NDP_INITIATOR_RSP_EVENTID,
+ WMI_NDP_RESPONDER_RSP_EVENTID,
+@@ -1865,6 +1866,8 @@ enum wmi_tlv_tag {
+ WMI_TAG_PDEV_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
+ WMI_TAG_PDEV_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD,
+ WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
++ WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
++ WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
+ WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8,
+ WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD,
+ WMI_TAG_MAX
+@@ -2097,6 +2100,7 @@ enum wmi_tlv_service {
+
+ /* The second 128 bits */
+ WMI_MAX_EXT_SERVICE = 256,
++ WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281,
+ WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326,
+
+ /* The third 128 bits */
+@@ -2313,6 +2317,8 @@ struct wmi_init_cmd {
+ #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5)
+ #define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18)
+
++#define WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT 4
++
+ struct wmi_resource_config {
+ u32 tlv_header;
+ u32 num_vdevs;
+@@ -2372,6 +2378,15 @@ struct wmi_resource_config {
+ u32 sched_params;
+ u32 twt_ap_pdev_count;
+ u32 twt_ap_sta_count;
++ u32 max_nlo_ssids;
++ u32 num_pkt_filters;
++ u32 num_max_sta_vdevs;
++ u32 max_bssid_indicator;
++ u32 ul_resp_config;
++ u32 msdu_flow_override_config0;
++ u32 msdu_flow_override_config1;
++ u32 flags2;
++ u32 host_service_flags;
+ } __packed;
+
+ struct wmi_service_ready_event {
+@@ -2854,6 +2869,8 @@ struct rx_reorder_queue_remove_params {
+ #define REG_RULE_MAX_BW 0x0000ffff
+ #define REG_RULE_REG_PWR 0x00ff0000
+ #define REG_RULE_ANT_GAIN 0xff000000
++#define REG_RULE_PSD_INFO BIT(0)
++#define REG_RULE_PSD_EIRP 0xff0000
+
+ #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
+ #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
+@@ -4049,6 +4066,7 @@ struct wmi_he_rate_set {
+
+ #define MAX_REG_RULES 10
+ #define REG_ALPHA2_LEN 2
++#define MAX_6GHZ_REG_RULES 5
+
+ enum wmi_start_event_param {
+ WMI_VDEV_START_RESP_EVENT = 0,
+@@ -4079,16 +4097,6 @@ enum wmi_vdev_start_resp_status_code {
+ WMI_VDEV_START_RESPONSE_INVALID_REGDOMAIN = 4,
+ };
+
+-;
+-enum cc_setting_code {
+- REG_SET_CC_STATUS_PASS = 0,
+- REG_CURRENT_ALPHA2_NOT_FOUND = 1,
+- REG_INIT_ALPHA2_NOT_FOUND = 2,
+- REG_SET_CC_CHANGE_NOT_ALLOWED = 3,
+- REG_SET_CC_STATUS_NO_MEMORY = 4,
+- REG_SET_CC_STATUS_FAIL = 5,
+-};
+-
+ /* Regaulatory Rule Flags Passed by FW */
+ #define REGULATORY_CHAN_DISABLED BIT(0)
+ #define REGULATORY_CHAN_NO_IR BIT(1)
+@@ -4102,13 +4110,72 @@ enum cc_setting_code {
+ #define REGULATORY_CHAN_NO_20MHZ BIT(11)
+ #define REGULATORY_CHAN_NO_10MHZ BIT(12)
+
+-enum {
++enum wmi_reg_chan_list_cmd_type {
++ WMI_REG_CHAN_LIST_CC_ID = 0,
++ WMI_REG_CHAN_LIST_CC_EXT_ID = 1,
++};
++
++enum wmi_reg_cc_setting_code {
+ WMI_REG_SET_CC_STATUS_PASS = 0,
+ WMI_REG_CURRENT_ALPHA2_NOT_FOUND = 1,
+ WMI_REG_INIT_ALPHA2_NOT_FOUND = 2,
+ WMI_REG_SET_CC_CHANGE_NOT_ALLOWED = 3,
+ WMI_REG_SET_CC_STATUS_NO_MEMORY = 4,
+ WMI_REG_SET_CC_STATUS_FAIL = 5,
++
++ /* add new setting code above, update in
++ * @enum cc_setting_code as well.
++ * Also handle it in ath11k_wmi_cc_setting_code_to_reg()
++ */
++};
++
++enum cc_setting_code {
++ REG_SET_CC_STATUS_PASS = 0,
++ REG_CURRENT_ALPHA2_NOT_FOUND = 1,
++ REG_INIT_ALPHA2_NOT_FOUND = 2,
++ REG_SET_CC_CHANGE_NOT_ALLOWED = 3,
++ REG_SET_CC_STATUS_NO_MEMORY = 4,
++ REG_SET_CC_STATUS_FAIL = 5,
++
++ /* add new setting code above, update in
++ * @enum wmi_reg_cc_setting_code as well.
++ */
++};
++
++static inline enum cc_setting_code
++ath11k_wmi_cc_setting_code_to_reg(enum wmi_reg_cc_setting_code status_code)
++{
++ switch (status_code) {
++ case WMI_REG_SET_CC_STATUS_PASS:
++ return REG_SET_CC_STATUS_PASS;
++ case WMI_REG_CURRENT_ALPHA2_NOT_FOUND:
++ return REG_CURRENT_ALPHA2_NOT_FOUND;
++ case WMI_REG_INIT_ALPHA2_NOT_FOUND:
++ return REG_INIT_ALPHA2_NOT_FOUND;
++ case WMI_REG_SET_CC_CHANGE_NOT_ALLOWED:
++ return REG_SET_CC_CHANGE_NOT_ALLOWED;
++ case WMI_REG_SET_CC_STATUS_NO_MEMORY:
++ return REG_SET_CC_STATUS_NO_MEMORY;
++ case WMI_REG_SET_CC_STATUS_FAIL:
++ return REG_SET_CC_STATUS_FAIL;
++ }
++
++ return REG_SET_CC_STATUS_FAIL;
++}
++
++enum wmi_reg_6ghz_ap_type {
++ WMI_REG_INDOOR_AP = 0,
++ WMI_REG_STANDARD_POWER_AP = 1,
++ WMI_REG_VERY_LOW_POWER_AP = 2,
++
++ WMI_REG_CURRENT_MAX_AP_TYPE,
++ WMI_REG_MAX_AP_TYPE = 7,
++};
++
++enum wmi_reg_6ghz_client_type {
++ WMI_REG_DEFAULT_CLIENT = 0,
++ WMI_REG_SUBORDINATE_CLIENT = 1,
++ WMI_REG_MAX_CLIENT_TYPE = 2,
+ };
+
+ struct cur_reg_rule {
+@@ -4118,6 +4185,8 @@ struct cur_reg_rule {
+ u8 reg_power;
+ u8 ant_gain;
+ u16 flags;
++ bool psd_flag;
++ s8 psd_eirp;
+ };
+
+ struct cur_regulatory_info {
+@@ -4137,6 +4206,22 @@ struct cur_regulatory_info {
+ u32 num_5ghz_reg_rules;
+ struct cur_reg_rule *reg_rules_2ghz_ptr;
+ struct cur_reg_rule *reg_rules_5ghz_ptr;
++ bool is_ext_reg_event;
++ enum wmi_reg_6ghz_client_type client_type;
++ bool rnr_tpe_usable;
++ bool unspecified_ap_usable;
++ u8 domain_code_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
++ u8 domain_code_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
++ u32 domain_code_6ghz_super_id;
++ u32 min_bw_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
++ u32 max_bw_6ghz_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
++ u32 min_bw_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
++ u32 max_bw_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
++ u32 num_6ghz_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
++ u32 num_6ghz_rules_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
++ struct cur_reg_rule *reg_rules_6ghz_ap_ptr[WMI_REG_CURRENT_MAX_AP_TYPE];
++ struct cur_reg_rule *reg_rules_6ghz_client_ptr
++ [WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
+ };
+
+ struct wmi_reg_chan_list_cc_event {
+@@ -4163,6 +4248,61 @@ struct wmi_regulatory_rule_struct {
+ u32 flag_info;
+ };
+
++#define WMI_REG_CLIENT_MAX 4
++
++struct wmi_reg_chan_list_cc_ext_event {
++ u32 status_code;
++ u32 phy_id;
++ u32 alpha2;
++ u32 num_phy;
++ u32 country_id;
++ u32 domain_code;
++ u32 dfs_region;
++ u32 phybitmap;
++ u32 min_bw_2ghz;
++ u32 max_bw_2ghz;
++ u32 min_bw_5ghz;
++ u32 max_bw_5ghz;
++ u32 num_2ghz_reg_rules;
++ u32 num_5ghz_reg_rules;
++ u32 client_type;
++ u32 rnr_tpe_usable;
++ u32 unspecified_ap_usable;
++ u32 domain_code_6ghz_ap_lpi;
++ u32 domain_code_6ghz_ap_sp;
++ u32 domain_code_6ghz_ap_vlp;
++ u32 domain_code_6ghz_client_lpi[WMI_REG_CLIENT_MAX];
++ u32 domain_code_6ghz_client_sp[WMI_REG_CLIENT_MAX];
++ u32 domain_code_6ghz_client_vlp[WMI_REG_CLIENT_MAX];
++ u32 domain_code_6ghz_super_id;
++ u32 min_bw_6ghz_ap_sp;
++ u32 max_bw_6ghz_ap_sp;
++ u32 min_bw_6ghz_ap_lpi;
++ u32 max_bw_6ghz_ap_lpi;
++ u32 min_bw_6ghz_ap_vlp;
++ u32 max_bw_6ghz_ap_vlp;
++ u32 min_bw_6ghz_client_sp[WMI_REG_CLIENT_MAX];
++ u32 max_bw_6ghz_client_sp[WMI_REG_CLIENT_MAX];
++ u32 min_bw_6ghz_client_lpi[WMI_REG_CLIENT_MAX];
++ u32 max_bw_6ghz_client_lpi[WMI_REG_CLIENT_MAX];
++ u32 min_bw_6ghz_client_vlp[WMI_REG_CLIENT_MAX];
++ u32 max_bw_6ghz_client_vlp[WMI_REG_CLIENT_MAX];
++ u32 num_6ghz_reg_rules_ap_sp;
++ u32 num_6ghz_reg_rules_ap_lpi;
++ u32 num_6ghz_reg_rules_ap_vlp;
++ u32 num_6ghz_reg_rules_client_sp[WMI_REG_CLIENT_MAX];
++ u32 num_6ghz_reg_rules_client_lpi[WMI_REG_CLIENT_MAX];
++ u32 num_6ghz_reg_rules_client_vlp[WMI_REG_CLIENT_MAX];
++} __packed;
++
++struct wmi_regulatory_ext_rule {
++ u32 tlv_header;
++ u32 freq_info;
++ u32 bw_pwr_info;
++ u32 flag_info;
++ u32 psd_power_info;
++} __packed;
++
+ struct wmi_vdev_delete_resp_event {
+ u32 vdev_id;
+ } __packed;
+@@ -5358,6 +5498,7 @@ struct target_resource_config {
+ u32 sched_params;
+ u32 twt_ap_pdev_count;
+ u32 twt_ap_sta_count;
++ u8 is_reg_cc_ext_event_supported;
+ };
+
+ enum wmi_debug_log_param {
diff --git a/package/kernel/mac80211/patches/ath11k/0045-wifi-ath11k-add-debug-prints-in-regulatory-WMI-event.patch b/package/kernel/mac80211/patches/ath11k/0045-wifi-ath11k-add-debug-prints-in-regulatory-WMI-event.patch
new file mode 100644
index 0000000000..b88e51928f
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0045-wifi-ath11k-add-debug-prints-in-regulatory-WMI-event.patch
@@ -0,0 +1,567 @@
+From e238e62ba8868a784e485eb94451c87cd1b85cee Mon Sep 17 00:00:00 2001
+From: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Date: Wed, 1 Mar 2023 16:20:59 +0200
+Subject: [PATCH] wifi: ath11k: add debug prints in regulatory WMI event
+ processing
+
+Add some more debug prints in processing regulatory WMI event in order to
+increase more debuggability.
+
+Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/20230110121024.14051-4-quic_adisi@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/reg.c | 2 +-
+ drivers/net/wireless/ath/ath11k/wmi.c | 207 ++++++++++++++++++--------
+ drivers/net/wireless/ath/ath11k/wmi.h | 142 ++++++++++++++++++
+ 3 files changed, 291 insertions(+), 60 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/reg.c
++++ b/drivers/net/wireless/ath/ath11k/reg.c
+@@ -646,7 +646,7 @@ ath11k_reg_build_regd(struct ath11k_base
+ tmp_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region);
+
+ ath11k_dbg(ab, ATH11K_DBG_REG,
+- "\r\nCountry %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n",
++ "Country %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n",
+ alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region),
+ reg_info->dfs_region, num_rules);
+ /* Update reg_rules[] below. Firmware is expected to
+--- a/drivers/net/wireless/ath/ath11k/wmi.c
++++ b/drivers/net/wireless/ath/ath11k/wmi.c
+@@ -4925,6 +4925,26 @@ static int ath11k_pull_vdev_start_resp_t
+ return 0;
+ }
+
++static void ath11k_print_reg_rule(struct ath11k_base *ab, const char *band,
++ u32 num_reg_rules,
++ struct cur_reg_rule *reg_rule_ptr)
++{
++ struct cur_reg_rule *reg_rule = reg_rule_ptr;
++ u32 count;
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI, "number of reg rules in %s band: %d\n",
++ band, num_reg_rules);
++
++ for (count = 0; count < num_reg_rules; count++) {
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d)\n",
++ count + 1, reg_rule->start_freq, reg_rule->end_freq,
++ reg_rule->max_bw, reg_rule->ant_gain,
++ reg_rule->reg_power, reg_rule->flags);
++ reg_rule++;
++ }
++}
++
+ static struct cur_reg_rule
+ *create_reg_rules_from_wmi(u32 num_reg_rules,
+ struct wmi_regulatory_rule_struct *wmi_reg_rule)
+@@ -5006,6 +5026,10 @@ static int ath11k_pull_reg_chan_list_upd
+ reg_info->ctry_code = chan_list_event_hdr->country_id;
+ reg_info->reg_dmn_pair = chan_list_event_hdr->domain_code;
+
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "status_code %s",
++ ath11k_cc_status_to_str(reg_info->status_code));
++
+ reg_info->status_code =
+ ath11k_wmi_cc_setting_code_to_reg(chan_list_event_hdr->status_code);
+
+@@ -5020,13 +5044,13 @@ static int ath11k_pull_reg_chan_list_upd
+ num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules;
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
+- "%s:cc %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
+- __func__, reg_info->alpha2, reg_info->dfs_region,
++ "cc %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
++ 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);
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
+- "%s: num_2ghz_reg_rules %d num_5ghz_reg_rules %d", __func__,
++ "num_2ghz_reg_rules %d num_5ghz_reg_rules %d",
+ num_2ghz_reg_rules, num_5ghz_reg_rules);
+
+ wmi_reg_rule =
+@@ -5043,6 +5067,10 @@ static int ath11k_pull_reg_chan_list_upd
+ ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n");
+ return -ENOMEM;
+ }
++
++ ath11k_print_reg_rule(ab, "2 GHz",
++ num_2ghz_reg_rules,
++ reg_info->reg_rules_2ghz_ptr);
+ }
+
+ if (num_5ghz_reg_rules) {
+@@ -5055,6 +5083,10 @@ static int ath11k_pull_reg_chan_list_upd
+ ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n");
+ return -ENOMEM;
+ }
++
++ ath11k_print_reg_rule(ab, "5 GHz",
++ num_5ghz_reg_rules,
++ reg_info->reg_rules_5ghz_ptr);
+ }
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory channel list\n");
+@@ -5128,7 +5160,7 @@ static int ath11k_pull_reg_chan_list_ext
+ struct cur_regulatory_info *reg_info)
+ {
+ const void **tb;
+- const struct wmi_reg_chan_list_cc_ext_event *ext_chan_list_event_hdr;
++ const struct wmi_reg_chan_list_cc_ext_event *ev;
+ struct wmi_regulatory_ext_rule *ext_wmi_reg_rule;
+ u32 num_2ghz_reg_rules, num_5ghz_reg_rules;
+ u32 num_6ghz_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
+@@ -5145,31 +5177,29 @@ static int ath11k_pull_reg_chan_list_ext
+ return ret;
+ }
+
+- ext_chan_list_event_hdr = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT];
+- if (!ext_chan_list_event_hdr) {
++ ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT];
++ if (!ev) {
+ ath11k_warn(ab, "failed to fetch reg chan list ext update ev\n");
+ kfree(tb);
+ return -EPROTO;
+ }
+
+- reg_info->num_2ghz_reg_rules =
+- ext_chan_list_event_hdr->num_2ghz_reg_rules;
+- reg_info->num_5ghz_reg_rules =
+- ext_chan_list_event_hdr->num_5ghz_reg_rules;
++ reg_info->num_2ghz_reg_rules = ev->num_2ghz_reg_rules;
++ reg_info->num_5ghz_reg_rules = ev->num_5ghz_reg_rules;
+ reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] =
+- ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_lpi;
++ ev->num_6ghz_reg_rules_ap_lpi;
+ reg_info->num_6ghz_rules_ap[WMI_REG_STANDARD_POWER_AP] =
+- ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_sp;
++ ev->num_6ghz_reg_rules_ap_sp;
+ reg_info->num_6ghz_rules_ap[WMI_REG_VERY_LOW_POWER_AP] =
+- ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_vlp;
++ ev->num_6ghz_reg_rules_ap_vlp;
+
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
+ reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i] =
+- ext_chan_list_event_hdr->num_6ghz_reg_rules_client_lpi[i];
++ ev->num_6ghz_reg_rules_client_lpi[i];
+ reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i] =
+- ext_chan_list_event_hdr->num_6ghz_reg_rules_client_sp[i];
++ ev->num_6ghz_reg_rules_client_sp[i];
+ reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] =
+- ext_chan_list_event_hdr->num_6ghz_reg_rules_client_vlp[i];
++ ev->num_6ghz_reg_rules_client_vlp[i];
+ }
+
+ num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules;
+@@ -5231,57 +5261,79 @@ static int ath11k_pull_reg_chan_list_ext
+ return -EINVAL;
+ }
+
+- memcpy(reg_info->alpha2, &ext_chan_list_event_hdr->alpha2,
+- REG_ALPHA2_LEN);
++ memcpy(reg_info->alpha2, &ev->alpha2, REG_ALPHA2_LEN);
++
++ reg_info->dfs_region = ev->dfs_region;
++ reg_info->phybitmap = ev->phybitmap;
++ reg_info->num_phy = ev->num_phy;
++ reg_info->phy_id = ev->phy_id;
++ reg_info->ctry_code = ev->country_id;
++ reg_info->reg_dmn_pair = ev->domain_code;
+
+- reg_info->dfs_region = ext_chan_list_event_hdr->dfs_region;
+- reg_info->phybitmap = ext_chan_list_event_hdr->phybitmap;
+- reg_info->num_phy = ext_chan_list_event_hdr->num_phy;
+- reg_info->phy_id = ext_chan_list_event_hdr->phy_id;
+- reg_info->ctry_code = ext_chan_list_event_hdr->country_id;
+- reg_info->reg_dmn_pair = ext_chan_list_event_hdr->domain_code;
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "status_code %s",
++ ath11k_cc_status_to_str(reg_info->status_code));
+
+ reg_info->status_code =
+- ath11k_wmi_cc_setting_code_to_reg(ext_chan_list_event_hdr->status_code);
++ ath11k_wmi_cc_setting_code_to_reg(ev->status_code);
+
+ reg_info->is_ext_reg_event = true;
+
+- reg_info->min_bw_2ghz = ext_chan_list_event_hdr->min_bw_2ghz;
+- reg_info->max_bw_2ghz = ext_chan_list_event_hdr->max_bw_2ghz;
+- reg_info->min_bw_5ghz = ext_chan_list_event_hdr->min_bw_5ghz;
+- reg_info->max_bw_5ghz = ext_chan_list_event_hdr->max_bw_5ghz;
++ reg_info->min_bw_2ghz = ev->min_bw_2ghz;
++ reg_info->max_bw_2ghz = ev->max_bw_2ghz;
++ reg_info->min_bw_5ghz = ev->min_bw_5ghz;
++ reg_info->max_bw_5ghz = ev->max_bw_5ghz;
+
+ reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP] =
+- ext_chan_list_event_hdr->min_bw_6ghz_ap_lpi;
++ ev->min_bw_6ghz_ap_lpi;
+ reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP] =
+- ext_chan_list_event_hdr->max_bw_6ghz_ap_lpi;
++ ev->max_bw_6ghz_ap_lpi;
+ reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
+- ext_chan_list_event_hdr->min_bw_6ghz_ap_sp;
++ ev->min_bw_6ghz_ap_sp;
+ reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
+- ext_chan_list_event_hdr->max_bw_6ghz_ap_sp;
++ ev->max_bw_6ghz_ap_sp;
+ reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
+- ext_chan_list_event_hdr->min_bw_6ghz_ap_vlp;
++ ev->min_bw_6ghz_ap_vlp;
+ reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
+- ext_chan_list_event_hdr->max_bw_6ghz_ap_vlp;
++ ev->max_bw_6ghz_ap_vlp;
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "6 GHz AP BW: LPI (%d - %d), SP (%d - %d), VLP (%d - %d)\n",
++ reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP],
++ reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP],
++ reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP],
++ reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP],
++ reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP],
++ reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP]);
+
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
+ reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i] =
+- ext_chan_list_event_hdr->min_bw_6ghz_client_lpi[i];
++ ev->min_bw_6ghz_client_lpi[i];
+ reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i] =
+- ext_chan_list_event_hdr->max_bw_6ghz_client_lpi[i];
++ ev->max_bw_6ghz_client_lpi[i];
+ reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
+- ext_chan_list_event_hdr->min_bw_6ghz_client_sp[i];
++ ev->min_bw_6ghz_client_sp[i];
+ reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
+- ext_chan_list_event_hdr->max_bw_6ghz_client_sp[i];
++ ev->max_bw_6ghz_client_sp[i];
+ reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
+- ext_chan_list_event_hdr->min_bw_6ghz_client_vlp[i];
++ ev->min_bw_6ghz_client_vlp[i];
+ reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
+- ext_chan_list_event_hdr->max_bw_6ghz_client_vlp[i];
++ ev->max_bw_6ghz_client_vlp[i];
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "6 GHz %s BW: LPI (%d - %d), SP (%d - %d), VLP (%d - %d)\n",
++ ath11k_6ghz_client_type_to_str(i),
++ reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i],
++ reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i],
++ reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i],
++ reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i],
++ reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i],
++ reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i]);
+ }
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
+- "%s:cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
+- __func__, reg_info->alpha2, reg_info->dfs_region,
++ "cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
++ 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);
+
+@@ -5310,9 +5362,8 @@ static int ath11k_pull_reg_chan_list_ext
+ num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]);
+
+ ext_wmi_reg_rule =
+- (struct wmi_regulatory_ext_rule *)((u8 *)ext_chan_list_event_hdr
+- + sizeof(*ext_chan_list_event_hdr)
+- + sizeof(struct wmi_tlv));
++ (struct wmi_regulatory_ext_rule *)((u8 *)ev + sizeof(*ev) +
++ sizeof(struct wmi_tlv));
+ if (num_2ghz_reg_rules) {
+ reg_info->reg_rules_2ghz_ptr =
+ create_ext_reg_rules_from_wmi(num_2ghz_reg_rules,
+@@ -5323,6 +5374,10 @@ static int ath11k_pull_reg_chan_list_ext
+ ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n");
+ return -ENOMEM;
+ }
++
++ ath11k_print_reg_rule(ab, "2 GHz",
++ num_2ghz_reg_rules,
++ reg_info->reg_rules_2ghz_ptr);
+ }
+
+ ext_wmi_reg_rule += num_2ghz_reg_rules;
+@@ -5358,6 +5413,10 @@ static int ath11k_pull_reg_chan_list_ext
+ ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n");
+ return -ENOMEM;
+ }
++
++ ath11k_print_reg_rule(ab, "5 GHz",
++ num_5ghz_reg_rules,
++ reg_info->reg_rules_5ghz_ptr);
+ }
+
+ /* We have adjusted the number of 5 GHz reg rules above. But still those
+@@ -5378,10 +5437,17 @@ static int ath11k_pull_reg_chan_list_ext
+ return -ENOMEM;
+ }
+
++ ath11k_print_reg_rule(ab, ath11k_6ghz_ap_type_to_str(i),
++ num_6ghz_reg_rules_ap[i],
++ reg_info->reg_rules_6ghz_ap_ptr[i]);
++
+ ext_wmi_reg_rule += num_6ghz_reg_rules_ap[i];
+ }
+
+ for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "6 GHz AP type %s", ath11k_6ghz_ap_type_to_str(j));
++
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
+ reg_info->reg_rules_6ghz_client_ptr[j][i] =
+ create_ext_reg_rules_from_wmi(num_6ghz_client[j][i],
+@@ -5393,35 +5459,58 @@ static int ath11k_pull_reg_chan_list_ext
+ return -ENOMEM;
+ }
+
++ ath11k_print_reg_rule(ab,
++ ath11k_6ghz_client_type_to_str(i),
++ num_6ghz_client[j][i],
++ reg_info->reg_rules_6ghz_client_ptr[j][i]);
++
+ ext_wmi_reg_rule += num_6ghz_client[j][i];
+ }
+ }
+
+- reg_info->client_type = ext_chan_list_event_hdr->client_type;
+- reg_info->rnr_tpe_usable = ext_chan_list_event_hdr->rnr_tpe_usable;
++ reg_info->client_type = ev->client_type;
++ reg_info->rnr_tpe_usable = ev->rnr_tpe_usable;
+ reg_info->unspecified_ap_usable =
+- ext_chan_list_event_hdr->unspecified_ap_usable;
++ ev->unspecified_ap_usable;
+ reg_info->domain_code_6ghz_ap[WMI_REG_INDOOR_AP] =
+- ext_chan_list_event_hdr->domain_code_6ghz_ap_lpi;
++ ev->domain_code_6ghz_ap_lpi;
+ reg_info->domain_code_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
+- ext_chan_list_event_hdr->domain_code_6ghz_ap_sp;
++ ev->domain_code_6ghz_ap_sp;
+ reg_info->domain_code_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
+- ext_chan_list_event_hdr->domain_code_6ghz_ap_vlp;
++ ev->domain_code_6ghz_ap_vlp;
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s, sp %s, vlp %s\n",
++ ath11k_6ghz_client_type_to_str(reg_info->client_type),
++ reg_info->rnr_tpe_usable,
++ reg_info->unspecified_ap_usable,
++ ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_lpi),
++ ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_sp),
++ ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_ap_vlp));
+
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
+ reg_info->domain_code_6ghz_client[WMI_REG_INDOOR_AP][i] =
+- ext_chan_list_event_hdr->domain_code_6ghz_client_lpi[i];
++ ev->domain_code_6ghz_client_lpi[i];
+ reg_info->domain_code_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
+- ext_chan_list_event_hdr->domain_code_6ghz_client_sp[i];
++ ev->domain_code_6ghz_client_sp[i];
+ reg_info->domain_code_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
+- ext_chan_list_event_hdr->domain_code_6ghz_client_vlp[i];
++ ev->domain_code_6ghz_client_vlp[i];
++
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "6 GHz client type %s client sub domain: lpi %s, sp %s, vlp %s\n",
++ ath11k_6ghz_client_type_to_str(i),
++ ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_lpi[i]),
++ ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_sp[i]),
++ ath11k_sub_reg_6ghz_to_str(ev->domain_code_6ghz_client_vlp[i])
++ );
+ }
+
+- reg_info->domain_code_6ghz_super_id =
+- ext_chan_list_event_hdr->domain_code_6ghz_super_id;
++ reg_info->domain_code_6ghz_super_id = ev->domain_code_6ghz_super_id;
+
+- ath11k_dbg(ab, ATH11K_DBG_WMI, "6 GHz client_type: %d domain_code_6ghz_super_id: %d",
+- reg_info->client_type, reg_info->domain_code_6ghz_super_id);
++ ath11k_dbg(ab, ATH11K_DBG_WMI,
++ "6 GHz client_type %s 6 GHz super domain %s",
++ ath11k_6ghz_client_type_to_str(reg_info->client_type),
++ ath11k_super_reg_6ghz_to_str(reg_info->domain_code_6ghz_super_id));
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory ext channel list\n");
+
+--- a/drivers/net/wireless/ath/ath11k/wmi.h
++++ b/drivers/net/wireless/ath/ath11k/wmi.h
+@@ -4139,6 +4139,7 @@ enum cc_setting_code {
+
+ /* add new setting code above, update in
+ * @enum wmi_reg_cc_setting_code as well.
++ * Also handle it in ath11k_cc_status_to_str()
+ */
+ };
+
+@@ -4163,21 +4164,162 @@ ath11k_wmi_cc_setting_code_to_reg(enum w
+ return REG_SET_CC_STATUS_FAIL;
+ }
+
++static inline const char *ath11k_cc_status_to_str(enum cc_setting_code code)
++{
++ switch (code) {
++ case REG_SET_CC_STATUS_PASS:
++ return "REG_SET_CC_STATUS_PASS";
++ case REG_CURRENT_ALPHA2_NOT_FOUND:
++ return "REG_CURRENT_ALPHA2_NOT_FOUND";
++ case REG_INIT_ALPHA2_NOT_FOUND:
++ return "REG_INIT_ALPHA2_NOT_FOUND";
++ case REG_SET_CC_CHANGE_NOT_ALLOWED:
++ return "REG_SET_CC_CHANGE_NOT_ALLOWED";
++ case REG_SET_CC_STATUS_NO_MEMORY:
++ return "REG_SET_CC_STATUS_NO_MEMORY";
++ case REG_SET_CC_STATUS_FAIL:
++ return "REG_SET_CC_STATUS_FAIL";
++ }
++
++ return "Unknown CC status";
++}
++
+ enum wmi_reg_6ghz_ap_type {
+ WMI_REG_INDOOR_AP = 0,
+ WMI_REG_STANDARD_POWER_AP = 1,
+ WMI_REG_VERY_LOW_POWER_AP = 2,
+
++ /* add AP type above, handle in ath11k_6ghz_ap_type_to_str()
++ */
+ WMI_REG_CURRENT_MAX_AP_TYPE,
+ WMI_REG_MAX_AP_TYPE = 7,
+ };
+
++static inline const char *
++ath11k_6ghz_ap_type_to_str(enum wmi_reg_6ghz_ap_type type)
++{
++ switch (type) {
++ case WMI_REG_INDOOR_AP:
++ return "INDOOR AP";
++ case WMI_REG_STANDARD_POWER_AP:
++ return "STANDARD POWER AP";
++ case WMI_REG_VERY_LOW_POWER_AP:
++ return "VERY LOW POWER AP";
++ case WMI_REG_CURRENT_MAX_AP_TYPE:
++ return "CURRENT_MAX_AP_TYPE";
++ case WMI_REG_MAX_AP_TYPE:
++ return "MAX_AP_TYPE";
++ }
++
++ return "unknown 6 GHz AP type";
++}
++
+ enum wmi_reg_6ghz_client_type {
+ WMI_REG_DEFAULT_CLIENT = 0,
+ WMI_REG_SUBORDINATE_CLIENT = 1,
+ WMI_REG_MAX_CLIENT_TYPE = 2,
++
++ /* add client type above, handle it in
++ * ath11k_6ghz_client_type_to_str()
++ */
++};
++
++static inline const char *
++ath11k_6ghz_client_type_to_str(enum wmi_reg_6ghz_client_type type)
++{
++ switch (type) {
++ case WMI_REG_DEFAULT_CLIENT:
++ return "DEFAULT CLIENT";
++ case WMI_REG_SUBORDINATE_CLIENT:
++ return "SUBORDINATE CLIENT";
++ case WMI_REG_MAX_CLIENT_TYPE:
++ return "MAX_CLIENT_TYPE";
++ }
++
++ return "unknown 6 GHz client type";
++}
++
++enum reg_subdomains_6ghz {
++ EMPTY_6GHZ = 0x0,
++ FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01,
++ FCC1_CLIENT_SP_6GHZ = 0x02,
++ FCC1_AP_LPI_6GHZ = 0x03,
++ FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ,
++ FCC1_AP_SP_6GHZ = 0x04,
++ ETSI1_LPI_6GHZ = 0x10,
++ ETSI1_VLP_6GHZ = 0x11,
++ ETSI2_LPI_6GHZ = 0x12,
++ ETSI2_VLP_6GHZ = 0x13,
++ APL1_LPI_6GHZ = 0x20,
++ APL1_VLP_6GHZ = 0x21,
++
++ /* add sub-domain above, handle it in
++ * ath11k_sub_reg_6ghz_to_str()
++ */
++};
++
++static inline const char *
++ath11k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz sub_id)
++{
++ switch (sub_id) {
++ case EMPTY_6GHZ:
++ return "N/A";
++ case FCC1_CLIENT_LPI_REGULAR_6GHZ:
++ return "FCC1_CLIENT_LPI_REGULAR_6GHZ";
++ case FCC1_CLIENT_SP_6GHZ:
++ return "FCC1_CLIENT_SP_6GHZ";
++ case FCC1_AP_LPI_6GHZ:
++ return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE";
++ case FCC1_AP_SP_6GHZ:
++ return "FCC1_AP_SP_6GHZ";
++ case ETSI1_LPI_6GHZ:
++ return "ETSI1_LPI_6GHZ";
++ case ETSI1_VLP_6GHZ:
++ return "ETSI1_VLP_6GHZ";
++ case ETSI2_LPI_6GHZ:
++ return "ETSI2_LPI_6GHZ";
++ case ETSI2_VLP_6GHZ:
++ return "ETSI2_VLP_6GHZ";
++ case APL1_LPI_6GHZ:
++ return "APL1_LPI_6GHZ";
++ case APL1_VLP_6GHZ:
++ return "APL1_VLP_6GHZ";
++ }
++
++ return "unknown sub reg id";
++}
++
++enum reg_super_domain_6ghz {
++ FCC1_6GHZ = 0x01,
++ ETSI1_6GHZ = 0x02,
++ ETSI2_6GHZ = 0x03,
++ APL1_6GHZ = 0x04,
++ FCC1_6GHZ_CL = 0x05,
++
++ /* add super domain above, handle it in
++ * ath11k_super_reg_6ghz_to_str()
++ */
+ };
+
++static inline const char *
++ath11k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz domain_id)
++{
++ switch (domain_id) {
++ case FCC1_6GHZ:
++ return "FCC1_6GHZ";
++ case ETSI1_6GHZ:
++ return "ETSI1_6GHZ";
++ case ETSI2_6GHZ:
++ return "ETSI2_6GHZ";
++ case APL1_6GHZ:
++ return "APL1_6GHZ";
++ case FCC1_6GHZ_CL:
++ return "FCC1_6GHZ_CL";
++ }
++
++ return "unknown domain id";
++}
++
+ struct cur_reg_rule {
+ u16 start_freq;
+ u16 end_freq;
diff --git a/package/kernel/mac80211/patches/ath11k/0046-wifi-ath11k-Replace-fake-flex-array-with-flexible-ar.patch b/package/kernel/mac80211/patches/ath11k/0046-wifi-ath11k-Replace-fake-flex-array-with-flexible-ar.patch
new file mode 100644
index 0000000000..bd16178564
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0046-wifi-ath11k-Replace-fake-flex-array-with-flexible-ar.patch
@@ -0,0 +1,246 @@
+From 3b1088a09ec9438523c251d8435e78988824bc0d Mon Sep 17 00:00:00 2001
+From: "Gustavo A. R. Silva" <gustavoars@kernel.org>
+Date: Tue, 7 Mar 2023 16:22:39 -0600
+Subject: [PATCH] wifi: ath11k: Replace fake flex-array with flexible-array
+ member
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Zero-length arrays as fake flexible arrays are deprecated and we are
+moving towards adopting C99 flexible-array members instead.
+
+Address 25 of the following warnings found with GCC-13 and
+-fstrict-flex-arrays=3 enabled:
+drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c:30:51: warning: array subscript <unknown> is outside array bounds of ‘const u32[0]’ {aka ‘const unsigned int[]’} [-Warray-bounds=]
+
+This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
+routines on memcpy() and help us make progress towards globally
+enabling -fstrict-flex-arrays=3 [1].
+
+Link: https://github.com/KSPP/linux/issues/21
+Link: https://github.com/KSPP/linux/issues/266
+Link: https://gcc.gnu.org/pipermail/gcc-patches/2022-October/602902.html [1]
+Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
+Reviewed-by: Simon Horman <simon.horman@corigine.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/ZAe5L5DtmsQxzqRH@work
+---
+ .../wireless/ath/ath11k/debugfs_htt_stats.h | 73 +++++++++++--------
+ 1 file changed, 43 insertions(+), 30 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
++++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
+@@ -143,7 +143,8 @@ enum htt_tx_pdev_underrun_enum {
+ /* Bytes stored in little endian order */
+ /* Length should be multiple of DWORD */
+ struct htt_stats_string_tlv {
+- u32 data[0]; /* Can be variable length */
++ /* Can be variable length */
++ DECLARE_FLEX_ARRAY(u32, data);
+ } __packed;
+
+ #define HTT_STATS_MAC_ID GENMASK(7, 0)
+@@ -205,27 +206,32 @@ struct htt_tx_pdev_stats_cmn_tlv {
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_pdev_stats_urrn_tlv_v {
+- u32 urrn_stats[0]; /* HTT_TX_PDEV_MAX_URRN_STATS */
++ /* HTT_TX_PDEV_MAX_URRN_STATS */
++ DECLARE_FLEX_ARRAY(u32, urrn_stats);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_pdev_stats_flush_tlv_v {
+- u32 flush_errs[0]; /* HTT_TX_PDEV_MAX_FLUSH_REASON_STATS */
++ /* HTT_TX_PDEV_MAX_FLUSH_REASON_STATS */
++ DECLARE_FLEX_ARRAY(u32, flush_errs);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_pdev_stats_sifs_tlv_v {
+- u32 sifs_status[0]; /* HTT_TX_PDEV_MAX_SIFS_BURST_STATS */
++ /* HTT_TX_PDEV_MAX_SIFS_BURST_STATS */
++ DECLARE_FLEX_ARRAY(u32, sifs_status);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_pdev_stats_phy_err_tlv_v {
+- u32 phy_errs[0]; /* HTT_TX_PDEV_MAX_PHY_ERR_STATS */
++ /* HTT_TX_PDEV_MAX_PHY_ERR_STATS */
++ DECLARE_FLEX_ARRAY(u32, phy_errs);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_pdev_stats_sifs_hist_tlv_v {
+- u32 sifs_hist_status[0]; /* HTT_TX_PDEV_SIFS_BURST_HIST_STATS */
++ /* HTT_TX_PDEV_SIFS_BURST_HIST_STATS */
++ DECLARE_FLEX_ARRAY(u32, sifs_hist_status);
+ };
+
+ struct htt_tx_pdev_stats_tx_ppdu_stats_tlv_v {
+@@ -590,20 +596,20 @@ struct htt_tx_hwq_difs_latency_stats_tlv
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_hwq_cmd_result_stats_tlv_v {
+- /* Histogram of sched cmd result */
+- u32 cmd_result[0]; /* HTT_TX_HWQ_MAX_CMD_RESULT_STATS */
++ /* Histogram of sched cmd result, HTT_TX_HWQ_MAX_CMD_RESULT_STATS */
++ DECLARE_FLEX_ARRAY(u32, cmd_result);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_hwq_cmd_stall_stats_tlv_v {
+- /* Histogram of various pause conitions */
+- u32 cmd_stall_status[0]; /* HTT_TX_HWQ_MAX_CMD_STALL_STATS */
++ /* Histogram of various pause conitions, HTT_TX_HWQ_MAX_CMD_STALL_STATS */
++ DECLARE_FLEX_ARRAY(u32, cmd_stall_status);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_hwq_fes_result_stats_tlv_v {
+- /* Histogram of number of user fes result */
+- u32 fes_result[0]; /* HTT_TX_HWQ_MAX_FES_RESULT_STATS */
++ /* Histogram of number of user fes result, HTT_TX_HWQ_MAX_FES_RESULT_STATS */
++ DECLARE_FLEX_ARRAY(u32, fes_result);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size
+@@ -635,8 +641,8 @@ struct htt_tx_hwq_tried_mpdu_cnt_hist_tl
+ * #define WAL_TXOP_USED_HISTOGRAM_INTERVAL 1000 ( 1 ms )
+ */
+ struct htt_tx_hwq_txop_used_cnt_hist_tlv_v {
+- /* Histogram of txop used cnt */
+- u32 txop_used_cnt_hist[0]; /* HTT_TX_HWQ_TXOP_USED_CNT_HIST */
++ /* Histogram of txop used cnt, HTT_TX_HWQ_TXOP_USED_CNT_HIST */
++ DECLARE_FLEX_ARRAY(u32, txop_used_cnt_hist);
+ };
+
+ /* == TX SELFGEN STATS == */
+@@ -804,17 +810,20 @@ struct htt_tx_pdev_mpdu_stats_tlv {
+ /* == TX SCHED STATS == */
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_sched_txq_cmd_posted_tlv_v {
+- u32 sched_cmd_posted[0]; /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */
++ /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */
++ DECLARE_FLEX_ARRAY(u32, sched_cmd_posted);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_sched_txq_cmd_reaped_tlv_v {
+- u32 sched_cmd_reaped[0]; /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */
++ /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */
++ DECLARE_FLEX_ARRAY(u32, sched_cmd_reaped);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_sched_txq_sched_order_su_tlv_v {
+- u32 sched_order_su[0]; /* HTT_TX_PDEV_NUM_SCHED_ORDER_LOG */
++ /* HTT_TX_PDEV_NUM_SCHED_ORDER_LOG */
++ DECLARE_FLEX_ARRAY(u32, sched_order_su);
+ };
+
+ enum htt_sched_txq_sched_ineligibility_tlv_enum {
+@@ -842,7 +851,7 @@ enum htt_sched_txq_sched_ineligibility_t
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_sched_txq_sched_ineligibility_tlv_v {
+ /* indexed by htt_sched_txq_sched_ineligibility_tlv_enum */
+- u32 sched_ineligibility[0];
++ DECLARE_FLEX_ARRAY(u32, sched_ineligibility);
+ };
+
+ #define HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID GENMASK(7, 0)
+@@ -888,18 +897,20 @@ struct htt_stats_tx_sched_cmn_tlv {
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_tqm_gen_mpdu_stats_tlv_v {
+- u32 gen_mpdu_end_reason[0]; /* HTT_TX_TQM_MAX_GEN_MPDU_END_REASON */
++ /* HTT_TX_TQM_MAX_GEN_MPDU_END_REASON */
++ DECLARE_FLEX_ARRAY(u32, gen_mpdu_end_reason);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_tqm_list_mpdu_stats_tlv_v {
+- u32 list_mpdu_end_reason[0]; /* HTT_TX_TQM_MAX_LIST_MPDU_END_REASON */
++ /* HTT_TX_TQM_MAX_LIST_MPDU_END_REASON */
++ DECLARE_FLEX_ARRAY(u32, list_mpdu_end_reason);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_tx_tqm_list_mpdu_cnt_tlv_v {
+- u32 list_mpdu_cnt_hist[0];
+- /* HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS */
++ /* HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS */
++ DECLARE_FLEX_ARRAY(u32, list_mpdu_cnt_hist);
+ };
+
+ struct htt_tx_tqm_pdev_stats_tlv_v {
+@@ -1098,7 +1109,7 @@ struct htt_tx_de_compl_stats_tlv {
+ * ENTRIES_PER_BIN_COUNT)
+ */
+ struct htt_tx_de_fw2wbm_ring_full_hist_tlv {
+- u32 fw2wbm_ring_full_hist[0];
++ DECLARE_FLEX_ARRAY(u32, fw2wbm_ring_full_hist);
+ };
+
+ struct htt_tx_de_cmn_stats_tlv {
+@@ -1151,7 +1162,7 @@ struct htt_ring_if_cmn_tlv {
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_sfm_client_user_tlv_v {
+ /* Number of DWORDS used per user and per client */
+- u32 dwords_used_by_user_n[0];
++ DECLARE_FLEX_ARRAY(u32, dwords_used_by_user_n);
+ };
+
+ struct htt_sfm_client_tlv {
+@@ -1436,12 +1447,14 @@ struct htt_rx_soc_fw_stats_tlv {
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_rx_soc_fw_refill_ring_empty_tlv_v {
+- u32 refill_ring_empty_cnt[0]; /* HTT_RX_STATS_REFILL_MAX_RING */
++ /* HTT_RX_STATS_REFILL_MAX_RING */
++ DECLARE_FLEX_ARRAY(u32, refill_ring_empty_cnt);
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_rx_soc_fw_refill_ring_num_refill_tlv_v {
+- u32 refill_ring_num_refill[0]; /* HTT_RX_STATS_REFILL_MAX_RING */
++ /* HTT_RX_STATS_REFILL_MAX_RING */
++ DECLARE_FLEX_ARRAY(u32, refill_ring_num_refill);
+ };
+
+ /* RXDMA error code from WBM released packets */
+@@ -1473,7 +1486,7 @@ enum htt_rx_rxdma_error_code_enum {
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_rx_soc_fw_refill_ring_num_rxdma_err_tlv_v {
+- u32 rxdma_err[0]; /* HTT_RX_RXDMA_MAX_ERR_CODE */
++ DECLARE_FLEX_ARRAY(u32, rxdma_err); /* HTT_RX_RXDMA_MAX_ERR_CODE */
+ };
+
+ /* REO error code from WBM released packets */
+@@ -1505,7 +1518,7 @@ enum htt_rx_reo_error_code_enum {
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_rx_soc_fw_refill_ring_num_reo_err_tlv_v {
+- u32 reo_err[0]; /* HTT_RX_REO_MAX_ERR_CODE */
++ DECLARE_FLEX_ARRAY(u32, reo_err); /* HTT_RX_REO_MAX_ERR_CODE */
+ };
+
+ /* == RX PDEV STATS == */
+@@ -1622,13 +1635,13 @@ struct htt_rx_pdev_fw_stats_phy_err_tlv
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_rx_pdev_fw_ring_mpdu_err_tlv_v {
+ /* Num error MPDU for each RxDMA error type */
+- u32 fw_ring_mpdu_err[0]; /* HTT_RX_STATS_RXDMA_MAX_ERR */
++ DECLARE_FLEX_ARRAY(u32, fw_ring_mpdu_err); /* HTT_RX_STATS_RXDMA_MAX_ERR */
+ };
+
+ /* NOTE: Variable length TLV, use length spec to infer array size */
+ struct htt_rx_pdev_fw_mpdu_drop_tlv_v {
+ /* Num MPDU dropped */
+- u32 fw_mpdu_drop[0]; /* HTT_RX_STATS_FW_DROP_REASON_MAX */
++ DECLARE_FLEX_ARRAY(u32, fw_mpdu_drop); /* HTT_RX_STATS_FW_DROP_REASON_MAX */
+ };
+
+ #define HTT_PDEV_CCA_STATS_TX_FRAME_INFO_PRESENT (0x1)
diff --git a/package/kernel/mac80211/patches/ath11k/0047-wifi-ath11k-fix-deinitialization-of-firmware-resourc.patch b/package/kernel/mac80211/patches/ath11k/0047-wifi-ath11k-fix-deinitialization-of-firmware-resourc.patch
new file mode 100644
index 0000000000..eec11f50e3
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0047-wifi-ath11k-fix-deinitialization-of-firmware-resourc.patch
@@ -0,0 +1,79 @@
+From 5a78ac33e3cb8822da64dd1af196e83664b332b0 Mon Sep 17 00:00:00 2001
+From: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Date: Thu, 9 Mar 2023 15:23:08 +0530
+Subject: [PATCH] wifi: ath11k: fix deinitialization of firmware resources
+
+Currently, in ath11k_ahb_fw_resources_init(), iommu domain
+mapping is done only for the chipsets having fixed firmware
+memory. Also, for such chipsets, mapping is done only if it
+does not have TrustZone support.
+
+During deinitialization, only if TrustZone support is not there,
+iommu is unmapped back. However, for non fixed firmware memory
+chipsets, TrustZone support is not there and this makes the
+condition check to true and it tries to unmap the memory which
+was not mapped during initialization.
+
+This leads to the following trace -
+
+[ 83.198790] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008
+[ 83.259537] Modules linked in: ath11k_ahb ath11k qmi_helpers
+.. snip ..
+[ 83.280286] pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
+[ 83.287228] pc : __iommu_unmap+0x30/0x140
+[ 83.293907] lr : iommu_unmap+0x5c/0xa4
+[ 83.298072] sp : ffff80000b3abad0
+.. snip ..
+[ 83.369175] Call trace:
+[ 83.376282] __iommu_unmap+0x30/0x140
+[ 83.378541] iommu_unmap+0x5c/0xa4
+[ 83.382360] ath11k_ahb_fw_resource_deinit.part.12+0x2c/0xac [ath11k_ahb]
+[ 83.385666] ath11k_ahb_free_resources+0x140/0x17c [ath11k_ahb]
+[ 83.392521] ath11k_ahb_shutdown+0x34/0x40 [ath11k_ahb]
+[ 83.398248] platform_shutdown+0x20/0x2c
+[ 83.403455] device_shutdown+0x16c/0x1c4
+[ 83.407621] kernel_restart_prepare+0x34/0x3c
+[ 83.411529] kernel_restart+0x14/0x74
+[ 83.415781] __do_sys_reboot+0x1c4/0x22c
+[ 83.419427] __arm64_sys_reboot+0x1c/0x24
+[ 83.423420] invoke_syscall+0x44/0xfc
+[ 83.427326] el0_svc_common.constprop.3+0xac/0xe8
+[ 83.430974] do_el0_svc+0xa0/0xa8
+[ 83.435659] el0_svc+0x1c/0x44
+[ 83.438957] el0t_64_sync_handler+0x60/0x144
+[ 83.441910] el0t_64_sync+0x15c/0x160
+[ 83.446343] Code: aa0103f4 f9400001 f90027a1 d2800001 (f94006a0)
+[ 83.449903] ---[ end trace 0000000000000000 ]---
+
+This can be reproduced by probing an AHB chipset which is not
+having a fixed memory region. During reboot (or rmmod) trace
+can be seen.
+
+Fix this issue by adding a condition check on firmware fixed memory
+hw_param as done in the counter initialization function.
+
+Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
+
+Fixes: f9eec4947add ("ath11k: Add support for targets without trustzone")
+Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/20230309095308.24937-1-quic_adisi@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/ahb.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/wireless/ath/ath11k/ahb.c
++++ b/drivers/net/wireless/ath/ath11k/ahb.c
+@@ -1078,6 +1078,12 @@ static int ath11k_ahb_fw_resource_deinit
+ struct iommu_domain *iommu;
+ size_t unmapped_size;
+
++ /* Chipsets not requiring MSA would have not initialized
++ * MSA resources, return success in such cases.
++ */
++ if (!ab->hw_params.fixed_fw_mem)
++ return 0;
++
+ if (ab_ahb->fw.use_tz)
+ return 0;
+