static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { struct ar5416_desc *ads = AR5416DESC(ds); u32 status; status = ACCESS_ONCE(ads->ds_txstatus9); if ((status & AR_TxDone) == 0) return -EINPROGRESS; ts->ts_tstamp = ads->AR_SendTimestamp; ts->ts_status = 0; ts->ts_flags = 0; if (status & AR_TxOpExceeded) ts->ts_status |= ATH9K_TXERR_XTXOP; ts->tid = MS(status, AR_TxTid); ts->ts_rateindex = MS(status, AR_FinalTxIdx); ts->ts_seqnum = MS(status, AR_SeqNum); status = ACCESS_ONCE(ads->ds_txstatus0); ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02); if (status & AR_TxBaStatus) { ts->ts_flags |= ATH9K_TX_BA; ts->ba_low = ads->AR_BaBitmapLow; ts->ba_high = ads->AR_BaBitmapHigh; } status = ACCESS_ONCE(ads->ds_txstatus1); if (status & AR_FrmXmitOK) ts->ts_status |= ATH9K_TX_ACKED; else { if (status & AR_ExcessiveRetries) ts->ts_status |= ATH9K_TXERR_XRETRY; if (status & AR_Filtered) ts->ts_status |= ATH9K_TXERR_FILT; if (status & AR_FIFOUnderrun) { ts->ts_status |= ATH9K_TXERR_FIFO; ath9k_hw_updatetxtriglevel(ah, true); } } if (status & AR_TxTimerExpired) ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; if (status & AR_DescCfgErr) ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; if (status & AR_TxDataUnderrun) { ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; ath9k_hw_updatetxtriglevel(ah, true); } if (status & AR_TxDelimUnderrun) { ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; ath9k_hw_updatetxtriglevel(ah, true); } ts->ts_shortretry = MS(status, AR_RTSFailCnt); ts->ts_longretry = MS(status, AR_DataFailCnt); ts->ts_virtcol = MS(status, AR_VirtRetryCnt); status = ACCESS_ONCE(ads->ds_txstatus5); ts->ts_rssi = MS(status, AR_TxRSSICombined); ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12); ts->evm0 = ads->AR_TxEVM0; ts->evm1 = ads->AR_TxEVM1; ts->evm2 = ads->AR_TxEVM2; return 0; }
irqreturn_t ath_isr(int irq, void *dev) { #define SCHED_INTR ( \ ATH9K_INT_FATAL | \ ATH9K_INT_BB_WATCHDOG | \ ATH9K_INT_RXORN | \ ATH9K_INT_RXEOL | \ ATH9K_INT_RX | \ ATH9K_INT_RXLP | \ ATH9K_INT_RXHP | \ ATH9K_INT_TX | \ ATH9K_INT_BMISS | \ ATH9K_INT_CST | \ ATH9K_INT_TSFOOR | \ ATH9K_INT_GENTIMER) struct ath_softc *sc = dev; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); enum ath9k_int status; bool sched = false; /* * The hardware is not ready/present, don't * touch anything. Note this can happen early * on if the IRQ is shared. */ if (sc->sc_flags & SC_OP_INVALID) return IRQ_NONE; /* shared irq, not for us */ if (!ath9k_hw_intrpend(ah)) 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 &= ah->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) 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) || ((status & ATH9K_INT_RXORN) && !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))) goto chip_reset; if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && (status & ATH9K_INT_BB_WATCHDOG)) { spin_lock(&common->cc_lock); ath_hw_cycle_counters_update(common); ar9003_hw_bb_watchdog_dbg_info(ah); spin_unlock(&common->cc_lock); goto chip_reset; } if (status & ATH9K_INT_SWBA) tasklet_schedule(&sc->bcon_tasklet); if (status & ATH9K_INT_TXURN) ath9k_hw_updatetxtriglevel(ah, true); if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { if (status & ATH9K_INT_RXEOL) { ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); ath9k_hw_set_interrupts(ah, ah->imask); } } if (status & ATH9K_INT_MIB) { /* * Disable interrupts until we service the MIB * interrupt; otherwise it will continue to * fire. */ ath9k_hw_disable_interrupts(ah); /* * Let the hal handle the event. We assume * it will clear whatever condition caused * the interrupt. */ spin_lock(&common->cc_lock); ath9k_hw_proc_mib_event(ah); spin_unlock(&common->cc_lock); ath9k_hw_enable_interrupts(ah); } if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) if (status & ATH9K_INT_TIM_TIMER) { if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle)) goto chip_reset; /* Clear RxAbort bit so that we can * receive frames */ ath9k_setpower(sc, ATH9K_PM_AWAKE); ath9k_hw_setrxabort(sc->sc_ah, 0); sc->ps_flags |= PS_WAIT_FOR_BEACON; } chip_reset: ath_debug_stat_interrupt(sc, status); if (sched) { /* turn off every interrupt */ ath9k_hw_disable_interrupts(ah); tasklet_schedule(&sc->intr_tq); } return IRQ_HANDLED; #undef SCHED_INTR }