void ath9k_htc_reset(struct ath9k_htc_priv *priv) { struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = priv->hw->conf.channel; struct ath9k_hw_cal_data *caldata = NULL; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; int ret; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); if (priv->op_flags & OP_ASSOCIATED) cancel_delayed_work_sync(&priv->ath9k_ani_work); ieee80211_stop_queues(priv->hw); htc_stop(priv->htc); WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); caldata = &priv->caldata; ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); if (ret) { ath_err(common, "Unable to reset device (%u Mhz) reset status %d\n", channel->center_freq, ret); } ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, &priv->curtxpow); WMI_CMD(WMI_START_RECV_CMDID); ath9k_host_rx_init(priv); mode = ath9k_htc_get_curmode(priv, ah->curchan); htc_mode = cpu_to_be16(mode); WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); WMI_CMD(WMI_ENABLE_INTR_CMDID); htc_start(priv->htc); if (priv->op_flags & OP_ASSOCIATED) { ath9k_htc_beacon_config(priv, priv->vif); ath_start_ani(priv); } ieee80211_wake_queues(priv->hw); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); }
static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) { struct ath9k_htc_priv *priv = hw->priv; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); spin_lock_bh(&priv->beacon_lock); priv->op_flags &= ~OP_SCANNING; spin_unlock_bh(&priv->beacon_lock); if (priv->op_flags & OP_ASSOCIATED) { ath9k_htc_beacon_config(priv, priv->vif); ath_start_ani(priv); } ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); }
void ath_check_ani(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; /* * Check for the various conditions in which ANI has to * be stopped. */ if (ah->opmode == NL80211_IFTYPE_ADHOC) { if (!cur_conf->enable_beacon) goto stop_ani; } else if (ah->opmode == NL80211_IFTYPE_AP) { if (!cur_conf->enable_beacon) { /* * Disable ANI only when there are no * associated stations. */ if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } } else if (ah->opmode == NL80211_IFTYPE_STATION) { if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } if (!test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { set_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_start_ani(sc); } return; stop_ani: clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); }
/* * 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; }
static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changed) { struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); if (changed & BSS_CHANGED_ASSOC) { common->curaid = bss_conf->assoc ? bss_conf->aid : 0; ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); if (bss_conf->assoc) { priv->op_flags |= OP_ASSOCIATED; ath_start_ani(priv); } else { priv->op_flags &= ~OP_ASSOCIATED; cancel_delayed_work_sync(&priv->ath9k_ani_work); } } if (changed & BSS_CHANGED_BSSID) { /* Set BSSID */ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); ath9k_hw_write_associd(ah); ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n", common->curbssid, common->curaid); } if ((changed & BSS_CHANGED_BEACON_INT) || (changed & BSS_CHANGED_BEACON) || ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { priv->op_flags |= OP_ENABLE_BEACON; ath9k_htc_beacon_config(priv, vif); } if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) { priv->op_flags &= ~OP_ENABLE_BEACON; ath9k_htc_beacon_config(priv, vif); } if (changed & BSS_CHANGED_ERP_PREAMBLE) { ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) priv->op_flags |= OP_PREAMBLE_SHORT; else priv->op_flags &= ~OP_PREAMBLE_SHORT; } if (changed & BSS_CHANGED_ERP_CTS_PROT) { ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) priv->op_flags |= OP_PROTECT_ENABLE; else priv->op_flags &= ~OP_PROTECT_ENABLE; } if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) ah->slottime = 9; else ah->slottime = 20; ath9k_hw_init_global_settings(ah); } if (changed & BSS_CHANGED_HT) ath9k_htc_update_rate(priv, vif, bss_conf); ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); }