aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/wl1271_main.c
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-02-22 01:38:37 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-03-09 15:03:03 -0500
commit1e73eb62cec7cf78b7295769b6e51a915518f5a1 (patch)
tree3a9cafedbe96d9953a9bcaee86bad9510c04dadf /drivers/net/wireless/wl12xx/wl1271_main.c
parent4aa05917051b01da037a80c3207b48aee252eed2 (diff)
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: Juuso Oikarinen <juuso.oikarinen@nokia.com> Reviewed-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx/wl1271_main.c')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c76
1 files changed, 47 insertions, 29 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index a46d323f8a6e..9f7416864053 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -406,10 +406,14 @@ static void wl1271_fw_status(struct wl1271 *wl,
406 le32_to_cpu(status->fw_localtime); 406 le32_to_cpu(status->fw_localtime);
407} 407}
408 408
409#define WL1271_IRQ_MAX_LOOPS 10
410
409static void wl1271_irq_work(struct work_struct *work) 411static void wl1271_irq_work(struct work_struct *work)
410{ 412{
411 int ret; 413 int ret;
412 u32 intr; 414 u32 intr;
415 int loopcount = WL1271_IRQ_MAX_LOOPS;
416 unsigned long flags;
413 struct wl1271 *wl = 417 struct wl1271 *wl =
414 container_of(work, struct wl1271, irq_work); 418 container_of(work, struct wl1271, irq_work);
415 419
@@ -417,51 +421,65 @@ static void wl1271_irq_work(struct work_struct *work)
417 421
418 wl1271_debug(DEBUG_IRQ, "IRQ work"); 422 wl1271_debug(DEBUG_IRQ, "IRQ work");
419 423
420 if (wl->state == WL1271_STATE_OFF) 424 if (unlikely(wl->state == WL1271_STATE_OFF))
421 goto out; 425 goto out;
422 426
423 ret = wl1271_ps_elp_wakeup(wl, true); 427 ret = wl1271_ps_elp_wakeup(wl, true);
424 if (ret < 0) 428 if (ret < 0)
425 goto out; 429 goto out;
426 430
427 wl1271_fw_status(wl, wl->fw_status); 431 spin_lock_irqsave(&wl->wl_lock, flags);
428 intr = le32_to_cpu(wl->fw_status->intr); 432 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
429 if (!intr) { 433 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
430 wl1271_debug(DEBUG_IRQ, "Zero interrupt received."); 434 spin_unlock_irqrestore(&wl->wl_lock, flags);
431 goto out_sleep; 435 loopcount--;
432 }
433 436
434 intr &= WL1271_INTR_MASK; 437 wl1271_fw_status(wl, wl->fw_status);
438 intr = le32_to_cpu(wl->fw_status->intr);
439 if (!intr) {
440 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
441 continue;
442 }
435 443
436 if (intr & WL1271_ACX_INTR_EVENT_A) { 444 intr &= WL1271_INTR_MASK;
437 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
438 wl1271_event_handle(wl, 0);
439 }
440 445
441 if (intr & WL1271_ACX_INTR_EVENT_B) { 446 if (intr & WL1271_ACX_INTR_DATA) {
442 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); 447 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
443 wl1271_event_handle(wl, 1);
444 }
445 448
446 if (intr & WL1271_ACX_INTR_INIT_COMPLETE) 449 /* check for tx results */
447 wl1271_debug(DEBUG_IRQ, 450 if (wl->fw_status->tx_results_counter !=
448 "WL1271_ACX_INTR_INIT_COMPLETE"); 451 (wl->tx_results_count & 0xff))
452 wl1271_tx_complete(wl);
449 453
450 if (intr & WL1271_ACX_INTR_HW_AVAILABLE) 454 wl1271_rx(wl, wl->fw_status);
451 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); 455 }
456
457 if (intr & WL1271_ACX_INTR_EVENT_A) {
458 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
459 wl1271_event_handle(wl, 0);
460 }
461
462 if (intr & WL1271_ACX_INTR_EVENT_B) {
463 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
464 wl1271_event_handle(wl, 1);
465 }
452 466
453 if (intr & WL1271_ACX_INTR_DATA) { 467 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
454 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); 468 wl1271_debug(DEBUG_IRQ,
469 "WL1271_ACX_INTR_INIT_COMPLETE");
455 470
456 /* check for tx results */ 471 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
457 if (wl->fw_status->tx_results_counter != 472 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
458 (wl->tx_results_count & 0xff))
459 wl1271_tx_complete(wl);
460 473
461 wl1271_rx(wl, wl->fw_status); 474 spin_lock_irqsave(&wl->wl_lock, flags);
462 } 475 }
463 476
464out_sleep: 477 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
478 ieee80211_queue_work(wl->hw, &wl->irq_work);
479 else
480 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
481 spin_unlock_irqrestore(&wl->wl_lock, flags);
482
465 wl1271_ps_elp_sleep(wl); 483 wl1271_ps_elp_sleep(wl);
466 484
467out: 485out: