diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2009-03-30 05:58:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-04-22 16:54:35 -0400 |
commit | 063d8be37d6f5818976a1185db4af55c5a5ae809 (patch) | |
tree | 3cbaab77c760f4075318499a380e0b18df1e26af /drivers/net/wireless/ath9k/main.c | |
parent | 87792efc7d20a21844eb7f4247e7b9027e783ec0 (diff) |
ath9k: Clean Interrupt handling routine
This patch cleans up the ISR, removing a unnecessary do..while
loop, and waking up the chip before getting the pending
interrupts.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 197 |
1 files changed, 95 insertions, 102 deletions
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 99a6852871e2..76c58cc74b27 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -456,133 +456,124 @@ static void ath9k_tasklet(unsigned long data) | |||
456 | u32 status = sc->intrstatus; | 456 | u32 status = sc->intrstatus; |
457 | 457 | ||
458 | if (status & ATH9K_INT_FATAL) { | 458 | if (status & ATH9K_INT_FATAL) { |
459 | /* need a chip reset */ | ||
460 | ath_reset(sc, false); | 459 | ath_reset(sc, false); |
461 | return; | 460 | return; |
462 | } else { | 461 | } |
463 | 462 | ||
464 | if (status & | 463 | if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { |
465 | (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { | 464 | spin_lock_bh(&sc->rx.rxflushlock); |
466 | spin_lock_bh(&sc->rx.rxflushlock); | 465 | ath_rx_tasklet(sc, 0); |
467 | ath_rx_tasklet(sc, 0); | 466 | spin_unlock_bh(&sc->rx.rxflushlock); |
468 | spin_unlock_bh(&sc->rx.rxflushlock); | ||
469 | } | ||
470 | /* XXX: optimize this */ | ||
471 | if (status & ATH9K_INT_TX) | ||
472 | ath_tx_tasklet(sc); | ||
473 | } | 467 | } |
474 | 468 | ||
469 | if (status & ATH9K_INT_TX) | ||
470 | ath_tx_tasklet(sc); | ||
471 | |||
475 | /* re-enable hardware interrupt */ | 472 | /* re-enable hardware interrupt */ |
476 | ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); | 473 | ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); |
477 | } | 474 | } |
478 | 475 | ||
479 | irqreturn_t ath_isr(int irq, void *dev) | 476 | irqreturn_t ath_isr(int irq, void *dev) |
480 | { | 477 | { |
478 | #define SCHED_INTR ( \ | ||
479 | ATH9K_INT_FATAL | \ | ||
480 | ATH9K_INT_RXORN | \ | ||
481 | ATH9K_INT_RXEOL | \ | ||
482 | ATH9K_INT_RX | \ | ||
483 | ATH9K_INT_TX | \ | ||
484 | ATH9K_INT_BMISS | \ | ||
485 | ATH9K_INT_CST | \ | ||
486 | ATH9K_INT_TSFOOR) | ||
487 | |||
481 | struct ath_softc *sc = dev; | 488 | struct ath_softc *sc = dev; |
482 | struct ath_hw *ah = sc->sc_ah; | 489 | struct ath_hw *ah = sc->sc_ah; |
483 | enum ath9k_int status; | 490 | enum ath9k_int status; |
484 | bool sched = false; | 491 | bool sched = false; |
485 | 492 | ||
486 | do { | 493 | /* |
487 | if (sc->sc_flags & SC_OP_INVALID) { | 494 | * The hardware is not ready/present, don't |
488 | /* | 495 | * touch anything. Note this can happen early |
489 | * The hardware is not ready/present, don't | 496 | * on if the IRQ is shared. |
490 | * touch anything. Note this can happen early | 497 | */ |
491 | * on if the IRQ is shared. | 498 | if (sc->sc_flags & SC_OP_INVALID) |
492 | */ | 499 | return IRQ_NONE; |
493 | return IRQ_NONE; | ||
494 | } | ||
495 | if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ | ||
496 | return IRQ_NONE; | ||
497 | } | ||
498 | 500 | ||
499 | /* | 501 | ath9k_ps_wakeup(sc); |
500 | * Figure out the reason(s) for the interrupt. Note | ||
501 | * that the hal returns a pseudo-ISR that may include | ||
502 | * bits we haven't explicitly enabled so we mask the | ||
503 | * value to insure we only process bits we requested. | ||
504 | */ | ||
505 | ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ | ||
506 | 502 | ||
507 | status &= sc->imask; /* discard unasked-for bits */ | 503 | /* shared irq, not for us */ |
504 | |||
505 | if (!ath9k_hw_intrpend(ah)) { | ||
506 | ath9k_ps_restore(sc); | ||
507 | return IRQ_NONE; | ||
508 | } | ||
509 | |||
510 | /* | ||
511 | * Figure out the reason(s) for the interrupt. Note | ||
512 | * that the hal returns a pseudo-ISR that may include | ||
513 | * bits we haven't explicitly enabled so we mask the | ||
514 | * value to insure we only process bits we requested. | ||
515 | */ | ||
516 | ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ | ||
517 | status &= sc->imask; /* discard unasked-for bits */ | ||
518 | |||
519 | /* | ||
520 | * If there are no status bits set, then this interrupt was not | ||
521 | * for me (should have been caught above). | ||
522 | */ | ||
523 | if (!status) { | ||
524 | ath9k_ps_restore(sc); | ||
525 | return IRQ_NONE; | ||
526 | } | ||
508 | 527 | ||
528 | /* Cache the status */ | ||
529 | sc->intrstatus = status; | ||
530 | |||
531 | if (status & SCHED_INTR) | ||
532 | sched = true; | ||
533 | |||
534 | /* | ||
535 | * If a FATAL or RXORN interrupt is received, we have to reset the | ||
536 | * chip immediately. | ||
537 | */ | ||
538 | if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN)) | ||
539 | goto chip_reset; | ||
540 | |||
541 | if (status & ATH9K_INT_SWBA) | ||
542 | tasklet_schedule(&sc->bcon_tasklet); | ||
543 | |||
544 | if (status & ATH9K_INT_TXURN) | ||
545 | ath9k_hw_updatetxtriglevel(ah, true); | ||
546 | |||
547 | if (status & ATH9K_INT_MIB) { | ||
509 | /* | 548 | /* |
510 | * If there are no status bits set, then this interrupt was not | 549 | * Disable interrupts until we service the MIB |
511 | * for me (should have been caught above). | 550 | * interrupt; otherwise it will continue to |
551 | * fire. | ||
512 | */ | 552 | */ |
513 | if (!status) | 553 | ath9k_hw_set_interrupts(ah, 0); |
514 | return IRQ_NONE; | 554 | /* |
515 | 555 | * Let the hal handle the event. We assume | |
516 | sc->intrstatus = status; | 556 | * it will clear whatever condition caused |
517 | ath9k_ps_wakeup(sc); | 557 | * the interrupt. |
558 | */ | ||
559 | ath9k_hw_procmibevent(ah, &sc->nodestats); | ||
560 | ath9k_hw_set_interrupts(ah, sc->imask); | ||
561 | } | ||
518 | 562 | ||
519 | if (status & ATH9K_INT_FATAL) { | 563 | if (status & ATH9K_INT_TIM_TIMER) { |
520 | /* need a chip reset */ | 564 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { |
521 | sched = true; | 565 | /* Clear RxAbort bit so that we can |
522 | } else if (status & ATH9K_INT_RXORN) { | 566 | * receive frames */ |
523 | /* need a chip reset */ | 567 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); |
568 | ath9k_hw_setrxabort(ah, 0); | ||
524 | sched = true; | 569 | sched = true; |
525 | } else { | 570 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; |
526 | if (status & ATH9K_INT_SWBA) { | ||
527 | /* schedule a tasklet for beacon handling */ | ||
528 | tasklet_schedule(&sc->bcon_tasklet); | ||
529 | } | ||
530 | if (status & ATH9K_INT_RXEOL) { | ||
531 | /* | ||
532 | * NB: the hardware should re-read the link when | ||
533 | * RXE bit is written, but it doesn't work | ||
534 | * at least on older hardware revs. | ||
535 | */ | ||
536 | sched = true; | ||
537 | } | ||
538 | |||
539 | if (status & ATH9K_INT_TXURN) | ||
540 | /* bump tx trigger level */ | ||
541 | ath9k_hw_updatetxtriglevel(ah, true); | ||
542 | /* XXX: optimize this */ | ||
543 | if (status & ATH9K_INT_RX) | ||
544 | sched = true; | ||
545 | if (status & ATH9K_INT_TX) | ||
546 | sched = true; | ||
547 | if (status & ATH9K_INT_BMISS) | ||
548 | sched = true; | ||
549 | /* carrier sense timeout */ | ||
550 | if (status & ATH9K_INT_CST) | ||
551 | sched = true; | ||
552 | if (status & ATH9K_INT_MIB) { | ||
553 | /* | ||
554 | * Disable interrupts until we service the MIB | ||
555 | * interrupt; otherwise it will continue to | ||
556 | * fire. | ||
557 | */ | ||
558 | ath9k_hw_set_interrupts(ah, 0); | ||
559 | /* | ||
560 | * Let the hal handle the event. We assume | ||
561 | * it will clear whatever condition caused | ||
562 | * the interrupt. | ||
563 | */ | ||
564 | ath9k_hw_procmibevent(ah, &sc->nodestats); | ||
565 | ath9k_hw_set_interrupts(ah, sc->imask); | ||
566 | } | ||
567 | if (status & ATH9K_INT_TIM_TIMER) { | ||
568 | if (!(ah->caps.hw_caps & | ||
569 | ATH9K_HW_CAP_AUTOSLEEP)) { | ||
570 | /* Clear RxAbort bit so that we can | ||
571 | * receive frames */ | ||
572 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); | ||
573 | ath9k_hw_setrxabort(ah, 0); | ||
574 | sched = true; | ||
575 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; | ||
576 | } | ||
577 | } | ||
578 | if (status & ATH9K_INT_TSFOOR) { | ||
579 | /* FIXME: Handle this interrupt for power save */ | ||
580 | sched = true; | ||
581 | } | ||
582 | } | 571 | } |
583 | ath9k_ps_restore(sc); | 572 | } |
584 | } while (0); | ||
585 | 573 | ||
574 | chip_reset: | ||
575 | |||
576 | ath9k_ps_restore(sc); | ||
586 | ath_debug_stat_interrupt(sc, status); | 577 | ath_debug_stat_interrupt(sc, status); |
587 | 578 | ||
588 | if (sched) { | 579 | if (sched) { |
@@ -592,6 +583,8 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
592 | } | 583 | } |
593 | 584 | ||
594 | return IRQ_HANDLED; | 585 | return IRQ_HANDLED; |
586 | |||
587 | #undef SCHED_INTR | ||
595 | } | 588 | } |
596 | 589 | ||
597 | static u32 ath_get_extchanmode(struct ath_softc *sc, | 590 | static u32 ath_get_extchanmode(struct ath_softc *sc, |