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>
This commit is contained in:
@@ -456,133 +456,124 @@ static void ath9k_tasklet(unsigned long data)
|
|||||||
u32 status = sc->intrstatus;
|
u32 status = sc->intrstatus;
|
||||||
|
|
||||||
if (status & ATH9K_INT_FATAL) {
|
if (status & ATH9K_INT_FATAL) {
|
||||||
/* need a chip reset */
|
|
||||||
ath_reset(sc, false);
|
ath_reset(sc, false);
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
|
|
||||||
if (status &
|
|
||||||
(ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
|
|
||||||
spin_lock_bh(&sc->rx.rxflushlock);
|
|
||||||
ath_rx_tasklet(sc, 0);
|
|
||||||
spin_unlock_bh(&sc->rx.rxflushlock);
|
|
||||||
}
|
|
||||||
/* XXX: optimize this */
|
|
||||||
if (status & ATH9K_INT_TX)
|
|
||||||
ath_tx_tasklet(sc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
|
||||||
|
spin_lock_bh(&sc->rx.rxflushlock);
|
||||||
|
ath_rx_tasklet(sc, 0);
|
||||||
|
spin_unlock_bh(&sc->rx.rxflushlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & ATH9K_INT_TX)
|
||||||
|
ath_tx_tasklet(sc);
|
||||||
|
|
||||||
/* re-enable hardware interrupt */
|
/* re-enable hardware interrupt */
|
||||||
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
|
||||||
}
|
}
|
||||||
|
|
||||||
irqreturn_t ath_isr(int irq, void *dev)
|
irqreturn_t ath_isr(int irq, void *dev)
|
||||||
{
|
{
|
||||||
|
#define SCHED_INTR ( \
|
||||||
|
ATH9K_INT_FATAL | \
|
||||||
|
ATH9K_INT_RXORN | \
|
||||||
|
ATH9K_INT_RXEOL | \
|
||||||
|
ATH9K_INT_RX | \
|
||||||
|
ATH9K_INT_TX | \
|
||||||
|
ATH9K_INT_BMISS | \
|
||||||
|
ATH9K_INT_CST | \
|
||||||
|
ATH9K_INT_TSFOOR)
|
||||||
|
|
||||||
struct ath_softc *sc = dev;
|
struct ath_softc *sc = dev;
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
enum ath9k_int status;
|
enum ath9k_int status;
|
||||||
bool sched = false;
|
bool sched = false;
|
||||||
|
|
||||||
do {
|
/*
|
||||||
if (sc->sc_flags & SC_OP_INVALID) {
|
* The hardware is not ready/present, don't
|
||||||
/*
|
* touch anything. Note this can happen early
|
||||||
* The hardware is not ready/present, don't
|
* on if the IRQ is shared.
|
||||||
* touch anything. Note this can happen early
|
*/
|
||||||
* on if the IRQ is shared.
|
if (sc->sc_flags & SC_OP_INVALID)
|
||||||
*/
|
return IRQ_NONE;
|
||||||
return IRQ_NONE;
|
|
||||||
}
|
|
||||||
if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */
|
|
||||||
return IRQ_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
ath9k_ps_wakeup(sc);
|
||||||
* Figure out the reason(s) for the interrupt. Note
|
|
||||||
* that the hal returns a pseudo-ISR that may include
|
|
||||||
* bits we haven't explicitly enabled so we mask the
|
|
||||||
* value to insure we only process bits we requested.
|
|
||||||
*/
|
|
||||||
ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
|
|
||||||
|
|
||||||
status &= sc->imask; /* discard unasked-for bits */
|
/* shared irq, not for us */
|
||||||
|
|
||||||
/*
|
if (!ath9k_hw_intrpend(ah)) {
|
||||||
* If there are no status bits set, then this interrupt was not
|
|
||||||
* for me (should have been caught above).
|
|
||||||
*/
|
|
||||||
if (!status)
|
|
||||||
return IRQ_NONE;
|
|
||||||
|
|
||||||
sc->intrstatus = status;
|
|
||||||
ath9k_ps_wakeup(sc);
|
|
||||||
|
|
||||||
if (status & ATH9K_INT_FATAL) {
|
|
||||||
/* need a chip reset */
|
|
||||||
sched = true;
|
|
||||||
} else if (status & ATH9K_INT_RXORN) {
|
|
||||||
/* need a chip reset */
|
|
||||||
sched = true;
|
|
||||||
} else {
|
|
||||||
if (status & ATH9K_INT_SWBA) {
|
|
||||||
/* schedule a tasklet for beacon handling */
|
|
||||||
tasklet_schedule(&sc->bcon_tasklet);
|
|
||||||
}
|
|
||||||
if (status & ATH9K_INT_RXEOL) {
|
|
||||||
/*
|
|
||||||
* NB: the hardware should re-read the link when
|
|
||||||
* RXE bit is written, but it doesn't work
|
|
||||||
* at least on older hardware revs.
|
|
||||||
*/
|
|
||||||
sched = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status & ATH9K_INT_TXURN)
|
|
||||||
/* bump tx trigger level */
|
|
||||||
ath9k_hw_updatetxtriglevel(ah, true);
|
|
||||||
/* XXX: optimize this */
|
|
||||||
if (status & ATH9K_INT_RX)
|
|
||||||
sched = true;
|
|
||||||
if (status & ATH9K_INT_TX)
|
|
||||||
sched = true;
|
|
||||||
if (status & ATH9K_INT_BMISS)
|
|
||||||
sched = true;
|
|
||||||
/* carrier sense timeout */
|
|
||||||
if (status & ATH9K_INT_CST)
|
|
||||||
sched = true;
|
|
||||||
if (status & ATH9K_INT_MIB) {
|
|
||||||
/*
|
|
||||||
* Disable interrupts until we service the MIB
|
|
||||||
* interrupt; otherwise it will continue to
|
|
||||||
* fire.
|
|
||||||
*/
|
|
||||||
ath9k_hw_set_interrupts(ah, 0);
|
|
||||||
/*
|
|
||||||
* Let the hal handle the event. We assume
|
|
||||||
* it will clear whatever condition caused
|
|
||||||
* the interrupt.
|
|
||||||
*/
|
|
||||||
ath9k_hw_procmibevent(ah, &sc->nodestats);
|
|
||||||
ath9k_hw_set_interrupts(ah, sc->imask);
|
|
||||||
}
|
|
||||||
if (status & ATH9K_INT_TIM_TIMER) {
|
|
||||||
if (!(ah->caps.hw_caps &
|
|
||||||
ATH9K_HW_CAP_AUTOSLEEP)) {
|
|
||||||
/* Clear RxAbort bit so that we can
|
|
||||||
* receive frames */
|
|
||||||
ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
|
|
||||||
ath9k_hw_setrxabort(ah, 0);
|
|
||||||
sched = true;
|
|
||||||
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (status & ATH9K_INT_TSFOOR) {
|
|
||||||
/* FIXME: Handle this interrupt for power save */
|
|
||||||
sched = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ath9k_ps_restore(sc);
|
ath9k_ps_restore(sc);
|
||||||
} while (0);
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Figure out the reason(s) for the interrupt. Note
|
||||||
|
* that the hal returns a pseudo-ISR that may include
|
||||||
|
* bits we haven't explicitly enabled so we mask the
|
||||||
|
* value to insure we only process bits we requested.
|
||||||
|
*/
|
||||||
|
ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
|
||||||
|
status &= sc->imask; /* discard unasked-for bits */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are no status bits set, then this interrupt was not
|
||||||
|
* for me (should have been caught above).
|
||||||
|
*/
|
||||||
|
if (!status) {
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cache the status */
|
||||||
|
sc->intrstatus = status;
|
||||||
|
|
||||||
|
if (status & SCHED_INTR)
|
||||||
|
sched = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a FATAL or RXORN interrupt is received, we have to reset the
|
||||||
|
* chip immediately.
|
||||||
|
*/
|
||||||
|
if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN))
|
||||||
|
goto chip_reset;
|
||||||
|
|
||||||
|
if (status & ATH9K_INT_SWBA)
|
||||||
|
tasklet_schedule(&sc->bcon_tasklet);
|
||||||
|
|
||||||
|
if (status & ATH9K_INT_TXURN)
|
||||||
|
ath9k_hw_updatetxtriglevel(ah, true);
|
||||||
|
|
||||||
|
if (status & ATH9K_INT_MIB) {
|
||||||
|
/*
|
||||||
|
* Disable interrupts until we service the MIB
|
||||||
|
* interrupt; otherwise it will continue to
|
||||||
|
* fire.
|
||||||
|
*/
|
||||||
|
ath9k_hw_set_interrupts(ah, 0);
|
||||||
|
/*
|
||||||
|
* Let the hal handle the event. We assume
|
||||||
|
* it will clear whatever condition caused
|
||||||
|
* the interrupt.
|
||||||
|
*/
|
||||||
|
ath9k_hw_procmibevent(ah, &sc->nodestats);
|
||||||
|
ath9k_hw_set_interrupts(ah, sc->imask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & ATH9K_INT_TIM_TIMER) {
|
||||||
|
if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||||
|
/* Clear RxAbort bit so that we can
|
||||||
|
* receive frames */
|
||||||
|
ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
|
||||||
|
ath9k_hw_setrxabort(ah, 0);
|
||||||
|
sched = true;
|
||||||
|
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chip_reset:
|
||||||
|
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
ath_debug_stat_interrupt(sc, status);
|
ath_debug_stat_interrupt(sc, status);
|
||||||
|
|
||||||
if (sched) {
|
if (sched) {
|
||||||
@@ -592,6 +583,8 @@ irqreturn_t ath_isr(int irq, void *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
||||||
|
#undef SCHED_INTR
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 ath_get_extchanmode(struct ath_softc *sc,
|
static u32 ath_get_extchanmode(struct ath_softc *sc,
|
||||||
|
Reference in New Issue
Block a user