mac80211: ath11k: poll reo status ring for IPQ5018
authorGeorge Moussalem <george.moussalem@outlook.com>
Mon, 16 Dec 2024 13:44:01 +0000 (17:44 +0400)
committerRobert Marko <robimarko@gmail.com>
Thu, 6 Feb 2025 08:51:14 +0000 (09:51 +0100)
This downstream patch fixes a bug which could flood the logs with the
following message and would eventually lead to a crash.

ath11k c000000.wifi: failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid 0 (-105)

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/932-wifi-ath11k-poll-reo-status-ipq5018.patch [new file with mode: 0644]

diff --git a/package/kernel/mac80211/patches/ath11k/932-wifi-ath11k-poll-reo-status-ipq5018.patch b/package/kernel/mac80211/patches/ath11k/932-wifi-ath11k-poll-reo-status-ipq5018.patch
new file mode 100644 (file)
index 0000000..d89fb92
--- /dev/null
@@ -0,0 +1,164 @@
+From d890c6d602307c9297df12c7d0287f9ffd26208b Mon Sep 17 00:00:00 2001
+From: Sriram R <srirrama@codeaurora.org>
+Date: Wed, 12 May 2021 19:21:09 +0530
+Subject: [PATCH] ath11k: poll reo status ring for IPQ5018
+
+Currently reo status interrupts are not received
+due to wrong mapping of the reo status interrupt
+line in IPQ5018.
+
+Hence, until the mapping is resolved in HW, use
+polling to reap the reo status ring. Rather than
+a period timer to reap the ring, the timer is
+triggered only on sending a reo command with
+status request.
+
+Without proper reaping of the ring, backpressure
+and ring full issues are seen in multi client test
+setups which leads to flooding the console with
+error messages reporting failure to send reo cmds.
+
+Can be reverted once HW solution is available.
+
+Signed-off-by: Sriram R <srirrama@codeaurora.org>
+---
+--- a/drivers/net/wireless/ath/ath11k/core.c
++++ b/drivers/net/wireless/ath/ath11k/core.c
+@@ -719,6 +719,7 @@ static struct ath11k_hw_params ath11k_hw
+               .smp2p_wow_exit = false,
+               .support_fw_mac_sequence = false,
+               .support_dual_stations = false,
++              .reo_status_poll = true,
+       },
+       {
+               .name = "qca2066 hw2.1",
+--- a/drivers/net/wireless/ath/ath11k/dp.c
++++ b/drivers/net/wireless/ath/ath11k/dp.c
+@@ -361,12 +361,66 @@ void ath11k_dp_stop_shadow_timers(struct
+       ath11k_dp_shadow_stop_timer(ab, &ab->dp.reo_cmd_timer);
+ }
++static void ath11k_dp_handle_reo_status_timer(struct timer_list *timer)
++{
++      struct ath11k_dp *dp = from_timer(dp, timer, reo_status_timer);
++      struct ath11k_base *ab = dp->ab;
++
++      spin_lock_bh(&dp->reo_cmd_lock);
++      dp->reo_status_timer_running = false;
++      spin_unlock_bh(&dp->reo_cmd_lock);
++
++      ath11k_dp_process_reo_status(ab);
++}
++
++void ath11k_dp_start_reo_status_timer(struct ath11k_base *ab)
++{
++      struct ath11k_dp *dp = &ab->dp;
++
++      if (!ab->hw_params.reo_status_poll)
++              return;
++
++      spin_lock_bh(&dp->reo_cmd_lock);
++      if (dp->reo_status_timer_running) {
++              spin_unlock_bh(&dp->reo_cmd_lock);
++              return;
++      }
++      dp->reo_status_timer_running = true;
++      spin_unlock_bh(&dp->reo_cmd_lock);
++
++      mod_timer(&dp->reo_status_timer, jiffies +
++                msecs_to_jiffies(ATH11K_REO_STATUS_POLL_TIMEOUT_MS));
++}
++
++static void ath11k_dp_stop_reo_status_timer(struct ath11k_base *ab)
++{
++      struct ath11k_dp *dp = &ab->dp;
++
++      if (!ab->hw_params.reo_status_poll)
++              return;
++
++      del_timer_sync(&dp->reo_status_timer);
++      dp->reo_status_timer_running = false;
++}
++
++static void ath11k_dp_init_reo_status_timer(struct ath11k_base *ab)
++{
++      struct ath11k_dp *dp = &ab->dp;
++
++      if (!ab->hw_params.reo_status_poll)
++              return;
++
++      timer_setup(&dp->reo_status_timer,
++                  ath11k_dp_handle_reo_status_timer, 0);
++}
++
+ static void ath11k_dp_srng_common_cleanup(struct ath11k_base *ab)
+ {
+       struct ath11k_dp *dp = &ab->dp;
+       int i;
+       ath11k_dp_stop_shadow_timers(ab);
++      ath11k_dp_stop_reo_status_timer(ab);
+       ath11k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring);
+       ath11k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring);
+       ath11k_dp_srng_cleanup(ab, &dp->tcl_status_ring);
+@@ -388,6 +442,8 @@ static int ath11k_dp_srng_common_setup(s
+       int i, ret;
+       u8 tcl_num, wbm_num;
++      ath11k_dp_init_reo_status_timer(ab);
++
+       ret = ath11k_dp_srng_setup(ab, &dp->wbm_desc_rel_ring,
+                                  HAL_SW2WBM_RELEASE, 0, 0,
+                                  DP_WBM_RELEASE_RING_SIZE);
+--- a/drivers/net/wireless/ath/ath11k/dp.h
++++ b/drivers/net/wireless/ath/ath11k/dp.h
+@@ -44,6 +44,8 @@ struct dp_rx_tid {
+ #define DP_MON_PURGE_TIMEOUT_MS     100
+ #define DP_MON_SERVICE_BUDGET       128
++#define ATH11K_REO_STATUS_POLL_TIMEOUT_MS 10
++
+ struct dp_reo_cache_flush_elem {
+       struct list_head list;
+       struct dp_rx_tid data;
+@@ -286,6 +288,10 @@ struct ath11k_dp {
+       spinlock_t reo_cmd_lock;
+       struct ath11k_hp_update_timer reo_cmd_timer;
+       struct ath11k_hp_update_timer tx_ring_timer[DP_TCL_NUM_RING_MAX];
++
++      /* reo status timer and flags */
++      struct timer_list reo_status_timer;
++      bool reo_status_timer_running;
+ };
+ /* HTT definitions */
+@@ -1712,5 +1718,6 @@ void ath11k_dp_shadow_init_timer(struct
+                                struct ath11k_hp_update_timer *update_timer,
+                                u32 interval, u32 ring_id);
+ void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab);
++void ath11k_dp_start_reo_status_timer(struct ath11k_base *ab);
+ #endif
+--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
+@@ -787,6 +787,10 @@ int ath11k_dp_tx_send_reo_cmd(struct ath
+       if (cmd_num == 0)
+               return -EINVAL;
++      /* Trigger reo status polling if required */
++      if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
++              ath11k_dp_start_reo_status_timer(ab);
++
+       if (!cb)
+               return 0;
+--- a/drivers/net/wireless/ath/ath11k/hw.h
++++ b/drivers/net/wireless/ath/ath11k/hw.h
+@@ -232,6 +232,7 @@ struct ath11k_hw_params {
+       bool smp2p_wow_exit;
+       bool support_fw_mac_sequence;
+       bool support_dual_stations;
++      bool reo_status_poll;
+ };
+ struct ath11k_hw_ops {