diff options
author | Janne Ylalehto <janne.ylalehto@nokia.com> | 2009-11-17 11:49:31 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-11-18 17:09:22 -0500 |
commit | dcea4dbe54f5bbea2ef0bb265072754ccd934a1e (patch) | |
tree | f0e9a50fe025ac0f57d85e90c4c50582241a7aca /drivers | |
parent | 33d51facad8360cb9c55fd696431e2a477f16cc1 (diff) |
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: Janne Ylalehto <janne.ylalehto@nokia.com>
Reviewed-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Kalle Valo <kalle.valo@nokia.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/wl12xx/wl1251_main.c | 127 |
1 files changed, 67 insertions, 60 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index cc32ba67909..dad010d114f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -212,9 +212,10 @@ out: | |||
212 | return ret; | 212 | return ret; |
213 | } | 213 | } |
214 | 214 | ||
215 | #define WL1251_IRQ_LOOP_COUNT 10 | ||
215 | static void wl1251_irq_work(struct work_struct *work) | 216 | static void wl1251_irq_work(struct work_struct *work) |
216 | { | 217 | { |
217 | u32 intr; | 218 | u32 intr, ctr = WL1251_IRQ_LOOP_COUNT; |
218 | struct wl1251 *wl = | 219 | struct wl1251 *wl = |
219 | container_of(work, struct wl1251, irq_work); | 220 | container_of(work, struct wl1251, irq_work); |
220 | int ret; | 221 | int ret; |
@@ -235,78 +236,84 @@ static void wl1251_irq_work(struct work_struct *work) | |||
235 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); | 236 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); |
236 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); | 237 | wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr); |
237 | 238 | ||
238 | if (wl->data_path) { | 239 | do { |
239 | wl->rx_counter = | 240 | if (wl->data_path) { |
240 | wl1251_mem_read32(wl, wl->data_path->rx_control_addr); | 241 | wl->rx_counter = wl1251_mem_read32( |
241 | 242 | wl, wl->data_path->rx_control_addr); | |
242 | /* We handle a frmware bug here */ | 243 | |
243 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { | 244 | /* We handle a frmware bug here */ |
244 | case 0: | 245 | switch ((wl->rx_counter - wl->rx_handled) & 0xf) { |
245 | wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync"); | 246 | case 0: |
246 | intr &= ~WL1251_ACX_INTR_RX0_DATA; | 247 | wl1251_debug(DEBUG_IRQ, |
247 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | 248 | "RX: FW and host in sync"); |
248 | break; | 249 | intr &= ~WL1251_ACX_INTR_RX0_DATA; |
249 | case 1: | 250 | intr &= ~WL1251_ACX_INTR_RX1_DATA; |
250 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); | 251 | break; |
251 | intr |= WL1251_ACX_INTR_RX0_DATA; | 252 | case 1: |
252 | intr &= ~WL1251_ACX_INTR_RX1_DATA; | 253 | wl1251_debug(DEBUG_IRQ, "RX: FW +1"); |
253 | break; | 254 | intr |= WL1251_ACX_INTR_RX0_DATA; |
254 | case 2: | 255 | intr &= ~WL1251_ACX_INTR_RX1_DATA; |
255 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); | 256 | break; |
256 | intr |= WL1251_ACX_INTR_RX0_DATA; | 257 | case 2: |
257 | intr |= WL1251_ACX_INTR_RX1_DATA; | 258 | wl1251_debug(DEBUG_IRQ, "RX: FW +2"); |
258 | break; | 259 | intr |= WL1251_ACX_INTR_RX0_DATA; |
259 | default: | 260 | intr |= WL1251_ACX_INTR_RX1_DATA; |
260 | wl1251_warning("RX: FW and host out of sync: %d", | 261 | break; |
261 | wl->rx_counter - wl->rx_handled); | 262 | default: |
262 | break; | 263 | wl1251_warning( |
263 | } | 264 | "RX: FW and host out of sync: %d", |
264 | 265 | wl->rx_counter - wl->rx_handled); | |
265 | wl->rx_handled = wl->rx_counter; | 266 | break; |
267 | } | ||
266 | 268 | ||
269 | wl->rx_handled = wl->rx_counter; | ||
267 | 270 | ||
268 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter); | 271 | wl1251_debug(DEBUG_IRQ, "RX counter: %d", |
269 | } | 272 | wl->rx_counter); |
273 | } | ||
270 | 274 | ||
271 | intr &= wl->intr_mask; | 275 | intr &= wl->intr_mask; |
272 | 276 | ||
273 | if (intr == 0) { | 277 | if (intr == 0) { |
274 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); | 278 | wl1251_debug(DEBUG_IRQ, "INTR is 0"); |
275 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, | 279 | goto out_sleep; |
276 | ~(wl->intr_mask)); | 280 | } |
277 | 281 | ||
278 | goto out_sleep; | 282 | if (intr & WL1251_ACX_INTR_RX0_DATA) { |
279 | } | 283 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); |
284 | wl1251_rx(wl); | ||
285 | } | ||
280 | 286 | ||
281 | if (intr & WL1251_ACX_INTR_RX0_DATA) { | 287 | if (intr & WL1251_ACX_INTR_RX1_DATA) { |
282 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA"); | 288 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); |
283 | wl1251_rx(wl); | 289 | wl1251_rx(wl); |
284 | } | 290 | } |
285 | 291 | ||
286 | if (intr & WL1251_ACX_INTR_RX1_DATA) { | 292 | if (intr & WL1251_ACX_INTR_TX_RESULT) { |
287 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA"); | 293 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); |
288 | wl1251_rx(wl); | 294 | wl1251_tx_complete(wl); |
289 | } | 295 | } |
290 | 296 | ||
291 | if (intr & WL1251_ACX_INTR_TX_RESULT) { | 297 | if (intr & (WL1251_ACX_INTR_EVENT_A | |
292 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT"); | 298 | WL1251_ACX_INTR_EVENT_B)) { |
293 | wl1251_tx_complete(wl); | 299 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", |
294 | } | 300 | intr); |
301 | if (intr & WL1251_ACX_INTR_EVENT_A) | ||
302 | wl1251_event_handle(wl, 0); | ||
303 | else | ||
304 | wl1251_event_handle(wl, 1); | ||
305 | } | ||
295 | 306 | ||
296 | if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) { | 307 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) |
297 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr); | 308 | wl1251_debug(DEBUG_IRQ, |
298 | if (intr & WL1251_ACX_INTR_EVENT_A) | 309 | "WL1251_ACX_INTR_INIT_COMPLETE"); |
299 | wl1251_event_handle(wl, 0); | ||
300 | else | ||
301 | wl1251_event_handle(wl, 1); | ||
302 | } | ||
303 | 310 | ||
304 | if (intr & WL1251_ACX_INTR_INIT_COMPLETE) | 311 | intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR); |
305 | wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE"); | ||
306 | 312 | ||
307 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | 313 | } while (intr && --ctr); |
308 | 314 | ||
309 | out_sleep: | 315 | out_sleep: |
316 | wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask)); | ||
310 | wl1251_ps_elp_sleep(wl); | 317 | wl1251_ps_elp_sleep(wl); |
311 | 318 | ||
312 | out: | 319 | out: |