mac80211: ath11k: fix remapped ce access on 64-bit OS
authorGeorge Moussalem <george.moussalem@outlook.com>
Mon, 7 Oct 2024 11:54:27 +0000 (15:54 +0400)
committerRobert Marko <robimarko@gmail.com>
Thu, 6 Feb 2025 08:51:13 +0000 (09:51 +0100)
https://lore.kernel.org/linux-wireless/TYZPR01MB55563B3A689D54D18179E5B4C9192@TYZPR01MB5556.apcprd01.prod.exchangelabs.com/

Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
Link: https://github.com/openwrt/openwrt/pull/17182
Signed-off-by: Robert Marko <robimarko@gmail.com>
package/kernel/mac80211/patches/ath11k/910-ath11k-fix-remapped-ce-accessing-issue-on-64bit-OS.patch [new file with mode: 0644]

diff --git a/package/kernel/mac80211/patches/ath11k/910-ath11k-fix-remapped-ce-accessing-issue-on-64bit-OS.patch b/package/kernel/mac80211/patches/ath11k/910-ath11k-fix-remapped-ce-accessing-issue-on-64bit-OS.patch
new file mode 100644 (file)
index 0000000..5878fa0
--- /dev/null
@@ -0,0 +1,153 @@
+From: Ziyang Huang <hzyitc@outlook.com>
+Date: Thu,  2 May 2024 00:14:31 +0800
+Subject: [PATCH] wifi: ath11k: fix remapped ce accessing issue on 64bit OS
+
+On 64bit OS, when ab->mem_ce is lower than or 4G far away from ab->mem,
+u32 is not enough to store the offsets, which makes ath11k_ahb_read32()
+and ath11k_ahb_write32() access incorrect address and causes Data Abort
+Exception.
+
+Let's use the high bits of offsets to decide where to access, which is
+similar as ath11k_pci_get_window_start() done. In the future, we can merge
+these functions for unified regs accessing.
+
+Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
+---
+
+--- a/drivers/net/wireless/ath/ath11k/ahb.c
++++ b/drivers/net/wireless/ath/ath11k/ahb.c
+@@ -198,12 +198,18 @@ static const struct ath11k_pci_ops ath11
+ static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
+ {
+-      return ioread32(ab->mem + offset);
++      if ((offset & ATH11K_REG_TYPE_MASK) == ATH11K_REG_TYPE_CE)
++              return ioread32(ab->mem_ce + FIELD_GET(ATH11K_REG_OFFSET_MASK, offset));
++      else
++              return ioread32(ab->mem + FIELD_GET(ATH11K_REG_OFFSET_MASK, offset));
+ }
+ static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)
+ {
+-      iowrite32(value, ab->mem + offset);
++      if ((offset & ATH11K_REG_TYPE_MASK) == ATH11K_REG_TYPE_CE)
++              iowrite32(value, ab->mem_ce + FIELD_GET(ATH11K_REG_OFFSET_MASK, offset));
++      else
++              iowrite32(value, ab->mem + FIELD_GET(ATH11K_REG_OFFSET_MASK, offset));
+ }
+ static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)
+@@ -275,9 +281,9 @@ static void ath11k_ahb_ce_irq_enable(str
+       const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
+       u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
+-      ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
+-      ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
+-      ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
++      ie1_reg_addr = ce_ie_addr->ie1_reg_addr;
++      ie2_reg_addr = ce_ie_addr->ie2_reg_addr;
++      ie3_reg_addr = ce_ie_addr->ie3_reg_addr;
+       ce_attr = &ab->hw_params.host_ce_config[ce_id];
+       if (ce_attr->src_nentries)
+@@ -296,9 +302,9 @@ static void ath11k_ahb_ce_irq_disable(st
+       const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
+       u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
+-      ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
+-      ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
+-      ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
++      ie1_reg_addr = ce_ie_addr->ie1_reg_addr;
++      ie2_reg_addr = ce_ie_addr->ie2_reg_addr;
++      ie3_reg_addr = ce_ie_addr->ie3_reg_addr;
+       ce_attr = &ab->hw_params.host_ce_config[ce_id];
+       if (ce_attr->src_nentries)
+--- a/drivers/net/wireless/ath/ath11k/hal.c
++++ b/drivers/net/wireless/ath/ath11k/hal.c
+@@ -1247,20 +1247,16 @@ static int ath11k_hal_srng_create_config
+       s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP;
+       s = &hal->srng_config[HAL_CE_SRC];
+-      s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_BASE_LSB +
+-              ATH11K_CE_OFFSET(ab);
+-      s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_HP +
+-              ATH11K_CE_OFFSET(ab);
++      s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_BASE_LSB;
++      s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) + HAL_CE_DST_RING_HP;
+       s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab);
+       s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab);
+       s = &hal->srng_config[HAL_CE_DST];
+-      s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_BASE_LSB +
+-              ATH11K_CE_OFFSET(ab);
+-      s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_HP +
+-              ATH11K_CE_OFFSET(ab);
++      s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_BASE_LSB;
++      s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_RING_HP;
+       s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);
+       s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -
+@@ -1268,9 +1264,8 @@ static int ath11k_hal_srng_create_config
+       s = &hal->srng_config[HAL_CE_DST_STATUS];
+       s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) +
+-              HAL_CE_DST_STATUS_RING_BASE_LSB + ATH11K_CE_OFFSET(ab);
+-      s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_STATUS_RING_HP +
+-              ATH11K_CE_OFFSET(ab);
++              HAL_CE_DST_STATUS_RING_BASE_LSB;
++      s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) + HAL_CE_DST_STATUS_RING_HP;
+       s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -
+               HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab);
+       s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) -
+--- a/drivers/net/wireless/ath/ath11k/hw.c
++++ b/drivers/net/wireless/ath/ath11k/hw.c
+@@ -2268,9 +2268,9 @@ const struct ce_ie_addr ath11k_ce_ie_add
+ };
+ const struct ce_ie_addr ath11k_ce_ie_addr_ipq5018 = {
+-      .ie1_reg_addr = CE_HOST_IPQ5018_IE_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE,
+-      .ie2_reg_addr = CE_HOST_IPQ5018_IE_2_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE,
+-      .ie3_reg_addr = CE_HOST_IPQ5018_IE_3_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE,
++      .ie1_reg_addr = ATH11K_REG_TYPE_CE + CE_HOST_IPQ5018_IE_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE,
++      .ie2_reg_addr = ATH11K_REG_TYPE_CE + CE_HOST_IPQ5018_IE_2_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE,
++      .ie3_reg_addr = ATH11K_REG_TYPE_CE + CE_HOST_IPQ5018_IE_3_ADDRESS - HAL_IPQ5018_CE_WFSS_REG_BASE,
+ };
+ const struct ce_remap ath11k_ce_remap_ipq5018 = {
+@@ -2801,13 +2801,13 @@ const struct ath11k_hw_regs ipq5018_regs
+       .hal_reo_status_hp = 0x00003070,
+       /* WCSS relative address */
+-      .hal_seq_wcss_umac_ce0_src_reg = 0x08400000
++      .hal_seq_wcss_umac_ce0_src_reg = ATH11K_REG_TYPE_CE + 0x08400000
+               - HAL_IPQ5018_CE_WFSS_REG_BASE,
+-      .hal_seq_wcss_umac_ce0_dst_reg = 0x08401000
++      .hal_seq_wcss_umac_ce0_dst_reg = ATH11K_REG_TYPE_CE + 0x08401000
+               - HAL_IPQ5018_CE_WFSS_REG_BASE,
+-      .hal_seq_wcss_umac_ce1_src_reg = 0x08402000
++      .hal_seq_wcss_umac_ce1_src_reg = ATH11K_REG_TYPE_CE + 0x08402000
+               - HAL_IPQ5018_CE_WFSS_REG_BASE,
+-      .hal_seq_wcss_umac_ce1_dst_reg = 0x08403000
++      .hal_seq_wcss_umac_ce1_dst_reg = ATH11K_REG_TYPE_CE + 0x08403000
+               - HAL_IPQ5018_CE_WFSS_REG_BASE,
+       /* WBM Idle address */
+--- a/drivers/net/wireless/ath/ath11k/hw.h
++++ b/drivers/net/wireless/ath/ath11k/hw.h
+@@ -81,7 +81,12 @@
+ #define ATH11K_M3_FILE                        "m3.bin"
+ #define ATH11K_REGDB_FILE_NAME                "regdb.bin"
+-#define ATH11K_CE_OFFSET(ab)  (ab->mem_ce - ab->mem)
++#define ATH11K_REG_TYPE_MASK          GENMASK(31, 28)
++#define  ATH11K_REG_TYPE(x)           FIELD_PREP_CONST(ATH11K_REG_TYPE_MASK, x)
++#define  ATH11K_REG_TYPE_NORMAL               ATH11K_REG_TYPE(0)
++#define  ATH11K_REG_TYPE_DP           ATH11K_REG_TYPE(1)
++#define  ATH11K_REG_TYPE_CE           ATH11K_REG_TYPE(2)
++#define ATH11K_REG_OFFSET_MASK                GENMASK(27, 0)
+ enum ath11k_hw_rate_cck {
+       ATH11K_HW_RATE_CCK_LP_11M = 0,