summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/wil6210/interrupt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/interrupt.c')
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c75
1 files changed, 48 insertions, 27 deletions
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 67f1002a03a1..4bcbd6297b3e 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -36,7 +36,8 @@
*/
#define WIL6210_IRQ_DISABLE (0xFFFFFFFFUL)
-#define WIL6210_IMC_RX BIT_DMA_EP_RX_ICR_RX_DONE
+#define WIL6210_IMC_RX (BIT_DMA_EP_RX_ICR_RX_DONE | \
+ 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_MISC (ISR_MISC_FW_READY | \
@@ -135,7 +136,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
}
-void wil6210_disable_irq(struct wil6210_priv *wil)
+void wil_mask_irq(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@@ -145,7 +146,7 @@ void wil6210_disable_irq(struct wil6210_priv *wil)
wil6210_mask_irq_pseudo(wil);
}
-void wil6210_enable_irq(struct wil6210_priv *wil)
+void wil_unmask_irq(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
@@ -157,17 +158,7 @@ void wil6210_enable_irq(struct wil6210_priv *wil)
offsetof(struct RGF_ICR, ICC));
/* interrupt moderation parameters */
- if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
- /* disable interrupt moderation for monitor
- * to get better timestamp precision
- */
- iowrite32(0, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
- } else {
- iowrite32(WIL6210_ITR_TRSH,
- wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
- iowrite32(BIT_DMA_ITR_CNT_CRL_EN,
- wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
- }
+ wil_set_itr_trsh(wil);
wil6210_unmask_irq_pseudo(wil);
wil6210_unmask_irq_tx(wil);
@@ -181,6 +172,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
u32 isr = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_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);
@@ -192,12 +184,29 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
wil6210_mask_irq_rx(wil);
- if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
+ /* RX_DONE and RX_HTRSH interrupts are the same if interrupt
+ * moderation is not used. Interrupt moderation may cause RX
+ * buffer overflow while RX_DONE is delayed. The required
+ * action is always the same - should empty the accumulated
+ * packets from the RX ring.
+ */
+ if (isr & (BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH)) {
wil_dbg_irq(wil, "RX done\n");
- isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
+
+ if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH)
+ wil_err_ratelimited(wil, "Received \"Rx buffer is in risk "
+ "of overflow\" interrupt\n");
+
+ isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH);
if (test_bit(wil_status_reset_done, &wil->status)) {
- wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
- napi_schedule(&wil->napi_rx);
+ if (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");
}
@@ -209,6 +218,10 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
/* Rx IRQ will be enabled when NAPI processing finished */
atomic_inc(&wil->isr_count_rx);
+
+ if (unlikely(need_unmask))
+ wil6210_unmask_irq_rx(wil);
+
return IRQ_HANDLED;
}
@@ -218,6 +231,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
u32 isr = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_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);
@@ -236,6 +250,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
isr &= ~(BIT(25) - 1UL);
if (test_bit(wil_status_reset_done, &wil->status)) {
wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
+ need_unmask = false;
napi_schedule(&wil->napi_tx);
} else {
wil_err(wil, "Got Tx interrupt while in reset\n");
@@ -248,6 +263,10 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
/* Tx IRQ will be enabled when NAPI processing finished */
atomic_inc(&wil->isr_count_tx);
+
+ if (unlikely(need_unmask))
+ wil6210_unmask_irq_tx(wil);
+
return IRQ_HANDLED;
}
@@ -506,7 +525,8 @@ free0:
return rc;
}
-/* can't use wil_ioread32_and_clear because ICC value is not ser yet */
+
+/* can't use wil_ioread32_and_clear because ICC value is not set yet */
static inline void wil_clear32(void __iomem *addr)
{
u32 x = ioread32(addr);
@@ -522,11 +542,15 @@ void wil6210_clear_irq(struct wil6210_priv *wil)
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 */
}
int wil6210_init_irq(struct wil6210_priv *wil, int irq)
{
int rc;
+
+ wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi);
+
if (wil->n_msi == 3)
rc = wil6210_request_3msi(wil, irq);
else
@@ -534,17 +558,14 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq)
wil6210_thread_irq,
wil->n_msi ? 0 : IRQF_SHARED,
WIL_NAME, wil);
- if (rc)
- return rc;
-
- wil6210_enable_irq(wil);
-
- return 0;
+ return rc;
}
void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
{
- wil6210_disable_irq(wil);
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ wil_mask_irq(wil);
free_irq(irq, wil);
if (wil->n_msi == 3) {
free_irq(irq + 1, wil);