aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath9k/main.c
diff options
context:
space:
mode:
authorSujith <Sujith.Manoharan@atheros.com>2009-03-30 05:58:49 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:54:35 -0400
commit063d8be37d6f5818976a1185db4af55c5a5ae809 (patch)
tree3cbaab77c760f4075318499a380e0b18df1e26af /drivers/net/wireless/ath9k/main.c
parent87792efc7d20a21844eb7f4247e7b9027e783ec0 (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.c197
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
479irqreturn_t ath_isr(int irq, void *dev) 476irqreturn_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
574chip_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
597static u32 ath_get_extchanmode(struct ath_softc *sc, 590static u32 ath_get_extchanmode(struct ath_softc *sc,