Commit dcea4dbe authored by Janne Ylalehto's avatar Janne Ylalehto Committed by John W. Linville

wl1251: Add IRQ looping support

Add support for IRQ looping. Helps in the case that we have e.g. multiple
packets coming from the network when we wake up from the ELP.
Signed-off-by: default avatarJanne Ylalehto <janne.ylalehto@nokia.com>
Reviewed-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: default avatarKalle Valo <kalle.valo@nokia.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 33d51fac
...@@ -212,9 +212,10 @@ static int wl1251_chip_wakeup(struct wl1251 *wl) ...@@ -212,9 +212,10 @@ static int wl1251_chip_wakeup(struct wl1251 *wl)
return ret; return ret;
} }
#define WL1251_IRQ_LOOP_COUNT 10
static void wl1251_irq_work(struct work_struct *work) static void wl1251_irq_work(struct work_struct *work)
{ {
u32 intr; u32 intr, ctr = WL1251_IRQ_LOOP_COUNT;
struct wl1251 *wl = struct wl1251 *wl =
container_of(work, struct wl1251, irq_work); container_of(work, struct wl1251, irq_work);
int ret; int ret;
...@@ -235,78 +236,84 @@ static void wl1251_irq_work(struct work_struct *work) ...@@ -235,78 +236,84 @@ static void wl1251_irq_work(struct work_struct *work)
intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
if (wl->data_path) { do {
wl->rx_counter = if (wl->data_path) {
wl1251_mem_read32(wl, wl->data_path->rx_control_addr); wl->rx_counter = wl1251_mem_read32(
wl, wl->data_path->rx_control_addr);
/* We handle a frmware bug here */
switch ((wl->rx_counter - wl->rx_handled) & 0xf) { /* We handle a frmware bug here */
case 0: switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); case 0:
intr &= ~WL1251_ACX_INTR_RX0_DATA; wl1251_debug(DEBUG_IRQ,
intr &= ~WL1251_ACX_INTR_RX1_DATA; "RX: FW and host in sync");
break; intr &= ~WL1251_ACX_INTR_RX0_DATA;
case 1: intr &= ~WL1251_ACX_INTR_RX1_DATA;
wl1251_debug(DEBUG_IRQ, "RX: FW +1"); break;
intr |= WL1251_ACX_INTR_RX0_DATA; case 1:
intr &= ~WL1251_ACX_INTR_RX1_DATA; wl1251_debug(DEBUG_IRQ, "RX: FW +1");
break; intr |= WL1251_ACX_INTR_RX0_DATA;
case 2: intr &= ~WL1251_ACX_INTR_RX1_DATA;
wl1251_debug(DEBUG_IRQ, "RX: FW +2"); break;
intr |= WL1251_ACX_INTR_RX0_DATA; case 2:
intr |= WL1251_ACX_INTR_RX1_DATA; wl1251_debug(DEBUG_IRQ, "RX: FW +2");
break; intr |= WL1251_ACX_INTR_RX0_DATA;
default: intr |= WL1251_ACX_INTR_RX1_DATA;
wl1251_warning("RX: FW and host out of sync: %d", break;
wl->rx_counter - wl->rx_handled); default:
break; wl1251_warning(
} "RX: FW and host out of sync: %d",
wl->rx_counter - wl->rx_handled);
wl->rx_handled = wl->rx_counter; break;
}
wl->rx_handled = wl->rx_counter;
wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); wl1251_debug(DEBUG_IRQ, "RX counter: %d",
} wl->rx_counter);
}
intr &= wl->intr_mask; intr &= wl->intr_mask;
if (intr == 0) { if (intr == 0) {
wl1251_debug(DEBUG_IRQ, "INTR is 0"); wl1251_debug(DEBUG_IRQ, "INTR is 0");
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, goto out_sleep;
~(wl->intr_mask)); }
goto out_sleep; if (intr & WL1251_ACX_INTR_RX0_DATA) {
} wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
wl1251_rx(wl);
}
if (intr & WL1251_ACX_INTR_RX0_DATA) { if (intr & WL1251_ACX_INTR_RX1_DATA) {
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
wl1251_rx(wl); wl1251_rx(wl);
} }
if (intr & WL1251_ACX_INTR_RX1_DATA) { if (intr & WL1251_ACX_INTR_TX_RESULT) {
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
wl1251_rx(wl); wl1251_tx_complete(wl);
} }
if (intr & WL1251_ACX_INTR_TX_RESULT) { if (intr & (WL1251_ACX_INTR_EVENT_A |
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); WL1251_ACX_INTR_EVENT_B)) {
wl1251_tx_complete(wl); wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)",
} intr);
if (intr & WL1251_ACX_INTR_EVENT_A)
wl1251_event_handle(wl, 0);
else
wl1251_event_handle(wl, 1);
}
if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); wl1251_debug(DEBUG_IRQ,
if (intr & WL1251_ACX_INTR_EVENT_A) "WL1251_ACX_INTR_INIT_COMPLETE");
wl1251_event_handle(wl, 0);
else
wl1251_event_handle(wl, 1);
}
if (intr & WL1251_ACX_INTR_INIT_COMPLETE) intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); } while (intr && --ctr);
out_sleep: out_sleep:
wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
wl1251_ps_elp_sleep(wl); wl1251_ps_elp_sleep(wl);
out: out:
......
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