diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/interrupt.c')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/interrupt.c | 225 |
1 files changed, 204 insertions, 21 deletions
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 84e9840c1752..d7e112da6a8d 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -44,6 +44,8 @@ (~(BIT_DMA_EP_RX_ICR_RX_HTRSH))) #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) +#define WIL6210_IMC_TX_EDMA BIT_TX_STATUS_IRQ +#define WIL6210_IMC_RX_EDMA BIT_RX_STATUS_IRQ #define WIL6210_IMC_MISC_NO_HALP (ISR_MISC_FW_READY | \ ISR_MISC_MBOX_EVT | \ ISR_MISC_FW_ERROR) @@ -87,12 +89,24 @@ static void wil6210_mask_irq_tx(struct wil6210_priv *wil) WIL6210_IRQ_DISABLE); } +static void wil6210_mask_irq_tx_edma(struct wil6210_priv *wil) +{ + wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); +} + static void wil6210_mask_irq_rx(struct wil6210_priv *wil) { wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS), WIL6210_IRQ_DISABLE); } +static void wil6210_mask_irq_rx_edma(struct wil6210_priv *wil) +{ + wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); +} + static void wil6210_mask_irq_misc(struct wil6210_priv *wil, bool mask_halp) { wil_dbg_irq(wil, "mask_irq_misc: mask_halp(%s)\n", @@ -125,6 +139,12 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil) WIL6210_IMC_TX); } +void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil) +{ + wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_TX_EDMA); +} + void wil6210_unmask_irq_rx(struct wil6210_priv *wil) { bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0; @@ -133,6 +153,12 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil) unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH); } +void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil) +{ + wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_RX_EDMA); +} + static void wil6210_unmask_irq_misc(struct wil6210_priv *wil, bool unmask_halp) { wil_dbg_irq(wil, "unmask_irq_misc: unmask_halp(%s)\n", @@ -164,7 +190,9 @@ 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); wil6210_mask_irq_rx(wil); + wil6210_mask_irq_rx_edma(wil); wil6210_mask_irq_misc(wil, true); wil6210_mask_irq_pseudo(wil); } @@ -179,13 +207,43 @@ void wil_unmask_irq(struct wil6210_priv *wil) 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), + WIL_ICR_ICC_VALUE); + wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); wil6210_unmask_irq_pseudo(wil); - wil6210_unmask_irq_tx(wil); - wil6210_unmask_irq_rx(wil); + if (wil->use_enhanced_dma_hw) { + wil6210_unmask_irq_tx_edma(wil); + wil6210_unmask_irq_rx_edma(wil); + } else { + wil6210_unmask_irq_tx(wil); + wil6210_unmask_irq_rx(wil); + } wil6210_unmask_irq_misc(wil, true); } +void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil) +{ + u32 moderation; + + wil_s(wil, RGF_INT_GEN_IDLE_TIME_LIMIT, WIL_EDMA_IDLE_TIME_LIMIT_USEC); + + wil_s(wil, RGF_INT_GEN_TIME_UNIT_LIMIT, WIL_EDMA_TIME_UNIT_CLK_CYCLES); + + /* Update RX and TX moderation */ + moderation = wil->rx_max_burst_duration | + (WIL_EDMA_AGG_WATERMARK << WIL_EDMA_AGG_WATERMARK_POS); + wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_0, moderation); + wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_1, moderation); + + /* Treat special events as regular + * (set bit 0 to 0x1 and clear bits 1-8) + */ + wil_c(wil, RGF_INT_COUNT_ON_SPECIAL_EVT, 0x1FE); + wil_s(wil, RGF_INT_COUNT_ON_SPECIAL_EVT, 0x1); +} + void wil_configure_interrupt_moderation(struct wil6210_priv *wil) { struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; @@ -294,6 +352,97 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) return IRQ_HANDLED; } +static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie) +{ + struct wil6210_priv *wil = cookie; + u32 isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + bool need_unmask = true; + + trace_wil6210_irq_rx(isr); + wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); + + if (unlikely(!isr)) { + wil_err(wil, "spurious IRQ: RX\n"); + return IRQ_NONE; + } + + wil6210_mask_irq_rx_edma(wil); + + if (likely(isr & BIT_RX_STATUS_IRQ)) { + wil_dbg_irq(wil, "RX status ring\n"); + isr &= ~BIT_RX_STATUS_IRQ; + if (likely(test_bit(wil_status_fwready, wil->status))) { + if (likely(test_bit(wil_status_napi_en, wil->status))) { + wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); + need_unmask = false; + napi_schedule(&wil->napi_rx); + } else { + wil_err(wil, + "Got Rx interrupt while stopping interface\n"); + } + } else { + wil_err(wil, "Got Rx interrupt while in reset\n"); + } + } + + if (unlikely(isr)) + wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); + + /* Rx IRQ will be enabled when NAPI processing finished */ + + atomic_inc(&wil->isr_count_rx); + + if (unlikely(need_unmask)) + wil6210_unmask_irq_rx_edma(wil); + + return IRQ_HANDLED; +} + +static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie) +{ + struct wil6210_priv *wil = cookie; + u32 isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + bool need_unmask = true; + + trace_wil6210_irq_tx(isr); + wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); + + if (unlikely(!isr)) { + wil_err(wil, "spurious IRQ: TX\n"); + return IRQ_NONE; + } + + wil6210_mask_irq_tx_edma(wil); + + if (likely(isr & BIT_TX_STATUS_IRQ)) { + wil_dbg_irq(wil, "TX status ring\n"); + isr &= ~BIT_TX_STATUS_IRQ; + if (likely(test_bit(wil_status_fwready, wil->status))) { + wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); + need_unmask = false; + napi_schedule(&wil->napi_tx); + } else { + wil_err(wil, "Got Tx status ring IRQ while in reset\n"); + } + } + + if (unlikely(isr)) + wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); + + /* Tx IRQ will be enabled when NAPI processing finished */ + + atomic_inc(&wil->isr_count_tx); + + if (unlikely(need_unmask)) + wil6210_unmask_irq_tx_edma(wil); + + return IRQ_HANDLED; +} + static irqreturn_t wil6210_irq_tx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -510,30 +659,53 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) */ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) { + u32 icm_rx, icr_rx, imv_rx; + u32 icm_tx, icr_tx, imv_tx; + u32 icm_misc, icr_misc, imv_misc; + if (!test_bit(wil_status_irqen, wil->status)) { - u32 icm_rx = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, ICM)); - u32 icr_rx = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, ICR)); - u32 imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR + + if (wil->use_enhanced_dma_hw) { + icm_rx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICM)); + icr_rx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + imv_rx = wil_r(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMV)); - u32 icm_tx = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, ICM)); - u32 icr_tx = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, ICR)); - u32 imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR + + icm_tx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICM)); + icr_tx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + imv_tx = wil_r(wil, RGF_INT_GEN_TX_ICR + + offsetof(struct RGF_ICR, IMV)); + } else { + icm_rx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_RX_ICR) + + offsetof(struct RGF_ICR, ICM)); + icr_rx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMV)); - u32 icm_misc = wil_ioread32_and_clear(wil->csr + + icm_tx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_TX_ICR) + + offsetof(struct RGF_ICR, ICM)); + icr_tx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR + + offsetof(struct RGF_ICR, IMV)); + } + icm_misc = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICM)); - u32 icr_misc = wil_ioread32_and_clear(wil->csr + + icr_misc = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); - u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR + + imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMV)); /* HALP interrupt can be unmasked when misc interrupts are @@ -592,11 +764,11 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) * voting for wake thread - need at least 1 vote */ if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) && - (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) + (wil->txrx_ops.irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) rc = IRQ_WAKE_THREAD; if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) && - (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) + (wil->txrx_ops.irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) rc = IRQ_WAKE_THREAD; if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) && @@ -624,6 +796,10 @@ 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)); wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); wmb(); /* make sure write completed */ @@ -652,6 +828,13 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi) wil_dbg_misc(wil, "init_irq: %s\n", use_msi ? "MSI" : "INTx"); + if (wil->use_enhanced_dma_hw) { + wil->txrx_ops.irq_tx = wil6210_irq_tx_edma; + wil->txrx_ops.irq_rx = wil6210_irq_rx_edma; + } else { + wil->txrx_ops.irq_tx = wil6210_irq_tx; + wil->txrx_ops.irq_rx = wil6210_irq_rx; + } rc = request_threaded_irq(irq, wil6210_hardirq, wil6210_thread_irq, use_msi ? 0 : IRQF_SHARED, |