]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Jan 2024 17:42:03 +0000 (18:42 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Jan 2024 17:42:03 +0000 (18:42 +0100)
added patches:
ath10k-add-interrupt-summary-based-ce-processing.patch
ath10k-get-rid-of-per_ce_irq-hw-param.patch
ath10k-keep-track-of-which-interrupts-fired-don-t-poll-them.patch
ath10k-wait-until-copy-complete-is-actually-done-before-completing.patch

queue-5.4/ath10k-add-interrupt-summary-based-ce-processing.patch [new file with mode: 0644]
queue-5.4/ath10k-get-rid-of-per_ce_irq-hw-param.patch [new file with mode: 0644]
queue-5.4/ath10k-keep-track-of-which-interrupts-fired-don-t-poll-them.patch [new file with mode: 0644]
queue-5.4/ath10k-wait-until-copy-complete-is-actually-done-before-completing.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/ath10k-add-interrupt-summary-based-ce-processing.patch b/queue-5.4/ath10k-add-interrupt-summary-based-ce-processing.patch
new file mode 100644 (file)
index 0000000..aea48af
--- /dev/null
@@ -0,0 +1,170 @@
+From stable+bounces-10188-greg=kroah.com@vger.kernel.org Mon Jan  8 16:37:56 2024
+From: Amit Pundir <amit.pundir@linaro.org>
+Date: Mon,  8 Jan 2024 21:07:35 +0530
+Subject: ath10k: Add interrupt summary based CE processing
+To: Greg KH <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>, Douglas Anderson <dianders@chromium.org>, Rakesh Pillai <pillair@codeaurora.org>
+Cc: Yongqin Liu <yongqin.liu@linaro.org>, Stable <stable@vger.kernel.org>, Kalle Valo <kvalo@codeaurora.org>
+Message-ID: <20240108153737.3538218-3-amit.pundir@linaro.org>
+
+From: Rakesh Pillai <pillair@codeaurora.org>
+
+[ Upstream commit b92aba35d39d10d8a6bdf2495172fd490c598b4a ]
+
+Currently the NAPI processing loops through all
+the copy engines and processes a particular copy
+engine is the copy completion is set for that copy
+engine. The host driver is not supposed to access
+any copy engine register after clearing the interrupt
+status register.
+
+This might result in kernel crash like the one below
+[ 1159.220143] Call trace:
+[ 1159.220170]  ath10k_snoc_read32+0x20/0x40 [ath10k_snoc]
+[ 1159.220193]  ath10k_ce_per_engine_service_any+0x78/0x130 [ath10k_core]
+[ 1159.220203]  ath10k_snoc_napi_poll+0x38/0x8c [ath10k_snoc]
+[ 1159.220270]  net_rx_action+0x100/0x3b0
+[ 1159.220312]  __do_softirq+0x164/0x30c
+[ 1159.220345]  run_ksoftirqd+0x2c/0x64
+[ 1159.220380]  smpboot_thread_fn+0x1b0/0x288
+[ 1159.220405]  kthread+0x11c/0x12c
+[ 1159.220423]  ret_from_fork+0x10/0x18
+
+To avoid such a scenario, we generate an interrupt
+summary by reading the copy completion for all the
+copy engine before actually processing any of them.
+This will avoid reading the interrupt status register
+for any CE after the interrupt status is cleared.
+
+Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1
+
+Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
+Reviewed-by: Douglas Anderson <dianders@chromium.org>
+Tested-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/1593193967-29897-1-git-send-email-pillair@codeaurora.org
+Stable-dep-of: 170c75d43a77 ("ath10k: Don't touch the CE interrupt registers after power up")
+Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/ath/ath10k/ce.c |   63 +++++++++++++++++++++--------------
+ drivers/net/wireless/ath/ath10k/ce.h |    5 +-
+ 2 files changed, 42 insertions(+), 26 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath10k/ce.c
++++ b/drivers/net/wireless/ath/ath10k/ce.c
+@@ -481,15 +481,38 @@ static inline void ath10k_ce_engine_int_
+       ath10k_ce_write32(ar, ce_ctrl_addr + wm_regs->addr, mask);
+ }
+-static inline bool ath10k_ce_engine_int_status_check(struct ath10k *ar,
+-                                                   u32 ce_ctrl_addr,
+-                                                   unsigned int mask)
++static bool ath10k_ce_engine_int_status_check(struct ath10k *ar, u32 ce_ctrl_addr,
++                                            unsigned int mask)
+ {
+       struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs;
+       return ath10k_ce_read32(ar, ce_ctrl_addr + wm_regs->addr) & mask;
+ }
++u32 ath10k_ce_gen_interrupt_summary(struct ath10k *ar)
++{
++      struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs;
++      struct ath10k_ce_pipe *ce_state;
++      struct ath10k_ce *ce;
++      u32 irq_summary = 0;
++      u32 ctrl_addr;
++      u32 ce_id;
++
++      ce = ath10k_ce_priv(ar);
++
++      for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
++              ce_state = &ce->ce_states[ce_id];
++              ctrl_addr = ce_state->ctrl_addr;
++              if (ath10k_ce_engine_int_status_check(ar, ctrl_addr,
++                                                    wm_regs->cc_mask)) {
++                      irq_summary |= BIT(ce_id);
++              }
++      }
++
++      return irq_summary;
++}
++EXPORT_SYMBOL(ath10k_ce_gen_interrupt_summary);
++
+ /*
+  * Guts of ath10k_ce_send.
+  * The caller takes responsibility for any needed locking.
+@@ -1308,32 +1331,24 @@ void ath10k_ce_per_engine_service(struct
+       struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs;
+       u32 ctrl_addr = ce_state->ctrl_addr;
+-      spin_lock_bh(&ce->ce_lock);
+-
+-      if (ath10k_ce_engine_int_status_check(ar, ctrl_addr,
+-                                            wm_regs->cc_mask)) {
+-              /* Clear before handling */
+-              ath10k_ce_engine_int_status_clear(ar, ctrl_addr,
+-                                                wm_regs->cc_mask);
+-
+-              spin_unlock_bh(&ce->ce_lock);
+-
+-              if (ce_state->recv_cb)
+-                      ce_state->recv_cb(ce_state);
+-
+-              if (ce_state->send_cb)
+-                      ce_state->send_cb(ce_state);
+-
+-              spin_lock_bh(&ce->ce_lock);
+-      }
+-
+       /*
++       * Clear before handling
++       *
+        * Misc CE interrupts are not being handled, but still need
+        * to be cleared.
++       *
++       * NOTE: When the last copy engine interrupt is cleared the
++       * hardware will go to sleep.  Once this happens any access to
++       * the CE registers can cause a hardware fault.
+        */
+-      ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->wm_mask);
++      ath10k_ce_engine_int_status_clear(ar, ctrl_addr,
++                                        wm_regs->cc_mask | wm_regs->wm_mask);
+-      spin_unlock_bh(&ce->ce_lock);
++      if (ce_state->recv_cb)
++              ce_state->recv_cb(ce_state);
++
++      if (ce_state->send_cb)
++              ce_state->send_cb(ce_state);
+ }
+ EXPORT_SYMBOL(ath10k_ce_per_engine_service);
+--- a/drivers/net/wireless/ath/ath10k/ce.h
++++ b/drivers/net/wireless/ath/ath10k/ce.h
+@@ -259,6 +259,8 @@ int ath10k_ce_disable_interrupts(struct
+ void ath10k_ce_enable_interrupts(struct ath10k *ar);
+ void ath10k_ce_dump_registers(struct ath10k *ar,
+                             struct ath10k_fw_crash_data *crash_data);
++
++u32 ath10k_ce_gen_interrupt_summary(struct ath10k *ar);
+ void ath10k_ce_alloc_rri(struct ath10k *ar);
+ void ath10k_ce_free_rri(struct ath10k *ar);
+@@ -369,7 +371,6 @@ static inline u32 ath10k_ce_base_address
+       (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \
+               CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB)
+ #define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS                  0x0000
+-#define CE_INTERRUPT_SUMMARY          (GENMASK(CE_COUNT_MAX - 1, 0))
+ static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar)
+ {
+@@ -380,7 +381,7 @@ static inline u32 ath10k_ce_interrupt_su
+                       ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS +
+                       CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS));
+       else
+-              return CE_INTERRUPT_SUMMARY;
++              return ath10k_ce_gen_interrupt_summary(ar);
+ }
+ /* Host software's Copy Engine configuration. */
diff --git a/queue-5.4/ath10k-get-rid-of-per_ce_irq-hw-param.patch b/queue-5.4/ath10k-get-rid-of-per_ce_irq-hw-param.patch
new file mode 100644 (file)
index 0000000..8c1d6ba
--- /dev/null
@@ -0,0 +1,146 @@
+From stable+bounces-10191-greg=kroah.com@vger.kernel.org Mon Jan  8 16:37:58 2024
+From: Amit Pundir <amit.pundir@linaro.org>
+Date: Mon,  8 Jan 2024 21:07:37 +0530
+Subject: ath10k: Get rid of "per_ce_irq" hw param
+To: Greg KH <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>, Douglas Anderson <dianders@chromium.org>, Rakesh Pillai <pillair@codeaurora.org>
+Cc: Yongqin Liu <yongqin.liu@linaro.org>, Stable <stable@vger.kernel.org>, Brian Norris <briannorris@chromium.org>, Kalle Valo <kvalo@codeaurora.org>
+Message-ID: <20240108153737.3538218-5-amit.pundir@linaro.org>
+
+From: Douglas Anderson <dianders@chromium.org>
+
+[ Upstream commit 7f86551665121931ecd6d327e019e7a69782bfcd ]
+
+As of the patch ("ath10k: Keep track of which interrupts fired, don't
+poll them") we now have no users of this hardware parameter.  Remove
+it.
+
+Suggested-by: Brian Norris <briannorris@chromium.org>
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/20200709082024.v2.2.I083faa4e62e69f863311c89ae5eb28ec5a229b70@changeid
+Stable-dep-of: 170c75d43a77 ("ath10k: Don't touch the CE interrupt registers after power up")
+Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/ath/ath10k/core.c |   13 -------------
+ drivers/net/wireless/ath/ath10k/hw.h   |    3 ---
+ 2 files changed, 16 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -118,7 +118,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -154,7 +153,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -217,7 +215,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -252,7 +249,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -287,7 +283,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -325,7 +320,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -366,7 +360,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -414,7 +407,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -459,7 +451,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -494,7 +485,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -531,7 +521,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -573,7 +562,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = 0x20,
+               .target_64bit = false,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
+-              .per_ce_irq = false,
+               .shadow_reg_support = false,
+               .rri_on_ddr = false,
+               .hw_filter_reset_required = true,
+@@ -601,7 +589,6 @@ static const struct ath10k_hw_params ath
+               .num_wds_entries = TARGET_HL_TLV_NUM_WDS_ENTRIES,
+               .target_64bit = true,
+               .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC,
+-              .per_ce_irq = true,
+               .shadow_reg_support = true,
+               .rri_on_ddr = true,
+               .hw_filter_reset_required = false,
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -590,9 +590,6 @@ struct ath10k_hw_params {
+       /* Target rx ring fill level */
+       u32 rx_ring_fill_level;
+-      /* target supporting per ce IRQ */
+-      bool per_ce_irq;
+-
+       /* target supporting shadow register for ce write */
+       bool shadow_reg_support;
diff --git a/queue-5.4/ath10k-keep-track-of-which-interrupts-fired-don-t-poll-them.patch b/queue-5.4/ath10k-keep-track-of-which-interrupts-fired-don-t-poll-them.patch
new file mode 100644 (file)
index 0000000..f09d0ee
--- /dev/null
@@ -0,0 +1,268 @@
+From stable+bounces-10189-greg=kroah.com@vger.kernel.org Mon Jan  8 16:37:55 2024
+From: Amit Pundir <amit.pundir@linaro.org>
+Date: Mon,  8 Jan 2024 21:07:36 +0530
+Subject: ath10k: Keep track of which interrupts fired, don't poll them
+To: Greg KH <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>, Douglas Anderson <dianders@chromium.org>, Rakesh Pillai <pillair@codeaurora.org>
+Cc: Yongqin Liu <yongqin.liu@linaro.org>, Stable <stable@vger.kernel.org>, Brian Norris <briannorris@chromium.org>, Kalle Valo <kvalo@codeaurora.org>
+Message-ID: <20240108153737.3538218-4-amit.pundir@linaro.org>
+
+From: Douglas Anderson <dianders@chromium.org>
+
+[ Upstream commit d66d24ac300cf41c6b88367fc9b4b6348679273d ]
+
+If we have a per CE (Copy Engine) IRQ then we have no summary
+register.  Right now the code generates a summary register by
+iterating over all copy engines and seeing if they have an interrupt
+pending.
+
+This has a problem.  Specifically if _none_ if the Copy Engines have
+an interrupt pending then they might go into low power mode and
+reading from their address space will cause a full system crash.  This
+was seen to happen when two interrupts went off at nearly the same
+time.  Both were handled by a single call of ath10k_snoc_napi_poll()
+but, because there were two interrupts handled and thus two calls to
+napi_schedule() there was still a second call to
+ath10k_snoc_napi_poll() which ran with no interrupts pending.
+
+Instead of iterating over all the copy engines, let's just keep track
+of the IRQs that fire.  Then we can effectively generate our own
+summary without ever needing to read the Copy Engines.
+
+Tested-on: WCN3990 SNOC WLAN.HL.3.2.2-00490-QCAHLSWMTPL-1
+
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Reviewed-by: Rakesh Pillai <pillair@codeaurora.org>
+Reviewed-by: Brian Norris <briannorris@chromium.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/20200709082024.v2.1.I4d2f85ffa06f38532631e864a3125691ef5ffe06@changeid
+Stable-dep-of: 170c75d43a77 ("ath10k: Don't touch the CE interrupt registers after power up")
+Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/ath/ath10k/ce.c   |   84 ++++++++++++---------------------
+ drivers/net/wireless/ath/ath10k/ce.h   |   14 ++---
+ drivers/net/wireless/ath/ath10k/snoc.c |   19 +++++--
+ drivers/net/wireless/ath/ath10k/snoc.h |    1 
+ 4 files changed, 52 insertions(+), 66 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath10k/ce.c
++++ b/drivers/net/wireless/ath/ath10k/ce.c
+@@ -481,38 +481,6 @@ static inline void ath10k_ce_engine_int_
+       ath10k_ce_write32(ar, ce_ctrl_addr + wm_regs->addr, mask);
+ }
+-static bool ath10k_ce_engine_int_status_check(struct ath10k *ar, u32 ce_ctrl_addr,
+-                                            unsigned int mask)
+-{
+-      struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs;
+-
+-      return ath10k_ce_read32(ar, ce_ctrl_addr + wm_regs->addr) & mask;
+-}
+-
+-u32 ath10k_ce_gen_interrupt_summary(struct ath10k *ar)
+-{
+-      struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs;
+-      struct ath10k_ce_pipe *ce_state;
+-      struct ath10k_ce *ce;
+-      u32 irq_summary = 0;
+-      u32 ctrl_addr;
+-      u32 ce_id;
+-
+-      ce = ath10k_ce_priv(ar);
+-
+-      for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
+-              ce_state = &ce->ce_states[ce_id];
+-              ctrl_addr = ce_state->ctrl_addr;
+-              if (ath10k_ce_engine_int_status_check(ar, ctrl_addr,
+-                                                    wm_regs->cc_mask)) {
+-                      irq_summary |= BIT(ce_id);
+-              }
+-      }
+-
+-      return irq_summary;
+-}
+-EXPORT_SYMBOL(ath10k_ce_gen_interrupt_summary);
+-
+ /*
+  * Guts of ath10k_ce_send.
+  * The caller takes responsibility for any needed locking.
+@@ -1399,45 +1367,55 @@ static void ath10k_ce_per_engine_handler
+       ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
+ }
+-int ath10k_ce_disable_interrupts(struct ath10k *ar)
++void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id)
+ {
+       struct ath10k_ce *ce = ath10k_ce_priv(ar);
+       struct ath10k_ce_pipe *ce_state;
+       u32 ctrl_addr;
+-      int ce_id;
+-      for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
+-              ce_state  = &ce->ce_states[ce_id];
+-              if (ce_state->attr_flags & CE_ATTR_POLL)
+-                      continue;
++      ce_state  = &ce->ce_states[ce_id];
++      if (ce_state->attr_flags & CE_ATTR_POLL)
++              return;
+-              ctrl_addr = ath10k_ce_base_address(ar, ce_id);
++      ctrl_addr = ath10k_ce_base_address(ar, ce_id);
+-              ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
+-              ath10k_ce_error_intr_disable(ar, ctrl_addr);
+-              ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
+-      }
++      ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
++      ath10k_ce_error_intr_disable(ar, ctrl_addr);
++      ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
++}
++EXPORT_SYMBOL(ath10k_ce_disable_interrupt);
+-      return 0;
++void ath10k_ce_disable_interrupts(struct ath10k *ar)
++{
++      int ce_id;
++
++      for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
++              ath10k_ce_disable_interrupt(ar, ce_id);
+ }
+ EXPORT_SYMBOL(ath10k_ce_disable_interrupts);
+-void ath10k_ce_enable_interrupts(struct ath10k *ar)
++void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id)
+ {
+       struct ath10k_ce *ce = ath10k_ce_priv(ar);
+-      int ce_id;
+       struct ath10k_ce_pipe *ce_state;
++      ce_state  = &ce->ce_states[ce_id];
++      if (ce_state->attr_flags & CE_ATTR_POLL)
++              return;
++
++      ath10k_ce_per_engine_handler_adjust(ce_state);
++}
++EXPORT_SYMBOL(ath10k_ce_enable_interrupt);
++
++void ath10k_ce_enable_interrupts(struct ath10k *ar)
++{
++      int ce_id;
++
+       /* Enable interrupts for copy engine that
+        * are not using polling mode.
+        */
+-      for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
+-              ce_state  = &ce->ce_states[ce_id];
+-              if (ce_state->attr_flags & CE_ATTR_POLL)
+-                      continue;
+-
+-              ath10k_ce_per_engine_handler_adjust(ce_state);
+-      }
++      for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
++              ath10k_ce_enable_interrupt(ar, ce_id);
+ }
+ EXPORT_SYMBOL(ath10k_ce_enable_interrupts);
+--- a/drivers/net/wireless/ath/ath10k/ce.h
++++ b/drivers/net/wireless/ath/ath10k/ce.h
+@@ -255,12 +255,13 @@ int ath10k_ce_cancel_send_next(struct at
+ /*==================CE Interrupt Handlers====================*/
+ void ath10k_ce_per_engine_service_any(struct ath10k *ar);
+ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
+-int ath10k_ce_disable_interrupts(struct ath10k *ar);
++void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id);
++void ath10k_ce_disable_interrupts(struct ath10k *ar);
++void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id);
+ void ath10k_ce_enable_interrupts(struct ath10k *ar);
+ void ath10k_ce_dump_registers(struct ath10k *ar,
+                             struct ath10k_fw_crash_data *crash_data);
+-u32 ath10k_ce_gen_interrupt_summary(struct ath10k *ar);
+ void ath10k_ce_alloc_rri(struct ath10k *ar);
+ void ath10k_ce_free_rri(struct ath10k *ar);
+@@ -376,12 +377,9 @@ static inline u32 ath10k_ce_interrupt_su
+ {
+       struct ath10k_ce *ce = ath10k_ce_priv(ar);
+-      if (!ar->hw_params.per_ce_irq)
+-              return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(
+-                      ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS +
+-                      CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS));
+-      else
+-              return ath10k_ce_gen_interrupt_summary(ar);
++      return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(
++              ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS +
++              CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS));
+ }
+ /* Host software's Copy Engine configuration. */
+--- a/drivers/net/wireless/ath/ath10k/snoc.c
++++ b/drivers/net/wireless/ath/ath10k/snoc.c
+@@ -3,6 +3,7 @@
+  * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+  */
++#include <linux/bits.h>
+ #include <linux/clk.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -927,6 +928,7 @@ static int ath10k_snoc_hif_start(struct
+ {
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
++      bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);
+       napi_enable(&ar->napi);
+       ath10k_snoc_irq_enable(ar);
+       ath10k_snoc_rx_post(ar);
+@@ -1166,7 +1168,9 @@ static irqreturn_t ath10k_snoc_per_engin
+               return IRQ_HANDLED;
+       }
+-      ath10k_snoc_irq_disable(ar);
++      ath10k_ce_disable_interrupt(ar, ce_id);
++      set_bit(ce_id, ar_snoc->pending_ce_irqs);
++
+       napi_schedule(&ar->napi);
+       return IRQ_HANDLED;
+@@ -1175,20 +1179,25 @@ static irqreturn_t ath10k_snoc_per_engin
+ static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)
+ {
+       struct ath10k *ar = container_of(ctx, struct ath10k, napi);
++      struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+       int done = 0;
++      int ce_id;
+       if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
+               napi_complete(ctx);
+               return done;
+       }
+-      ath10k_ce_per_engine_service_any(ar);
++      for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
++              if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) {
++                      ath10k_ce_per_engine_service(ar, ce_id);
++                      ath10k_ce_enable_interrupt(ar, ce_id);
++              }
++
+       done = ath10k_htt_txrx_compl_task(ar, budget);
+-      if (done < budget) {
++      if (done < budget)
+               napi_complete(ctx);
+-              ath10k_snoc_irq_enable(ar);
+-      }
+       return done;
+ }
+--- a/drivers/net/wireless/ath/ath10k/snoc.h
++++ b/drivers/net/wireless/ath/ath10k/snoc.h
+@@ -81,6 +81,7 @@ struct ath10k_snoc {
+       struct ath10k_clk_info *clk;
+       struct ath10k_qmi *qmi;
+       unsigned long flags;
++      DECLARE_BITMAP(pending_ce_irqs, CE_COUNT_MAX);
+ };
+ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
diff --git a/queue-5.4/ath10k-wait-until-copy-complete-is-actually-done-before-completing.patch b/queue-5.4/ath10k-wait-until-copy-complete-is-actually-done-before-completing.patch
new file mode 100644 (file)
index 0000000..7ef8609
--- /dev/null
@@ -0,0 +1,98 @@
+From stable+bounces-10185-greg=kroah.com@vger.kernel.org Mon Jan  8 16:37:49 2024
+From: Amit Pundir <amit.pundir@linaro.org>
+Date: Mon,  8 Jan 2024 21:07:34 +0530
+Subject: ath10k: Wait until copy complete is actually done before completing
+To: Greg KH <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>, Douglas Anderson <dianders@chromium.org>, Rakesh Pillai <pillair@codeaurora.org>
+Cc: Yongqin Liu <yongqin.liu@linaro.org>, Stable <stable@vger.kernel.org>, Kalle Valo <kvalo@codeaurora.org>
+Message-ID: <20240108153737.3538218-2-amit.pundir@linaro.org>
+
+From: Douglas Anderson <dianders@chromium.org>
+
+[ Upstream commit 8f9ed93d09a97444733d492a3bbf66bcb786a777 ]
+
+On wcn3990 we have "per_ce_irq = true".  That makes the
+ath10k_ce_interrupt_summary() function always return 0xfff. The
+ath10k_ce_per_engine_service_any() function will see this and think
+that _all_ copy engines have an interrupt.  Without checking, the
+ath10k_ce_per_engine_service() assumes that if it's called that the
+"copy complete" (cc) interrupt fired.  This combination seems bad.
+
+Let's add a check to make sure that the "copy complete" interrupt
+actually fired in ath10k_ce_per_engine_service().
+
+This might fix a hard-to-reproduce failure where it appears that the
+copy complete handlers run before the copy is really complete.
+Specifically a symptom was that we were seeing this on a Qualcomm
+sc7180 board:
+  arm-smmu 15000000.iommu: Unhandled context fault:
+  fsr=0x402, iova=0x7fdd45780, fsynr=0x30003, cbfrsynra=0xc1, cb=10
+
+Even on platforms that don't have wcn3990 this still seems like it
+would be a sane thing to do.  Specifically the current IRQ handler
+comments indicate that there might be other misc interrupt sources
+firing that need to be cleared.  If one of those sources was the one
+that caused the IRQ handler to be called it would also be important to
+double-check that the interrupt we cared about actually fired.
+
+Tested-on: WCN3990 SNOC WLAN.HL.3.2.2-00490-QCAHLSWMTPL-1
+
+Signed-off-by: Douglas Anderson <dianders@chromium.org>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Link: https://lore.kernel.org/r/20200609082015.1.Ife398994e5a0a6830e4d4a16306ef36e0144e7ba@changeid
+Stable-dep-of: 170c75d43a77 ("ath10k: Don't touch the CE interrupt registers after power up")
+Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/ath/ath10k/ce.c |   30 +++++++++++++++++++++---------
+ 1 file changed, 21 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath10k/ce.c
++++ b/drivers/net/wireless/ath/ath10k/ce.c
+@@ -481,6 +481,15 @@ static inline void ath10k_ce_engine_int_
+       ath10k_ce_write32(ar, ce_ctrl_addr + wm_regs->addr, mask);
+ }
++static inline bool ath10k_ce_engine_int_status_check(struct ath10k *ar,
++                                                   u32 ce_ctrl_addr,
++                                                   unsigned int mask)
++{
++      struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs;
++
++      return ath10k_ce_read32(ar, ce_ctrl_addr + wm_regs->addr) & mask;
++}
++
+ /*
+  * Guts of ath10k_ce_send.
+  * The caller takes responsibility for any needed locking.
+@@ -1301,19 +1310,22 @@ void ath10k_ce_per_engine_service(struct
+       spin_lock_bh(&ce->ce_lock);
+-      /* Clear the copy-complete interrupts that will be handled here. */
+-      ath10k_ce_engine_int_status_clear(ar, ctrl_addr,
+-                                        wm_regs->cc_mask);
++      if (ath10k_ce_engine_int_status_check(ar, ctrl_addr,
++                                            wm_regs->cc_mask)) {
++              /* Clear before handling */
++              ath10k_ce_engine_int_status_clear(ar, ctrl_addr,
++                                                wm_regs->cc_mask);
+-      spin_unlock_bh(&ce->ce_lock);
++              spin_unlock_bh(&ce->ce_lock);
+-      if (ce_state->recv_cb)
+-              ce_state->recv_cb(ce_state);
++              if (ce_state->recv_cb)
++                      ce_state->recv_cb(ce_state);
+-      if (ce_state->send_cb)
+-              ce_state->send_cb(ce_state);
++              if (ce_state->send_cb)
++                      ce_state->send_cb(ce_state);
+-      spin_lock_bh(&ce->ce_lock);
++              spin_lock_bh(&ce->ce_lock);
++      }
+       /*
+        * Misc CE interrupts are not being handled, but still need
index 0d4e2cbda99d81f1d00848000253f6559cfb7be8..4df9b084a842eaedc72e5c159f7534a2ad96ba65 100644 (file)
@@ -25,3 +25,7 @@ mm-fix-unmap_mapping_range-high-bits-shift-bug.patch
 mmc-rpmb-fixes-pause-retune-on-all-rpmb-partitions.patch
 mmc-core-cancel-delayed-work-before-releasing-host.patch
 mmc-sdhci-sprd-fix-emmc-init-failure-after-hw-reset.patch
+ath10k-wait-until-copy-complete-is-actually-done-before-completing.patch
+ath10k-add-interrupt-summary-based-ce-processing.patch
+ath10k-keep-track-of-which-interrupts-fired-don-t-poll-them.patch
+ath10k-get-rid-of-per_ce_irq-hw-param.patch