mac80211: ath11k: sync with ath-next
authorRobert Marko <robimarko@gmail.com>
Mon, 20 Mar 2023 11:12:57 +0000 (12:12 +0100)
committerRobert Marko <robimarko@gmail.com>
Mon, 20 Mar 2023 11:23:11 +0000 (12:23 +0100)
Synchronize the ath11k backports with the current ath-next tree.

This brings in actually setting the MU-MIMO parameters in HW and 6GHz
regulatory support along with some minor resource handling fixes.

This allows to easily backport further fixes as cherry picking them has
started requiring manual conflict resolution.

Signed-off-by: Robert Marko <robimarko@gmail.com>
package/kernel/mac80211/patches/ath11k/0037-wifi-ath11k-allow-system-suspend-to-survive-ath11k.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0038-wifi-ath11k-modify-accessor-macros-to-match-index-si.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0039-wifi-ath11k-push-MU-MIMO-params-from-hostapd-to-hard.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0040-wifi-ath11k-move-HE-MCS-mapper-to-a-separate-functio.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0041-wifi-ath11k-generate-rx-and-tx-mcs-maps-for-supporte.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0042-wifi-ath11k-Add-tx-ack-signal-support-for-management.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0043-wifi-ath11k-use-proper-regulatory-reference-for-band.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0044-wifi-ath11k-add-support-to-parse-new-WMI-event-for-6.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0045-wifi-ath11k-add-debug-prints-in-regulatory-WMI-event.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0046-wifi-ath11k-Replace-fake-flex-array-with-flexible-ar.patch [new file with mode: 0644]
package/kernel/mac80211/patches/ath11k/0047-wifi-ath11k-fix-deinitialization-of-firmware-resourc.patch [new file with mode: 0644]

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 (file)
index 0000000..cd8ab3d
--- /dev/null
@@ -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 (file)
index 0000000..42bf170
--- /dev/null
@@ -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 (file)
index 0000000..298ce1a
--- /dev/null
@@ -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 (file)
index 0000000..6bc9880
--- /dev/null
@@ -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 (file)
index 0000000..5cb7801
--- /dev/null
@@ -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 (file)
index 0000000..8d41657
--- /dev/null
@@ -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 (file)
index 0000000..5bc1955
--- /dev/null
@@ -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 (file)
index 0000000..e165c09
--- /dev/null
@@ -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 (file)
index 0000000..b88e519
--- /dev/null
@@ -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 (file)
index 0000000..bd16178
--- /dev/null
@@ -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 (file)
index 0000000..eec11f5
--- /dev/null
@@ -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;