void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ieee80211_channel *channel = hw->conf.channel; int r; ath9k_ps_wakeup(sc); cancel_delayed_work_sync(&sc->hw_pll_work); spin_lock_bh(&sc->sc_pcu_lock); ieee80211_stop_queues(hw); /* * Keep the LED on when the radio is disabled * during idle unassociated state. */ if (!sc->ps_idle) { ath9k_hw_set_gpio(ah, ah->led_pin, 1); ath9k_hw_cfg_gpio_input(ah, ah->led_pin); } /* Disable interrupts */ ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, false); /* clear pendin
/** * ath9k_hw_updatetxtriglevel - adjusts the frame trigger level * * @ah: atheros hardware struct * @bIncTrigLevel: whether or not the frame trigger level should be updated * * The frame trigger level specifies the minimum number of bytes, * in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO * before the PCU will initiate sending the frame on the air. This can * mean we initiate transmit before a full frame is on the PCU TX FIFO. * Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs * first) * * Caution must be taken to ensure to set the frame trigger level based * on the DMA request size. For example if the DMA request size is set to * 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because * there need to be enough space in the tx FIFO for the requested transfer * size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set * the threshold to a value beyond 6, then the transmit will hang. * * Current dual stream devices have a PCU TX FIFO size of 8 KB. * Current single stream devices have a PCU TX FIFO size of 4 KB, however, * there is a hardware issue which forces us to use 2 KB instead so the * frame trigger level must not exceed 2 KB for these chipsets. */ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) { u32 txcfg, curLevel, newLevel; if (ah->tx_trig_level >= ah->config.max_txtrig_level) return false; ath9k_hw_disable_interrupts(ah); txcfg = REG_READ(ah, AR_TXCFG); curLevel = MS(txcfg, AR_FTRIG); newLevel = curLevel; if (bIncTrigLevel) { if (curLevel < ah->config.max_txtrig_level) newLevel++; } else if (curLevel > MIN_TX_FIFO_THRESHOLD) newLevel--; if (newLevel != curLevel) REG_WRITE(ah, AR_TXCFG, (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); ath9k_hw_enable_interrupts(ah); ah->tx_trig_level = newLevel; return newLevel != curLevel; }
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval) { struct ath_hw *ah = sc->sc_ah; ath9k_hw_disable_interrupts(ah); ath9k_hw_reset_tsf(ah); ath9k_beaconq_config(sc); ath9k_hw_beaconinit(ah, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); }
static int ath9k_tx99_init(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_tx_control txctl; int r; if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_err(common, "driver is in invalid state unable to use TX99"); return -EINVAL; } sc->tx99_skb = ath9k_build_tx99_skb(sc); if (!sc->tx99_skb) return -ENOMEM; memset(&txctl, 0, sizeof(txctl)); txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; ath_reset(sc, NULL); ath9k_ps_wakeup(sc); ath9k_hw_disable_interrupts(ah); atomic_set(&ah->intr_ref_cnt, -1); ath_drain_all_txq(sc); ath_stoprecv(sc); sc->tx99_state = true; ieee80211_stop_queues(hw); if (sc->tx99_power == MAX_RATE_POWER + 1) sc->tx99_power = MAX_RATE_POWER; ath9k_hw_tx99_set_txpower(ah, sc->tx99_power); r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl); if (r) { ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n"); return r; } ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n", sc->tx99_power, sc->tx99_power / 2); /* We leave the harware awake as it will be chugging on */ return 0; }
static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; ath9k_hw_gen_timer_stop(ah, timer); /* if no timer is enabled, turn off interrupt mask */ if (timer_table->timer_mask.val == 0) { ath9k_hw_disable_interrupts(ah); ah->imask &= ~ATH9K_INT_GENTIMER; ath9k_hw_set_interrupts(ah, ah->imask); } }
static void ath9k_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, u32 timer_next, u32 timer_period) { ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_disable_interrupts(ah); ah->imask |= ATH9K_INT_GENTIMER; ath9k_hw_set_interrupts(ah, ah->imask); } }
void ath9k_hw_set_interrupts(struct ath_hw *ah) { enum ath9k_int ints = ah->imask; u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); if (!(ints & ATH9K_INT_GLOBAL)) ath9k_hw_disable_interrupts(ah); ath_dbg(common, INTERRUPT, "New interrupt mask 0x%x\n", ints); mask = ints & ATH9K_INT_COMMON; mask2 = 0; if (ints & ATH9K_INT_TX) { if (ah->config.tx_intr_mitigation) mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; else { if (ah->txok_interrupt_mask) mask |= AR_IMR_TXOK; if (ah->txdesc_interrupt_mask) mask |= AR_IMR_TXDESC; } if (ah->txerr_interrupt_mask) mask |= AR_IMR_TXERR; if (ah->txeol_interrupt_mask) mask |= AR_IMR_TXEOL; } if (ints & ATH9K_INT_RX) { if (AR_SREV_9300_20_OR_LATER(ah)) { mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP; if (ah->config.rx_intr_mitigation) { mask &= ~AR_IMR_RXOK_LP; mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; } else { mask |= AR_IMR_RXOK_LP; } } else { if (ah->config.rx_intr_mitigation) mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM; else mask |= AR_IMR_RXOK | AR_IMR_RXDESC; } if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) mask |= AR_IMR_GENTMR; } if (ints & ATH9K_INT_GENTIMER) mask |= AR_IMR_GENTMR; if (ints & (ATH9K_INT_BMISC)) { mask |= AR_IMR_BCNMISC; if (ints & ATH9K_INT_TIM) mask2 |= AR_IMR_S2_TIM; if (ints & ATH9K_INT_DTIM) mask2 |= AR_IMR_S2_DTIM; if (ints & ATH9K_INT_DTIMSYNC) mask2 |= AR_IMR_S2_DTIMSYNC; if (ints & ATH9K_INT_CABEND) mask2 |= AR_IMR_S2_CABEND; if (ints & ATH9K_INT_TSFOOR) mask2 |= AR_IMR_S2_TSFOOR; } if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { mask |= AR_IMR_BCNMISC; if (ints & ATH9K_INT_GTT) mask2 |= AR_IMR_S2_GTT; if (ints & ATH9K_INT_CST) mask2 |= AR_IMR_S2_CST; } if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { if (ints & ATH9K_INT_BB_WATCHDOG) { mask |= AR_IMR_BCNMISC; mask2 |= AR_IMR_S2_BB_WATCHDOG; } } ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST); if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { if (ints & ATH9K_INT_BB_WATCHDOG) ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG; } ah->imrs2_reg |= mask2; REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if (ints & ATH9K_INT_TIM_TIMER) REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); else REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); } return; }
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 }
/* * Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending * DMA, then restart stuff. */ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; bool fastcc = true, stopped; struct ieee80211_channel *channel = hw->conf.channel; struct ath9k_hw_cal_data *caldata = NULL; int r; if (sc->sc_flags & SC_OP_INVALID) return -EIO; sc->hw_busy_count = 0; del_timer_sync(&common->ani.timer); cancel_work_sync(&sc->paprd_work); cancel_work_sync(&sc->hw_check_work); cancel_delayed_work_sync(&sc->tx_complete_work); cancel_delayed_work_sync(&sc->hw_pll_work); ath9k_ps_wakeup(sc); spin_lock_bh(&sc->sc_pcu_lock); /* * This is only performed if the channel settings have * actually changed. * * To switch channels clear any pending DMA operations; * wait long enough for the RX fifo to drain, reset the * hardware at the new frequency, and then re-enable * the relevant bits of the h/w. */ ath9k_hw_disable_interrupts(ah); stopped = ath_drain_all_txq(sc, false); if (!ath_stoprecv(sc)) stopped = false; if (!ath9k_hw_check_alive(ah)) stopped = false; /* XXX: do not flush receive queue here. We don't want * to flush data frames already in queue because of * changing channel. */ if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL)) fastcc = false; if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) caldata = &sc->caldata; ath_dbg(common, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n", sc->sc_ah->curchan->channel, channel->center_freq, conf_is_ht40(conf), fastcc); r = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (r) { ath_err(common, "Unable to reset channel (%u MHz), reset status %d\n", channel->center_freq, r); goto ps_restore; } if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); r = -EIO; goto ps_restore; } ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); ath9k_hw_set_interrupts(ah, ah->imask); if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { if (sc->sc_flags & SC_OP_BEACONS) ath_set_beacon(sc); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); if (!common->disable_ani) ath_start_ani(common); } ps_restore: ieee80211_wake_queues(hw); spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); return r; }
/* * This sets up the beacon timers according to the timestamp of the last * received beacon and the current TSF, configures PCF and DTIM * handling, programs the sleep registers so the hardware will wakeup in * time to receive beacons, and configures the beacon miss handling so * we'll receive a BMISS interrupt when we stop seeing beacons from the AP * we've associated with. */ static void ath9k_beacon_config_sta(struct ath_softc *sc, struct ath_beacon_config *conf) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_beacon_state bs; int dtimperiod, dtimcount, sleepduration; int cfpperiod, cfpcount; u32 nexttbtt = 0, intval, tsftu; u64 tsf; int num_beacons, offset, dtim_dec_count, cfp_dec_count; /* No need to configure beacon if we are not associated */ if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { ath_dbg(common, BEACON, "STA is not yet associated..skipping beacon config\n"); return; } memset(&bs, 0, sizeof(bs)); intval = conf->beacon_interval; /* * Setup dtim and cfp parameters according to * last beacon we received (which may be none). */ dtimperiod = conf->dtim_period; dtimcount = conf->dtim_count; if (dtimcount >= dtimperiod) /* NB: sanity check */ dtimcount = 0; cfpperiod = 1; /* NB: no PCF support yet */ cfpcount = 0; sleepduration = conf->listen_interval * intval; /* * Pull nexttbtt forward to reflect the current * TSF and calculate dtim+cfp state for the result. */ tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; num_beacons = tsftu / intval + 1; offset = tsftu % intval; nexttbtt = tsftu - offset; if (offset) nexttbtt += intval; /* DTIM Beacon every dtimperiod Beacon */ dtim_dec_count = num_beacons % dtimperiod; /* CFP every cfpperiod DTIM Beacon */ cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; if (dtim_dec_count) cfp_dec_count++; dtimcount -= dtim_dec_count; if (dtimcount < 0) dtimcount += dtimperiod; cfpcount -= cfp_dec_count; if (cfpcount < 0) cfpcount += cfpperiod; bs.bs_intval = intval; bs.bs_nexttbtt = nexttbtt; bs.bs_dtimperiod = dtimperiod*intval; bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; bs.bs_cfpmaxduration = 0; /* * Calculate the number of consecutive beacons to miss* before taking * a BMISS interrupt. The configuration is specified in TU so we only * need calculate based on the beacon interval. Note that we clamp the * result to at most 15 beacons. */ if (sleepduration > intval) { bs.bs_bmissthreshold = conf->listen_interval * ATH_DEFAULT_BMISS_LIMIT / 2; } else { bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); if (bs.bs_bmissthreshold > 15) bs.bs_bmissthreshold = 15; else if (bs.bs_bmissthreshold <= 0) bs.bs_bmissthreshold = 1; } /* * Calculate sleep duration. The configuration is given in ms. * We ensure a multiple of the beacon period is used. Also, if the sleep * duration is greater than the DTIM period then it makes senses * to make it a multiple of that. * * XXX fixed at 100ms */ bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); if (bs.bs_sleepduration > bs.bs_dtimperiod) bs.bs_sleepduration = bs.bs_dtimperiod; /* TSF out of range threshold fixed at 1 second */ bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); ath_dbg(common, BEACON, "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", bs.bs_bmissthreshold, bs.bs_sleepduration, bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); /* Set the computed STA beacon timers */ ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); ah->imask |= ATH9K_INT_BMISS; ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); }