Commit 1e73eb62 authored by Juuso Oikarinen's avatar Juuso Oikarinen Committed by John W. Linville

wl1271: Implement looped IRQ handling

This patch implements looped IRQ handling. In essence, if a new interrupt is
asserted by the FW while the host is processing the previous one, the host
will directly proceed processing the new IRQ without leaving the handling
function.
Signed-off-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: default avatarTeemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4aa05917
...@@ -371,6 +371,8 @@ struct wl1271 { ...@@ -371,6 +371,8 @@ struct wl1271 {
#define WL1271_FLAG_IN_ELP (6) #define WL1271_FLAG_IN_ELP (6)
#define WL1271_FLAG_PSM (7) #define WL1271_FLAG_PSM (7)
#define WL1271_FLAG_PSM_REQUESTED (8) #define WL1271_FLAG_PSM_REQUESTED (8)
#define WL1271_FLAG_IRQ_PENDING (9)
#define WL1271_FLAG_IRQ_RUNNING (10)
unsigned long flags; unsigned long flags;
struct wl1271_partition_set part; struct wl1271_partition_set part;
......
...@@ -406,10 +406,14 @@ static void wl1271_fw_status(struct wl1271 *wl, ...@@ -406,10 +406,14 @@ static void wl1271_fw_status(struct wl1271 *wl,
le32_to_cpu(status->fw_localtime); le32_to_cpu(status->fw_localtime);
} }
#define WL1271_IRQ_MAX_LOOPS 10
static void wl1271_irq_work(struct work_struct *work) static void wl1271_irq_work(struct work_struct *work)
{ {
int ret; int ret;
u32 intr; u32 intr;
int loopcount = WL1271_IRQ_MAX_LOOPS;
unsigned long flags;
struct wl1271 *wl = struct wl1271 *wl =
container_of(work, struct wl1271, irq_work); container_of(work, struct wl1271, irq_work);
...@@ -417,51 +421,65 @@ static void wl1271_irq_work(struct work_struct *work) ...@@ -417,51 +421,65 @@ static void wl1271_irq_work(struct work_struct *work)
wl1271_debug(DEBUG_IRQ, "IRQ work"); wl1271_debug(DEBUG_IRQ, "IRQ work");
if (wl->state == WL1271_STATE_OFF) if (unlikely(wl->state == WL1271_STATE_OFF))
goto out; goto out;
ret = wl1271_ps_elp_wakeup(wl, true); ret = wl1271_ps_elp_wakeup(wl, true);
if (ret < 0) if (ret < 0)
goto out; goto out;
wl1271_fw_status(wl, wl->fw_status); spin_lock_irqsave(&wl->wl_lock, flags);
intr = le32_to_cpu(wl->fw_status->intr); while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
if (!intr) { clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); spin_unlock_irqrestore(&wl->wl_lock, flags);
goto out_sleep; loopcount--;
}
intr &= WL1271_INTR_MASK; wl1271_fw_status(wl, wl->fw_status);
intr = le32_to_cpu(wl->fw_status->intr);
if (!intr) {
wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
continue;
}
if (intr & WL1271_ACX_INTR_EVENT_A) { intr &= WL1271_INTR_MASK;
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
wl1271_event_handle(wl, 0);
}
if (intr & WL1271_ACX_INTR_EVENT_B) { if (intr & WL1271_ACX_INTR_DATA) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
wl1271_event_handle(wl, 1);
}
if (intr & WL1271_ACX_INTR_INIT_COMPLETE) /* check for tx results */
wl1271_debug(DEBUG_IRQ, if (wl->fw_status->tx_results_counter !=
"WL1271_ACX_INTR_INIT_COMPLETE"); (wl->tx_results_count & 0xff))
wl1271_tx_complete(wl);
if (intr & WL1271_ACX_INTR_HW_AVAILABLE) wl1271_rx(wl, wl->fw_status);
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); }
if (intr & WL1271_ACX_INTR_EVENT_A) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
wl1271_event_handle(wl, 0);
}
if (intr & WL1271_ACX_INTR_EVENT_B) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
wl1271_event_handle(wl, 1);
}
if (intr & WL1271_ACX_INTR_DATA) { if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); wl1271_debug(DEBUG_IRQ,
"WL1271_ACX_INTR_INIT_COMPLETE");
/* check for tx results */ if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
if (wl->fw_status->tx_results_counter != wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
(wl->tx_results_count & 0xff))
wl1271_tx_complete(wl);
wl1271_rx(wl, wl->fw_status); spin_lock_irqsave(&wl->wl_lock, flags);
} }
out_sleep: if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
ieee80211_queue_work(wl->hw, &wl->irq_work);
else
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
spin_unlock_irqrestore(&wl->wl_lock, flags);
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
out: out:
......
...@@ -75,7 +75,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) ...@@ -75,7 +75,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl->elp_compl = NULL; wl->elp_compl = NULL;
} }
ieee80211_queue_work(wl->hw, &wl->irq_work); if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
ieee80211_queue_work(wl->hw, &wl->irq_work);
set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
......
...@@ -324,7 +324,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) ...@@ -324,7 +324,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
wl->elp_compl = NULL; wl->elp_compl = NULL;
} }
ieee80211_queue_work(wl->hw, &wl->irq_work); if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
ieee80211_queue_work(wl->hw, &wl->irq_work);
set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
spin_unlock_irqrestore(&wl->wl_lock, flags); spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment