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
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_tx99_stop(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); ath_drain_all_txq(sc); ath_startrecv(sc); ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); ieee80211_wake_queues(sc->hw); kfree_skb(sc->tx99_skb); sc->tx99_skb = NULL; sc->tx99_state = false; ath9k_hw_tx99_stop(sc->sc_ah); ath_dbg(common, XMIT, "TX99 stopped\n"); }
/* * 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; }