From: Sebastian Gottschall s.gottschall@dd-wrt.com
[ Upstream commit 593963660919a97a4546acfd706dac93625724f5 ]
the wil6210 driver irq handling code is unconditionally writing edma irq registers which are supposed to be only used on Talyn chipsets. This however leade to a chipset hang on the older sparrow chipset generation and firmware will not even boot. Fix that by simply checking for edma support before handling these registers.
Tested on Netgear R9000
Signed-off-by: Sebastian Gottschall s.gottschall@dd-wrt.com Link: https://patch.msgid.link/20250304012131.25970-2-s.gottschall@dd-wrt.com Signed-off-by: Jeff Johnson jeff.johnson@oss.qualcomm.com Signed-off-by: Sasha Levin sashal@kernel.org ---
**YES**
This commit should be backported to stable kernel trees. Here's the extensive explanation:
## Analysis of the Commit
### 1. **The Bug Being Fixed** The commit fixes a critical hardware compatibility issue where the wil6210 driver unconditionally writes to EDMA (Enhanced DMA) interrupt registers that only exist on Talyn chipsets. When running on older Sparrow chipsets (which don't have these registers), this causes: - Chipset hang - Firmware boot failure - Complete device malfunction
### 2. **Code Changes Analysis**
The commit adds conditional checks for `wil->use_enhanced_dma_hw` before accessing EDMA-specific registers:
```c // In wil_mask_irq(): - wil6210_mask_irq_tx_edma(wil); + if (wil->use_enhanced_dma_hw) + wil6210_mask_irq_tx_edma(wil);
// In wil_unmask_irq(): - wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), - WIL_ICR_ICC_VALUE); + if (wil->use_enhanced_dma_hw) { + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + }
// In wil6210_clear_irq(): - wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) + - offsetof(struct RGF_ICR, ICR)); + if (wil->use_enhanced_dma_hw) { + wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + } ```
### 3. **Why This Qualifies for Stable Backport**
This commit meets all the criteria for stable tree backporting:
**a) Fixes a real bug affecting users:** - Users with Sparrow chipsets (like Netgear R9000) experience complete device failure - The bug prevents the device from functioning at all (firmware won't boot) - This is a regression that breaks existing hardware
**b) Small and contained fix:** - The fix is minimal - just adding conditional checks - Changes are limited to interrupt handling functions - No architectural changes or new features added
**c) Low risk of regression:** - The fix follows existing patterns in the code (other functions already check `use_enhanced_dma_hw`) - Only affects behavior on non-EDMA hardware (Sparrow) - EDMA hardware behavior remains unchanged
**d) Clear cause and effect:** - The problem is well-understood: accessing non-existent registers - The solution is straightforward: check hardware capability before accessing EDMA registers - The fix has been tested on affected hardware (Netgear R9000)
### 4. **Comparison with Similar Commits**
Looking at the provided similar commits: - **Similar Commit #1** (Backported: YES) fixed a Talyn reset flow issue - similar hardware-specific bug fix - This commit is even more critical as it fixes a complete device failure rather than just a reset issue
### 5. **Critical Nature of the Fix**
This is not just a minor bug - it's a complete breakage of Sparrow hardware support. Without this fix: - Sparrow chipsets cannot function at all - Users with devices like Netgear R9000 have non-functional WiFi - This represents a regression in hardware support
The fix is essential for maintaining hardware compatibility across different generations of the wil6210 chipset family.
drivers/net/wireless/ath/wil6210/interrupt.c | 26 ++++++++++++-------- 1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index b00a13d6d5307..35c5fda9f8105 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -190,9 +190,11 @@ void wil_mask_irq(struct wil6210_priv *wil) wil_dbg_irq(wil, "mask_irq\n");
wil6210_mask_irq_tx(wil); - wil6210_mask_irq_tx_edma(wil); + if (wil->use_enhanced_dma_hw) + wil6210_mask_irq_tx_edma(wil); wil6210_mask_irq_rx(wil); - wil6210_mask_irq_rx_edma(wil); + if (wil->use_enhanced_dma_hw) + wil6210_mask_irq_rx_edma(wil); wil6210_mask_irq_misc(wil, true); wil6210_mask_irq_pseudo(wil); } @@ -201,10 +203,12 @@ void wil_unmask_irq(struct wil6210_priv *wil) { wil_dbg_irq(wil, "unmask_irq\n");
- wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), - WIL_ICR_ICC_VALUE); - wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC), - WIL_ICR_ICC_VALUE); + if (wil->use_enhanced_dma_hw) { + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + } wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC), WIL_ICR_ICC_MISC_VALUE); wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, ICC), @@ -858,10 +862,12 @@ void wil6210_clear_irq(struct wil6210_priv *wil) offsetof(struct RGF_ICR, ICR)); wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICR)); - wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) + - offsetof(struct RGF_ICR, ICR)); - wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) + - offsetof(struct RGF_ICR, ICR)); + if (wil->use_enhanced_dma_hw) { + wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + } wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); wmb(); /* make sure write completed */