162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/nl80211.h> 1862306a36Sopenharmony_ci#include <linux/delay.h> 1962306a36Sopenharmony_ci#include "ath9k.h" 2062306a36Sopenharmony_ci#include "btcoex.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 2362306a36Sopenharmony_ci u32 queues, bool drop); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciu8 ath9k_parse_mpdudensity(u8 mpdudensity) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci /* 2862306a36Sopenharmony_ci * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": 2962306a36Sopenharmony_ci * 0 for no restriction 3062306a36Sopenharmony_ci * 1 for 1/4 us 3162306a36Sopenharmony_ci * 2 for 1/2 us 3262306a36Sopenharmony_ci * 3 for 1 us 3362306a36Sopenharmony_ci * 4 for 2 us 3462306a36Sopenharmony_ci * 5 for 4 us 3562306a36Sopenharmony_ci * 6 for 8 us 3662306a36Sopenharmony_ci * 7 for 16 us 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci switch (mpdudensity) { 3962306a36Sopenharmony_ci case 0: 4062306a36Sopenharmony_ci return 0; 4162306a36Sopenharmony_ci case 1: 4262306a36Sopenharmony_ci case 2: 4362306a36Sopenharmony_ci case 3: 4462306a36Sopenharmony_ci /* Our lower layer calculations limit our precision to 4562306a36Sopenharmony_ci 1 microsecond */ 4662306a36Sopenharmony_ci return 1; 4762306a36Sopenharmony_ci case 4: 4862306a36Sopenharmony_ci return 2; 4962306a36Sopenharmony_ci case 5: 5062306a36Sopenharmony_ci return 4; 5162306a36Sopenharmony_ci case 6: 5262306a36Sopenharmony_ci return 8; 5362306a36Sopenharmony_ci case 7: 5462306a36Sopenharmony_ci return 16; 5562306a36Sopenharmony_ci default: 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq, 6162306a36Sopenharmony_ci bool sw_pending) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci bool pending = false; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci spin_lock_bh(&txq->axq_lock); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (txq->axq_depth) { 6862306a36Sopenharmony_ci pending = true; 6962306a36Sopenharmony_ci goto out; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (!sw_pending) 7362306a36Sopenharmony_ci goto out; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (txq->mac80211_qnum >= 0) { 7662306a36Sopenharmony_ci struct ath_acq *acq; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci acq = &sc->cur_chan->acq[txq->mac80211_qnum]; 7962306a36Sopenharmony_ci if (!list_empty(&acq->acq_new) || !list_empty(&acq->acq_old)) 8062306a36Sopenharmony_ci pending = true; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ciout: 8362306a36Sopenharmony_ci spin_unlock_bh(&txq->axq_lock); 8462306a36Sopenharmony_ci return pending; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci unsigned long flags; 9062306a36Sopenharmony_ci bool ret; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 9362306a36Sopenharmony_ci ret = ath9k_hw_setpower(sc->sc_ah, mode); 9462306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return ret; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_civoid ath_ps_full_sleep(struct timer_list *t) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct ath_softc *sc = from_timer(sc, t, sleep_timer); 10262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 10362306a36Sopenharmony_ci unsigned long flags; 10462306a36Sopenharmony_ci bool reset; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci spin_lock_irqsave(&common->cc_lock, flags); 10762306a36Sopenharmony_ci ath_hw_cycle_counters_update(common); 10862306a36Sopenharmony_ci spin_unlock_irqrestore(&common->cc_lock, flags); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci ath9k_hw_setrxabort(sc->sc_ah, 1); 11162306a36Sopenharmony_ci ath9k_hw_stopdmarecv(sc->sc_ah, &reset); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_civoid ath9k_ps_wakeup(struct ath_softc *sc) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 11962306a36Sopenharmony_ci unsigned long flags; 12062306a36Sopenharmony_ci enum ath9k_power_mode power_mode; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 12362306a36Sopenharmony_ci if (++sc->ps_usecount != 1) 12462306a36Sopenharmony_ci goto unlock; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci del_timer_sync(&sc->sleep_timer); 12762306a36Sopenharmony_ci power_mode = sc->sc_ah->power_mode; 12862306a36Sopenharmony_ci ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * While the hardware is asleep, the cycle counters contain no 13262306a36Sopenharmony_ci * useful data. Better clear them now so that they don't mess up 13362306a36Sopenharmony_ci * survey data results. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci if (power_mode != ATH9K_PM_AWAKE) { 13662306a36Sopenharmony_ci spin_lock(&common->cc_lock); 13762306a36Sopenharmony_ci ath_hw_cycle_counters_update(common); 13862306a36Sopenharmony_ci memset(&common->cc_survey, 0, sizeof(common->cc_survey)); 13962306a36Sopenharmony_ci memset(&common->cc_ani, 0, sizeof(common->cc_ani)); 14062306a36Sopenharmony_ci spin_unlock(&common->cc_lock); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci unlock: 14462306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_civoid ath9k_ps_restore(struct ath_softc *sc) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 15062306a36Sopenharmony_ci enum ath9k_power_mode mode; 15162306a36Sopenharmony_ci unsigned long flags; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 15462306a36Sopenharmony_ci if (--sc->ps_usecount != 0) 15562306a36Sopenharmony_ci goto unlock; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (sc->ps_idle) { 15862306a36Sopenharmony_ci mod_timer(&sc->sleep_timer, jiffies + HZ / 10); 15962306a36Sopenharmony_ci goto unlock; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (sc->ps_enabled && 16362306a36Sopenharmony_ci !(sc->ps_flags & (PS_WAIT_FOR_BEACON | 16462306a36Sopenharmony_ci PS_WAIT_FOR_CAB | 16562306a36Sopenharmony_ci PS_WAIT_FOR_PSPOLL_DATA | 16662306a36Sopenharmony_ci PS_WAIT_FOR_TX_ACK | 16762306a36Sopenharmony_ci PS_WAIT_FOR_ANI))) { 16862306a36Sopenharmony_ci mode = ATH9K_PM_NETWORK_SLEEP; 16962306a36Sopenharmony_ci if (ath9k_hw_btcoex_is_enabled(sc->sc_ah)) 17062306a36Sopenharmony_ci ath9k_btcoex_stop_gen_timer(sc); 17162306a36Sopenharmony_ci } else { 17262306a36Sopenharmony_ci goto unlock; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci spin_lock(&common->cc_lock); 17662306a36Sopenharmony_ci ath_hw_cycle_counters_update(common); 17762306a36Sopenharmony_ci spin_unlock(&common->cc_lock); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci ath9k_hw_setpower(sc->sc_ah, mode); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci unlock: 18262306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void __ath_cancel_work(struct ath_softc *sc) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci cancel_work_sync(&sc->paprd_work); 18862306a36Sopenharmony_ci cancel_delayed_work_sync(&sc->hw_check_work); 18962306a36Sopenharmony_ci cancel_delayed_work_sync(&sc->hw_pll_work); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT 19262306a36Sopenharmony_ci if (ath9k_hw_mci_is_enabled(sc->sc_ah)) 19362306a36Sopenharmony_ci cancel_work_sync(&sc->mci_work); 19462306a36Sopenharmony_ci#endif 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid ath_cancel_work(struct ath_softc *sc) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci __ath_cancel_work(sc); 20062306a36Sopenharmony_ci cancel_work_sync(&sc->hw_reset_work); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_civoid ath_restart_work(struct ath_softc *sc) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work, 20662306a36Sopenharmony_ci msecs_to_jiffies(ATH_HW_CHECK_POLL_INT)); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah)) 20962306a36Sopenharmony_ci ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, 21062306a36Sopenharmony_ci msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ath_start_ani(sc); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic bool ath_prepare_reset(struct ath_softc *sc) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 21862306a36Sopenharmony_ci bool ret = true; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ieee80211_stop_queues(sc->hw); 22162306a36Sopenharmony_ci ath_stop_ani(sc); 22262306a36Sopenharmony_ci ath9k_hw_disable_interrupts(ah); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (AR_SREV_9300_20_OR_LATER(ah)) { 22562306a36Sopenharmony_ci ret &= ath_stoprecv(sc); 22662306a36Sopenharmony_ci ret &= ath_drain_all_txq(sc); 22762306a36Sopenharmony_ci } else { 22862306a36Sopenharmony_ci ret &= ath_drain_all_txq(sc); 22962306a36Sopenharmony_ci ret &= ath_stoprecv(sc); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return ret; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic bool ath_complete_reset(struct ath_softc *sc, bool start) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 23862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 23962306a36Sopenharmony_ci unsigned long flags; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ath9k_calculate_summary_state(sc, sc->cur_chan); 24262306a36Sopenharmony_ci ath_startrecv(sc); 24362306a36Sopenharmony_ci ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, 24462306a36Sopenharmony_ci sc->cur_chan->txpower, 24562306a36Sopenharmony_ci &sc->cur_chan->cur_txpower); 24662306a36Sopenharmony_ci clear_bit(ATH_OP_HW_RESET, &common->op_flags); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (!sc->cur_chan->offchannel && start) { 24962306a36Sopenharmony_ci /* restore per chanctx TSF timer */ 25062306a36Sopenharmony_ci if (sc->cur_chan->tsf_val) { 25162306a36Sopenharmony_ci u32 offset; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci offset = ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, 25462306a36Sopenharmony_ci NULL); 25562306a36Sopenharmony_ci ath9k_hw_settsf64(ah, sc->cur_chan->tsf_val + offset); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) 26062306a36Sopenharmony_ci goto work; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_STATION && 26362306a36Sopenharmony_ci test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { 26462306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 26562306a36Sopenharmony_ci sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; 26662306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 26762306a36Sopenharmony_ci } else { 26862306a36Sopenharmony_ci ath9k_set_beacon(sc); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci work: 27162306a36Sopenharmony_ci ath_restart_work(sc); 27262306a36Sopenharmony_ci ath_txq_schedule_all(sc); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci sc->gtt_cnt = 0; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci ath9k_hw_set_interrupts(ah); 27862306a36Sopenharmony_ci ath9k_hw_enable_interrupts(ah); 27962306a36Sopenharmony_ci ieee80211_wake_queues(sc->hw); 28062306a36Sopenharmony_ci ath9k_p2p_ps_timer(sc); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return true; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 28862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 28962306a36Sopenharmony_ci struct ath9k_hw_cal_data *caldata = NULL; 29062306a36Sopenharmony_ci bool fastcc = true; 29162306a36Sopenharmony_ci int r; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci __ath_cancel_work(sc); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci disable_irq(sc->irq); 29662306a36Sopenharmony_ci tasklet_disable(&sc->intr_tq); 29762306a36Sopenharmony_ci tasklet_disable(&sc->bcon_tasklet); 29862306a36Sopenharmony_ci spin_lock_bh(&sc->sc_pcu_lock); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!sc->cur_chan->offchannel) { 30162306a36Sopenharmony_ci fastcc = false; 30262306a36Sopenharmony_ci caldata = &sc->cur_chan->caldata; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!hchan) { 30662306a36Sopenharmony_ci fastcc = false; 30762306a36Sopenharmony_ci hchan = ah->curchan; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (!hchan) { 31162306a36Sopenharmony_ci fastcc = false; 31262306a36Sopenharmony_ci hchan = ath9k_cmn_get_channel(sc->hw, ah, &sc->cur_chan->chandef); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!ath_prepare_reset(sc)) 31662306a36Sopenharmony_ci fastcc = false; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) 31962306a36Sopenharmony_ci fastcc = false; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 32262306a36Sopenharmony_ci sc->cur_chandef = sc->cur_chan->chandef; 32362306a36Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", 32662306a36Sopenharmony_ci hchan->channel, IS_CHAN_HT40(hchan), fastcc); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci r = ath9k_hw_reset(ah, hchan, caldata, fastcc); 32962306a36Sopenharmony_ci if (r) { 33062306a36Sopenharmony_ci ath_err(common, 33162306a36Sopenharmony_ci "Unable to reset channel, reset status %d\n", r); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ath9k_hw_enable_interrupts(ah); 33462306a36Sopenharmony_ci ath9k_queue_reset(sc, RESET_TYPE_BB_HANG); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci goto out; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (ath9k_hw_mci_is_enabled(sc->sc_ah) && 34062306a36Sopenharmony_ci sc->cur_chan->offchannel) 34162306a36Sopenharmony_ci ath9k_mci_set_txpower(sc, true, false); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!ath_complete_reset(sc, true)) 34462306a36Sopenharmony_ci r = -EIO; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ciout: 34762306a36Sopenharmony_ci enable_irq(sc->irq); 34862306a36Sopenharmony_ci spin_unlock_bh(&sc->sc_pcu_lock); 34962306a36Sopenharmony_ci tasklet_enable(&sc->bcon_tasklet); 35062306a36Sopenharmony_ci tasklet_enable(&sc->intr_tq); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return r; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, 35662306a36Sopenharmony_ci struct ieee80211_vif *vif) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct ath_node *an; 35962306a36Sopenharmony_ci an = (struct ath_node *)sta->drv_priv; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci an->sc = sc; 36262306a36Sopenharmony_ci an->sta = sta; 36362306a36Sopenharmony_ci an->vif = vif; 36462306a36Sopenharmony_ci memset(&an->key_idx, 0, sizeof(an->key_idx)); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci ath_tx_node_init(sc, an); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ath_dynack_node_init(sc->sc_ah, an); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct ath_node *an = (struct ath_node *)sta->drv_priv; 37462306a36Sopenharmony_ci ath_tx_node_cleanup(sc, an); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci ath_dynack_node_deinit(sc->sc_ah, an); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_civoid ath9k_tasklet(struct tasklet_struct *t) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct ath_softc *sc = from_tasklet(sc, t, intr_tq); 38262306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 38362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 38462306a36Sopenharmony_ci enum ath_reset_type type; 38562306a36Sopenharmony_ci unsigned long flags; 38662306a36Sopenharmony_ci u32 status; 38762306a36Sopenharmony_ci u32 rxmask; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci spin_lock_irqsave(&sc->intr_lock, flags); 39062306a36Sopenharmony_ci status = sc->intrstatus; 39162306a36Sopenharmony_ci sc->intrstatus = 0; 39262306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->intr_lock, flags); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 39562306a36Sopenharmony_ci spin_lock(&sc->sc_pcu_lock); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (status & ATH9K_INT_FATAL) { 39862306a36Sopenharmony_ci type = RESET_TYPE_FATAL_INT; 39962306a36Sopenharmony_ci ath9k_queue_reset(sc, type); 40062306a36Sopenharmony_ci ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); 40162306a36Sopenharmony_ci goto out; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) && 40562306a36Sopenharmony_ci (status & ATH9K_INT_BB_WATCHDOG)) { 40662306a36Sopenharmony_ci spin_lock_irqsave(&common->cc_lock, flags); 40762306a36Sopenharmony_ci ath_hw_cycle_counters_update(common); 40862306a36Sopenharmony_ci ar9003_hw_bb_watchdog_dbg_info(ah); 40962306a36Sopenharmony_ci spin_unlock_irqrestore(&common->cc_lock, flags); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (ar9003_hw_bb_watchdog_check(ah)) { 41262306a36Sopenharmony_ci type = RESET_TYPE_BB_WATCHDOG; 41362306a36Sopenharmony_ci ath9k_queue_reset(sc, type); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci ath_dbg(common, RESET, 41662306a36Sopenharmony_ci "BB_WATCHDOG: Skipping interrupts\n"); 41762306a36Sopenharmony_ci goto out; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (status & ATH9K_INT_GTT) { 42262306a36Sopenharmony_ci sc->gtt_cnt++; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) { 42562306a36Sopenharmony_ci type = RESET_TYPE_TX_GTT; 42662306a36Sopenharmony_ci ath9k_queue_reset(sc, type); 42762306a36Sopenharmony_ci ath_dbg(common, RESET, 42862306a36Sopenharmony_ci "GTT: Skipping interrupts\n"); 42962306a36Sopenharmony_ci goto out; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 43462306a36Sopenharmony_ci if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * TSF sync does not look correct; remain awake to sync with 43762306a36Sopenharmony_ci * the next Beacon. 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_ci ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n"); 44062306a36Sopenharmony_ci sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) 44562306a36Sopenharmony_ci rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | 44662306a36Sopenharmony_ci ATH9K_INT_RXORN); 44762306a36Sopenharmony_ci else 44862306a36Sopenharmony_ci rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (status & rxmask) { 45162306a36Sopenharmony_ci /* Check for high priority Rx first */ 45262306a36Sopenharmony_ci if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && 45362306a36Sopenharmony_ci (status & ATH9K_INT_RXHP)) 45462306a36Sopenharmony_ci ath_rx_tasklet(sc, 0, true); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci ath_rx_tasklet(sc, 0, false); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (status & ATH9K_INT_TX) { 46062306a36Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { 46162306a36Sopenharmony_ci /* 46262306a36Sopenharmony_ci * For EDMA chips, TX completion is enabled for the 46362306a36Sopenharmony_ci * beacon queue, so if a beacon has been transmitted 46462306a36Sopenharmony_ci * successfully after a GTT interrupt, the GTT counter 46562306a36Sopenharmony_ci * gets reset to zero here. 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ci sc->gtt_cnt = 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci ath_tx_edma_tasklet(sc); 47062306a36Sopenharmony_ci } else { 47162306a36Sopenharmony_ci ath_tx_tasklet(sc); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci wake_up(&sc->tx_wait); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (status & ATH9K_INT_GENTIMER) 47862306a36Sopenharmony_ci ath_gen_timer_isr(sc->sc_ah); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci ath9k_btcoex_handle_interrupt(sc, status); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* re-enable hardware interrupt */ 48362306a36Sopenharmony_ci ath9k_hw_resume_interrupts(ah); 48462306a36Sopenharmony_ciout: 48562306a36Sopenharmony_ci spin_unlock(&sc->sc_pcu_lock); 48662306a36Sopenharmony_ci ath9k_ps_restore(sc); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ciirqreturn_t ath_isr(int irq, void *dev) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci#define SCHED_INTR ( \ 49262306a36Sopenharmony_ci ATH9K_INT_FATAL | \ 49362306a36Sopenharmony_ci ATH9K_INT_BB_WATCHDOG | \ 49462306a36Sopenharmony_ci ATH9K_INT_RXORN | \ 49562306a36Sopenharmony_ci ATH9K_INT_RXEOL | \ 49662306a36Sopenharmony_ci ATH9K_INT_RX | \ 49762306a36Sopenharmony_ci ATH9K_INT_RXLP | \ 49862306a36Sopenharmony_ci ATH9K_INT_RXHP | \ 49962306a36Sopenharmony_ci ATH9K_INT_TX | \ 50062306a36Sopenharmony_ci ATH9K_INT_BMISS | \ 50162306a36Sopenharmony_ci ATH9K_INT_CST | \ 50262306a36Sopenharmony_ci ATH9K_INT_GTT | \ 50362306a36Sopenharmony_ci ATH9K_INT_TSFOOR | \ 50462306a36Sopenharmony_ci ATH9K_INT_GENTIMER | \ 50562306a36Sopenharmony_ci ATH9K_INT_MCI) 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci struct ath_softc *sc = dev; 50862306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 50962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 51062306a36Sopenharmony_ci enum ath9k_int status; 51162306a36Sopenharmony_ci u32 sync_cause = 0; 51262306a36Sopenharmony_ci bool sched = false; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* 51562306a36Sopenharmony_ci * The hardware is not ready/present, don't 51662306a36Sopenharmony_ci * touch anything. Note this can happen early 51762306a36Sopenharmony_ci * on if the IRQ is shared. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags)) 52062306a36Sopenharmony_ci return IRQ_NONE; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* shared irq, not for us */ 52362306a36Sopenharmony_ci if (!ath9k_hw_intrpend(ah)) 52462306a36Sopenharmony_ci return IRQ_NONE; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* 52762306a36Sopenharmony_ci * Figure out the reason(s) for the interrupt. Note 52862306a36Sopenharmony_ci * that the hal returns a pseudo-ISR that may include 52962306a36Sopenharmony_ci * bits we haven't explicitly enabled so we mask the 53062306a36Sopenharmony_ci * value to insure we only process bits we requested. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci ath9k_hw_getisr(ah, &status, &sync_cause); /* NB: clears ISR too */ 53362306a36Sopenharmony_ci ath9k_debug_sync_cause(sc, sync_cause); 53462306a36Sopenharmony_ci status &= ah->imask; /* discard unasked-for bits */ 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { 53762306a36Sopenharmony_ci ath9k_hw_kill_interrupts(sc->sc_ah); 53862306a36Sopenharmony_ci return IRQ_HANDLED; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* 54262306a36Sopenharmony_ci * If there are no status bits set, then this interrupt was not 54362306a36Sopenharmony_ci * for me (should have been caught above). 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_ci if (!status) 54662306a36Sopenharmony_ci return IRQ_NONE; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* Cache the status */ 54962306a36Sopenharmony_ci spin_lock(&sc->intr_lock); 55062306a36Sopenharmony_ci sc->intrstatus |= status; 55162306a36Sopenharmony_ci spin_unlock(&sc->intr_lock); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (status & SCHED_INTR) 55462306a36Sopenharmony_ci sched = true; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* 55762306a36Sopenharmony_ci * If a FATAL interrupt is received, we have to reset the chip 55862306a36Sopenharmony_ci * immediately. 55962306a36Sopenharmony_ci */ 56062306a36Sopenharmony_ci if (status & ATH9K_INT_FATAL) 56162306a36Sopenharmony_ci goto chip_reset; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) && 56462306a36Sopenharmony_ci (status & ATH9K_INT_BB_WATCHDOG)) 56562306a36Sopenharmony_ci goto chip_reset; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (status & ATH9K_INT_SWBA) 56862306a36Sopenharmony_ci tasklet_schedule(&sc->bcon_tasklet); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (status & ATH9K_INT_TXURN) 57162306a36Sopenharmony_ci ath9k_hw_updatetxtriglevel(ah, true); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (status & ATH9K_INT_RXEOL) { 57462306a36Sopenharmony_ci ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); 57562306a36Sopenharmony_ci ath9k_hw_set_interrupts(ah); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) 57962306a36Sopenharmony_ci if (status & ATH9K_INT_TIM_TIMER) { 58062306a36Sopenharmony_ci if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle)) 58162306a36Sopenharmony_ci goto chip_reset; 58262306a36Sopenharmony_ci /* Clear RxAbort bit so that we can 58362306a36Sopenharmony_ci * receive frames */ 58462306a36Sopenharmony_ci ath9k_setpower(sc, ATH9K_PM_AWAKE); 58562306a36Sopenharmony_ci spin_lock(&sc->sc_pm_lock); 58662306a36Sopenharmony_ci ath9k_hw_setrxabort(sc->sc_ah, 0); 58762306a36Sopenharmony_ci sc->ps_flags |= PS_WAIT_FOR_BEACON; 58862306a36Sopenharmony_ci spin_unlock(&sc->sc_pm_lock); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cichip_reset: 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci ath_debug_stat_interrupt(sc, status); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (sched) { 59662306a36Sopenharmony_ci /* turn off every interrupt */ 59762306a36Sopenharmony_ci ath9k_hw_kill_interrupts(ah); 59862306a36Sopenharmony_ci tasklet_schedule(&sc->intr_tq); 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return IRQ_HANDLED; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci#undef SCHED_INTR 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci/* 60762306a36Sopenharmony_ci * This function is called when a HW reset cannot be deferred 60862306a36Sopenharmony_ci * and has to be immediate. 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_ciint ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 61362306a36Sopenharmony_ci int r; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ath9k_hw_kill_interrupts(sc->sc_ah); 61662306a36Sopenharmony_ci set_bit(ATH_OP_HW_RESET, &common->op_flags); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 61962306a36Sopenharmony_ci r = ath_reset_internal(sc, hchan); 62062306a36Sopenharmony_ci ath9k_ps_restore(sc); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return r; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci/* 62662306a36Sopenharmony_ci * When a HW reset can be deferred, it is added to the 62762306a36Sopenharmony_ci * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before 62862306a36Sopenharmony_ci * queueing. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_civoid ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 63362306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_DEBUGFS 63462306a36Sopenharmony_ci RESET_STAT_INC(sc, type); 63562306a36Sopenharmony_ci#endif 63662306a36Sopenharmony_ci ath9k_hw_kill_interrupts(sc->sc_ah); 63762306a36Sopenharmony_ci set_bit(ATH_OP_HW_RESET, &common->op_flags); 63862306a36Sopenharmony_ci ieee80211_queue_work(sc->hw, &sc->hw_reset_work); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_civoid ath_reset_work(struct work_struct *work) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 64662306a36Sopenharmony_ci ath_reset_internal(sc, NULL); 64762306a36Sopenharmony_ci ath9k_ps_restore(sc); 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci/**********************/ 65162306a36Sopenharmony_ci/* mac80211 callbacks */ 65262306a36Sopenharmony_ci/**********************/ 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic int ath9k_start(struct ieee80211_hw *hw) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 65762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 65862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 65962306a36Sopenharmony_ci struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; 66062306a36Sopenharmony_ci struct ath_chanctx *ctx = sc->cur_chan; 66162306a36Sopenharmony_ci struct ath9k_channel *init_channel; 66262306a36Sopenharmony_ci int r; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci ath_dbg(common, CONFIG, 66562306a36Sopenharmony_ci "Starting driver with initial channel: %d MHz\n", 66662306a36Sopenharmony_ci curchan->center_freq); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 66962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci init_channel = ath9k_cmn_get_channel(hw, ah, &ctx->chandef); 67262306a36Sopenharmony_ci sc->cur_chandef = hw->conf.chandef; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* Reset SERDES registers */ 67562306a36Sopenharmony_ci ath9k_hw_configpcipowersave(ah, false); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* 67862306a36Sopenharmony_ci * The basic interface to setting the hardware in a good 67962306a36Sopenharmony_ci * state is ``reset''. On return the hardware is known to 68062306a36Sopenharmony_ci * be powered up and with interrupts disabled. This must 68162306a36Sopenharmony_ci * be followed by initialization of the appropriate bits 68262306a36Sopenharmony_ci * and then setup of the interrupt mask. 68362306a36Sopenharmony_ci */ 68462306a36Sopenharmony_ci spin_lock_bh(&sc->sc_pcu_lock); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci atomic_set(&ah->intr_ref_cnt, -1); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); 68962306a36Sopenharmony_ci if (r) { 69062306a36Sopenharmony_ci ath_err(common, 69162306a36Sopenharmony_ci "Unable to reset hardware; reset status %d (freq %u MHz)\n", 69262306a36Sopenharmony_ci r, curchan->center_freq); 69362306a36Sopenharmony_ci ah->reset_power_on = false; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Setup our intr mask. */ 69762306a36Sopenharmony_ci ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | 69862306a36Sopenharmony_ci ATH9K_INT_RXORN | ATH9K_INT_FATAL | 69962306a36Sopenharmony_ci ATH9K_INT_GLOBAL; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) 70262306a36Sopenharmony_ci ah->imask |= ATH9K_INT_RXHP | 70362306a36Sopenharmony_ci ATH9K_INT_RXLP; 70462306a36Sopenharmony_ci else 70562306a36Sopenharmony_ci ah->imask |= ATH9K_INT_RX; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) 70862306a36Sopenharmony_ci ah->imask |= ATH9K_INT_BB_WATCHDOG; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * Enable GTT interrupts only for AR9003/AR9004 chips 71262306a36Sopenharmony_ci * for now. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci if (AR_SREV_9300_20_OR_LATER(ah)) 71562306a36Sopenharmony_ci ah->imask |= ATH9K_INT_GTT; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) 71862306a36Sopenharmony_ci ah->imask |= ATH9K_INT_CST; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci ath_mci_enable(sc); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci clear_bit(ATH_OP_INVALID, &common->op_flags); 72362306a36Sopenharmony_ci sc->sc_ah->is_monitoring = false; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (!ath_complete_reset(sc, false)) 72662306a36Sopenharmony_ci ah->reset_power_on = false; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (ah->led_pin >= 0) { 72962306a36Sopenharmony_ci ath9k_hw_set_gpio(ah, ah->led_pin, 73062306a36Sopenharmony_ci (ah->config.led_active_high) ? 1 : 0); 73162306a36Sopenharmony_ci ath9k_hw_gpio_request_out(ah, ah->led_pin, NULL, 73262306a36Sopenharmony_ci AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* 73662306a36Sopenharmony_ci * Reset key cache to sane defaults (all entries cleared) instead of 73762306a36Sopenharmony_ci * semi-random values after suspend/resume. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci ath9k_cmn_init_crypto(sc->sc_ah); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci ath9k_hw_reset_tsf(ah); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci spin_unlock_bh(&sc->sc_pcu_lock); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci ath9k_rng_start(sc); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci ath9k_ps_restore(sc); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci return 0; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic void ath9k_tx(struct ieee80211_hw *hw, 75562306a36Sopenharmony_ci struct ieee80211_tx_control *control, 75662306a36Sopenharmony_ci struct sk_buff *skb) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 75962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 76062306a36Sopenharmony_ci struct ath_tx_control txctl; 76162306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 76262306a36Sopenharmony_ci unsigned long flags; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (sc->ps_enabled) { 76562306a36Sopenharmony_ci /* 76662306a36Sopenharmony_ci * mac80211 does not set PM field for normal data frames, so we 76762306a36Sopenharmony_ci * need to update that based on the current PS mode. 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_ci if (ieee80211_is_data(hdr->frame_control) && 77062306a36Sopenharmony_ci !ieee80211_is_nullfunc(hdr->frame_control) && 77162306a36Sopenharmony_ci !ieee80211_has_pm(hdr->frame_control)) { 77262306a36Sopenharmony_ci ath_dbg(common, PS, 77362306a36Sopenharmony_ci "Add PM=1 for a TX frame while in PS mode\n"); 77462306a36Sopenharmony_ci hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP)) { 77962306a36Sopenharmony_ci /* 78062306a36Sopenharmony_ci * We are using PS-Poll and mac80211 can request TX while in 78162306a36Sopenharmony_ci * power save mode. Need to wake up hardware for the TX to be 78262306a36Sopenharmony_ci * completed and if needed, also for RX of buffered frames. 78362306a36Sopenharmony_ci */ 78462306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 78562306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 78662306a36Sopenharmony_ci if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) 78762306a36Sopenharmony_ci ath9k_hw_setrxabort(sc->sc_ah, 0); 78862306a36Sopenharmony_ci if (ieee80211_is_pspoll(hdr->frame_control)) { 78962306a36Sopenharmony_ci ath_dbg(common, PS, 79062306a36Sopenharmony_ci "Sending PS-Poll to pick a buffered frame\n"); 79162306a36Sopenharmony_ci sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA; 79262306a36Sopenharmony_ci } else { 79362306a36Sopenharmony_ci ath_dbg(common, PS, "Wake up to complete TX\n"); 79462306a36Sopenharmony_ci sc->ps_flags |= PS_WAIT_FOR_TX_ACK; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci /* 79762306a36Sopenharmony_ci * The actual restore operation will happen only after 79862306a36Sopenharmony_ci * the ps_flags bit is cleared. We are just dropping 79962306a36Sopenharmony_ci * the ps_usecount here. 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 80262306a36Sopenharmony_ci ath9k_ps_restore(sc); 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* 80662306a36Sopenharmony_ci * Cannot tx while the hardware is in full sleep, it first needs a full 80762306a36Sopenharmony_ci * chip reset to recover from that 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_ci if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) { 81062306a36Sopenharmony_ci ath_err(common, "TX while HW is in FULL_SLEEP mode\n"); 81162306a36Sopenharmony_ci goto exit; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci memset(&txctl, 0, sizeof(struct ath_tx_control)); 81562306a36Sopenharmony_ci txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; 81662306a36Sopenharmony_ci txctl.sta = control->sta; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (ath_tx_start(hw, skb, &txctl) != 0) { 82162306a36Sopenharmony_ci ath_dbg(common, XMIT, "TX failed\n"); 82262306a36Sopenharmony_ci TX_STAT_INC(sc, txctl.txq->axq_qnum, txfailed); 82362306a36Sopenharmony_ci goto exit; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return; 82762306a36Sopenharmony_ciexit: 82862306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic bool ath9k_txq_list_has_key(struct list_head *txq_list, u32 keyix) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct ath_buf *bf; 83462306a36Sopenharmony_ci struct ieee80211_tx_info *txinfo; 83562306a36Sopenharmony_ci struct ath_frame_info *fi; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci list_for_each_entry(bf, txq_list, list) { 83862306a36Sopenharmony_ci if (bf->bf_state.stale || !bf->bf_mpdu) 83962306a36Sopenharmony_ci continue; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci txinfo = IEEE80211_SKB_CB(bf->bf_mpdu); 84262306a36Sopenharmony_ci fi = (struct ath_frame_info *)&txinfo->status.status_driver_data[0]; 84362306a36Sopenharmony_ci if (fi->keyix == keyix) 84462306a36Sopenharmony_ci return true; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci return false; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 85362306a36Sopenharmony_ci int i, j; 85462306a36Sopenharmony_ci struct ath_txq *txq; 85562306a36Sopenharmony_ci bool key_in_use = false; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci for (i = 0; !key_in_use && i < ATH9K_NUM_TX_QUEUES; i++) { 85862306a36Sopenharmony_ci if (!ATH_TXQ_SETUP(sc, i)) 85962306a36Sopenharmony_ci continue; 86062306a36Sopenharmony_ci txq = &sc->tx.txq[i]; 86162306a36Sopenharmony_ci if (!txq->axq_depth) 86262306a36Sopenharmony_ci continue; 86362306a36Sopenharmony_ci if (!ath9k_hw_numtxpending(ah, txq->axq_qnum)) 86462306a36Sopenharmony_ci continue; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci ath_txq_lock(sc, txq); 86762306a36Sopenharmony_ci key_in_use = ath9k_txq_list_has_key(&txq->axq_q, keyix); 86862306a36Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { 86962306a36Sopenharmony_ci int idx = txq->txq_tailidx; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci for (j = 0; !key_in_use && 87262306a36Sopenharmony_ci !list_empty(&txq->txq_fifo[idx]) && 87362306a36Sopenharmony_ci j < ATH_TXFIFO_DEPTH; j++) { 87462306a36Sopenharmony_ci key_in_use = ath9k_txq_list_has_key( 87562306a36Sopenharmony_ci &txq->txq_fifo[idx], keyix); 87662306a36Sopenharmony_ci INCR(idx, ATH_TXFIFO_DEPTH); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci ath_txq_unlock(sc, txq); 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return key_in_use; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic void ath9k_pending_key_del(struct ath_softc *sc, u8 keyix) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 88862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (!test_bit(keyix, ah->pending_del_keymap) || 89162306a36Sopenharmony_ci ath9k_txq_has_key(sc, keyix)) 89262306a36Sopenharmony_ci return; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci /* No more TXQ frames point to this key cache entry, so delete it. */ 89562306a36Sopenharmony_ci clear_bit(keyix, ah->pending_del_keymap); 89662306a36Sopenharmony_ci ath_key_delete(common, keyix); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic void ath9k_stop(struct ieee80211_hw *hw) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 90262306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 90362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 90462306a36Sopenharmony_ci bool prev_idle; 90562306a36Sopenharmony_ci int i; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci ath9k_deinit_channel_context(sc); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci ath9k_rng_stop(sc); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci ath_cancel_work(sc); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (test_bit(ATH_OP_INVALID, &common->op_flags)) { 91662306a36Sopenharmony_ci ath_dbg(common, ANY, "Device not present\n"); 91762306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 91862306a36Sopenharmony_ci return; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* Ensure HW is awake when we try to shut it down. */ 92262306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci spin_lock_bh(&sc->sc_pcu_lock); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* prevent tasklets to enable interrupts once we disable them */ 92762306a36Sopenharmony_ci ah->imask &= ~ATH9K_INT_GLOBAL; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* make sure h/w will not generate any interrupt 93062306a36Sopenharmony_ci * before setting the invalid flag. */ 93162306a36Sopenharmony_ci ath9k_hw_disable_interrupts(ah); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci spin_unlock_bh(&sc->sc_pcu_lock); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* we can now sync irq and kill any running tasklets, since we already 93662306a36Sopenharmony_ci * disabled interrupts and not holding a spin lock */ 93762306a36Sopenharmony_ci synchronize_irq(sc->irq); 93862306a36Sopenharmony_ci tasklet_kill(&sc->intr_tq); 93962306a36Sopenharmony_ci tasklet_kill(&sc->bcon_tasklet); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci prev_idle = sc->ps_idle; 94262306a36Sopenharmony_ci sc->ps_idle = true; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci spin_lock_bh(&sc->sc_pcu_lock); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (ah->led_pin >= 0) { 94762306a36Sopenharmony_ci ath9k_hw_set_gpio(ah, ah->led_pin, 94862306a36Sopenharmony_ci (ah->config.led_active_high) ? 0 : 1); 94962306a36Sopenharmony_ci ath9k_hw_gpio_request_in(ah, ah->led_pin, NULL); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci ath_prepare_reset(sc); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci if (sc->rx.frag) { 95562306a36Sopenharmony_ci dev_kfree_skb_any(sc->rx.frag); 95662306a36Sopenharmony_ci sc->rx.frag = NULL; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (!ah->curchan) 96062306a36Sopenharmony_ci ah->curchan = ath9k_cmn_get_channel(hw, ah, 96162306a36Sopenharmony_ci &sc->cur_chan->chandef); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci set_bit(ATH_OP_INVALID, &common->op_flags); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci ath9k_hw_phy_disable(ah); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci ath9k_hw_configpcipowersave(ah, true); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci spin_unlock_bh(&sc->sc_pcu_lock); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci for (i = 0; i < ATH_KEYMAX; i++) 97462306a36Sopenharmony_ci ath9k_pending_key_del(sc, i); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* Clear key cache entries explicitly to get rid of any potentially 97762306a36Sopenharmony_ci * remaining keys. 97862306a36Sopenharmony_ci */ 97962306a36Sopenharmony_ci ath9k_cmn_init_crypto(sc->sc_ah); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci ath9k_ps_restore(sc); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci sc->ps_idle = prev_idle; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Driver halt\n"); 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic bool ath9k_uses_beacons(int type) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci switch (type) { 99362306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 99462306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 99562306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 99662306a36Sopenharmony_ci return true; 99762306a36Sopenharmony_ci default: 99862306a36Sopenharmony_ci return false; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic void ath9k_vif_iter_set_beacon(struct ath9k_vif_iter_data *iter_data, 100362306a36Sopenharmony_ci struct ieee80211_vif *vif) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci /* Use the first (configured) interface, but prefering AP interfaces. */ 100662306a36Sopenharmony_ci if (!iter_data->primary_beacon_vif) { 100762306a36Sopenharmony_ci iter_data->primary_beacon_vif = vif; 100862306a36Sopenharmony_ci } else { 100962306a36Sopenharmony_ci if (iter_data->primary_beacon_vif->type != NL80211_IFTYPE_AP && 101062306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_AP) 101162306a36Sopenharmony_ci iter_data->primary_beacon_vif = vif; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci iter_data->beacons = true; 101562306a36Sopenharmony_ci iter_data->nbcnvifs += 1; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, 101962306a36Sopenharmony_ci u8 *mac, struct ieee80211_vif *vif) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; 102262306a36Sopenharmony_ci int i; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (iter_data->has_hw_macaddr) { 102562306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 102662306a36Sopenharmony_ci iter_data->mask[i] &= 102762306a36Sopenharmony_ci ~(iter_data->hw_macaddr[i] ^ mac[i]); 102862306a36Sopenharmony_ci } else { 102962306a36Sopenharmony_ci memcpy(iter_data->hw_macaddr, mac, ETH_ALEN); 103062306a36Sopenharmony_ci iter_data->has_hw_macaddr = true; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (!vif->bss_conf.use_short_slot) 103462306a36Sopenharmony_ci iter_data->slottime = 20; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci switch (vif->type) { 103762306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 103862306a36Sopenharmony_ci iter_data->naps++; 103962306a36Sopenharmony_ci if (vif->bss_conf.enable_beacon) 104062306a36Sopenharmony_ci ath9k_vif_iter_set_beacon(iter_data, vif); 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 104362306a36Sopenharmony_ci iter_data->nstations++; 104462306a36Sopenharmony_ci if (avp->assoc && !iter_data->primary_sta) 104562306a36Sopenharmony_ci iter_data->primary_sta = vif; 104662306a36Sopenharmony_ci break; 104762306a36Sopenharmony_ci case NL80211_IFTYPE_OCB: 104862306a36Sopenharmony_ci iter_data->nocbs++; 104962306a36Sopenharmony_ci break; 105062306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 105162306a36Sopenharmony_ci iter_data->nadhocs++; 105262306a36Sopenharmony_ci if (vif->bss_conf.enable_beacon) 105362306a36Sopenharmony_ci ath9k_vif_iter_set_beacon(iter_data, vif); 105462306a36Sopenharmony_ci break; 105562306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 105662306a36Sopenharmony_ci iter_data->nmeshes++; 105762306a36Sopenharmony_ci if (vif->bss_conf.enable_beacon) 105862306a36Sopenharmony_ci ath9k_vif_iter_set_beacon(iter_data, vif); 105962306a36Sopenharmony_ci break; 106062306a36Sopenharmony_ci default: 106162306a36Sopenharmony_ci break; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_cistatic void ath9k_update_bssid_mask(struct ath_softc *sc, 106662306a36Sopenharmony_ci struct ath_chanctx *ctx, 106762306a36Sopenharmony_ci struct ath9k_vif_iter_data *iter_data) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 107062306a36Sopenharmony_ci struct ath_vif *avp; 107162306a36Sopenharmony_ci int i; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) 107462306a36Sopenharmony_ci return; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci list_for_each_entry(avp, &ctx->vifs, list) { 107762306a36Sopenharmony_ci if (ctx->nvifs_assigned != 1) 107862306a36Sopenharmony_ci continue; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (!iter_data->has_hw_macaddr) 108162306a36Sopenharmony_ci continue; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci ether_addr_copy(common->curbssid, avp->bssid); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* perm_addr will be used as the p2p device address. */ 108662306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 108762306a36Sopenharmony_ci iter_data->mask[i] &= 108862306a36Sopenharmony_ci ~(iter_data->hw_macaddr[i] ^ 108962306a36Sopenharmony_ci sc->hw->wiphy->perm_addr[i]); 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci/* Called with sc->mutex held. */ 109462306a36Sopenharmony_civoid ath9k_calculate_iter_data(struct ath_softc *sc, 109562306a36Sopenharmony_ci struct ath_chanctx *ctx, 109662306a36Sopenharmony_ci struct ath9k_vif_iter_data *iter_data) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct ath_vif *avp; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* 110162306a36Sopenharmony_ci * The hardware will use primary station addr together with the 110262306a36Sopenharmony_ci * BSSID mask when matching addresses. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_ci memset(iter_data, 0, sizeof(*iter_data)); 110562306a36Sopenharmony_ci eth_broadcast_addr(iter_data->mask); 110662306a36Sopenharmony_ci iter_data->slottime = 9; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci list_for_each_entry(avp, &ctx->vifs, list) 110962306a36Sopenharmony_ci ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci ath9k_update_bssid_mask(sc, ctx, iter_data); 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic void ath9k_set_assoc_state(struct ath_softc *sc, 111562306a36Sopenharmony_ci struct ieee80211_vif *vif, bool changed) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 111862306a36Sopenharmony_ci struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; 111962306a36Sopenharmony_ci unsigned long flags; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci ether_addr_copy(common->curbssid, avp->bssid); 112462306a36Sopenharmony_ci common->curaid = avp->aid; 112562306a36Sopenharmony_ci ath9k_hw_write_associd(sc->sc_ah); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci if (changed) { 112862306a36Sopenharmony_ci common->last_rssi = ATH_RSSI_DUMMY_MARKER; 112962306a36Sopenharmony_ci sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 113262306a36Sopenharmony_ci sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; 113362306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (ath9k_hw_mci_is_enabled(sc->sc_ah)) 113762306a36Sopenharmony_ci ath9k_mci_update_wlan_channels(sc, false); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci ath_dbg(common, CONFIG, 114062306a36Sopenharmony_ci "Primary Station interface: %pM, BSSID: %pM\n", 114162306a36Sopenharmony_ci vif->addr, common->curbssid); 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 114562306a36Sopenharmony_cistatic void ath9k_set_offchannel_state(struct ath_softc *sc) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 114862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 114962306a36Sopenharmony_ci struct ieee80211_vif *vif = NULL; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START) 115462306a36Sopenharmony_ci vif = sc->offchannel.scan_vif; 115562306a36Sopenharmony_ci else 115662306a36Sopenharmony_ci vif = sc->offchannel.roc_vif; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (WARN_ON(!vif)) 115962306a36Sopenharmony_ci goto exit; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci eth_zero_addr(common->curbssid); 116262306a36Sopenharmony_ci eth_broadcast_addr(common->bssidmask); 116362306a36Sopenharmony_ci memcpy(common->macaddr, vif->addr, ETH_ALEN); 116462306a36Sopenharmony_ci common->curaid = 0; 116562306a36Sopenharmony_ci ah->opmode = vif->type; 116662306a36Sopenharmony_ci ah->imask &= ~ATH9K_INT_SWBA; 116762306a36Sopenharmony_ci ah->imask &= ~ATH9K_INT_TSFOOR; 116862306a36Sopenharmony_ci ah->slottime = 9; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci ath_hw_setbssidmask(common); 117162306a36Sopenharmony_ci ath9k_hw_setopmode(ah); 117262306a36Sopenharmony_ci ath9k_hw_write_associd(sc->sc_ah); 117362306a36Sopenharmony_ci ath9k_hw_set_interrupts(ah); 117462306a36Sopenharmony_ci ath9k_hw_init_global_settings(ah); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ciexit: 117762306a36Sopenharmony_ci ath9k_ps_restore(sc); 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci#endif 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci/* Called with sc->mutex held. */ 118262306a36Sopenharmony_civoid ath9k_calculate_summary_state(struct ath_softc *sc, 118362306a36Sopenharmony_ci struct ath_chanctx *ctx) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 118662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 118762306a36Sopenharmony_ci struct ath9k_vif_iter_data iter_data; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci ath_chanctx_check_active(sc, ctx); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (ctx != sc->cur_chan) 119262306a36Sopenharmony_ci return; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 119562306a36Sopenharmony_ci if (ctx == &sc->offchannel.chan) 119662306a36Sopenharmony_ci return ath9k_set_offchannel_state(sc); 119762306a36Sopenharmony_ci#endif 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 120062306a36Sopenharmony_ci ath9k_calculate_iter_data(sc, ctx, &iter_data); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (iter_data.has_hw_macaddr) 120362306a36Sopenharmony_ci memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); 120662306a36Sopenharmony_ci ath_hw_setbssidmask(common); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (iter_data.naps > 0) { 120962306a36Sopenharmony_ci ath9k_hw_set_tsfadjust(ah, true); 121062306a36Sopenharmony_ci ah->opmode = NL80211_IFTYPE_AP; 121162306a36Sopenharmony_ci } else { 121262306a36Sopenharmony_ci ath9k_hw_set_tsfadjust(ah, false); 121362306a36Sopenharmony_ci if (iter_data.beacons) 121462306a36Sopenharmony_ci ath9k_beacon_ensure_primary_slot(sc); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (iter_data.nmeshes) 121762306a36Sopenharmony_ci ah->opmode = NL80211_IFTYPE_MESH_POINT; 121862306a36Sopenharmony_ci else if (iter_data.nocbs) 121962306a36Sopenharmony_ci ah->opmode = NL80211_IFTYPE_OCB; 122062306a36Sopenharmony_ci else if (iter_data.nadhocs) 122162306a36Sopenharmony_ci ah->opmode = NL80211_IFTYPE_ADHOC; 122262306a36Sopenharmony_ci else 122362306a36Sopenharmony_ci ah->opmode = NL80211_IFTYPE_STATION; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci ath9k_hw_setopmode(ah); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci ctx->switch_after_beacon = false; 122962306a36Sopenharmony_ci if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) 123062306a36Sopenharmony_ci ah->imask |= ATH9K_INT_TSFOOR; 123162306a36Sopenharmony_ci else { 123262306a36Sopenharmony_ci ah->imask &= ~ATH9K_INT_TSFOOR; 123362306a36Sopenharmony_ci if (iter_data.naps == 1 && iter_data.beacons) 123462306a36Sopenharmony_ci ctx->switch_after_beacon = true; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci if (ah->opmode == NL80211_IFTYPE_STATION) { 123862306a36Sopenharmony_ci bool changed = (iter_data.primary_sta != ctx->primary_sta); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (iter_data.primary_sta) { 124162306a36Sopenharmony_ci iter_data.primary_beacon_vif = iter_data.primary_sta; 124262306a36Sopenharmony_ci iter_data.beacons = true; 124362306a36Sopenharmony_ci ath9k_set_assoc_state(sc, iter_data.primary_sta, 124462306a36Sopenharmony_ci changed); 124562306a36Sopenharmony_ci ctx->primary_sta = iter_data.primary_sta; 124662306a36Sopenharmony_ci } else { 124762306a36Sopenharmony_ci ctx->primary_sta = NULL; 124862306a36Sopenharmony_ci eth_zero_addr(common->curbssid); 124962306a36Sopenharmony_ci common->curaid = 0; 125062306a36Sopenharmony_ci ath9k_hw_write_associd(sc->sc_ah); 125162306a36Sopenharmony_ci if (ath9k_hw_mci_is_enabled(sc->sc_ah)) 125262306a36Sopenharmony_ci ath9k_mci_update_wlan_channels(sc, true); 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci sc->nbcnvifs = iter_data.nbcnvifs; 125662306a36Sopenharmony_ci ath9k_beacon_config(sc, iter_data.primary_beacon_vif, 125762306a36Sopenharmony_ci iter_data.beacons); 125862306a36Sopenharmony_ci ath9k_hw_set_interrupts(ah); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci if (ah->slottime != iter_data.slottime) { 126162306a36Sopenharmony_ci ah->slottime = iter_data.slottime; 126262306a36Sopenharmony_ci ath9k_hw_init_global_settings(ah); 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (iter_data.primary_sta) 126662306a36Sopenharmony_ci set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); 126762306a36Sopenharmony_ci else 126862306a36Sopenharmony_ci clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci ath_dbg(common, CONFIG, 127162306a36Sopenharmony_ci "macaddr: %pM, bssid: %pM, bssidmask: %pM\n", 127262306a36Sopenharmony_ci common->macaddr, common->curbssid, common->bssidmask); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci ath9k_ps_restore(sc); 127562306a36Sopenharmony_ci} 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_cistatic void ath9k_tpc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci int *power = data; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci if (vif->bss_conf.txpower == INT_MIN) 128262306a36Sopenharmony_ci return; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci if (*power < vif->bss_conf.txpower) 128562306a36Sopenharmony_ci *power = vif->bss_conf.txpower; 128662306a36Sopenharmony_ci} 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci/* Called with sc->mutex held. */ 128962306a36Sopenharmony_civoid ath9k_set_txpower(struct ath_softc *sc, struct ieee80211_vif *vif) 129062306a36Sopenharmony_ci{ 129162306a36Sopenharmony_ci int power; 129262306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 129362306a36Sopenharmony_ci struct ath_regulatory *reg = ath9k_hw_regulatory(ah); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 129662306a36Sopenharmony_ci if (ah->tpc_enabled) { 129762306a36Sopenharmony_ci power = (vif) ? vif->bss_conf.txpower : -1; 129862306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 129962306a36Sopenharmony_ci sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, 130062306a36Sopenharmony_ci ath9k_tpc_vif_iter, &power); 130162306a36Sopenharmony_ci if (power == -1) 130262306a36Sopenharmony_ci power = sc->hw->conf.power_level; 130362306a36Sopenharmony_ci } else { 130462306a36Sopenharmony_ci power = sc->hw->conf.power_level; 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci sc->cur_chan->txpower = 2 * power; 130762306a36Sopenharmony_ci ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); 130862306a36Sopenharmony_ci sc->cur_chan->cur_txpower = reg->max_power_level; 130962306a36Sopenharmony_ci ath9k_ps_restore(sc); 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic void ath9k_assign_hw_queues(struct ieee80211_hw *hw, 131362306a36Sopenharmony_ci struct ieee80211_vif *vif) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci int i; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) 131862306a36Sopenharmony_ci return; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) 132162306a36Sopenharmony_ci vif->hw_queue[i] = i; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP || 132462306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT) 132562306a36Sopenharmony_ci vif->cab_queue = hw->queues - 2; 132662306a36Sopenharmony_ci else 132762306a36Sopenharmony_ci vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic int ath9k_add_interface(struct ieee80211_hw *hw, 133162306a36Sopenharmony_ci struct ieee80211_vif *vif) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 133462306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 133562306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 133662306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 133762306a36Sopenharmony_ci struct ath_node *an = &avp->mcast_node; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 134062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH9K_TX99)) { 134162306a36Sopenharmony_ci if (sc->cur_chan->nvifs >= 1) { 134262306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 134362306a36Sopenharmony_ci return -EOPNOTSUPP; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci sc->tx99_vif = vif; 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); 134962306a36Sopenharmony_ci sc->cur_chan->nvifs++; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && ath9k_is_chanctx_enabled()) 135262306a36Sopenharmony_ci vif->driver_flags |= IEEE80211_VIF_GET_NOA_UPDATE; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci if (ath9k_uses_beacons(vif->type)) 135562306a36Sopenharmony_ci ath9k_beacon_assign_slot(sc, vif); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci avp->vif = vif; 135862306a36Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) { 135962306a36Sopenharmony_ci avp->chanctx = sc->cur_chan; 136062306a36Sopenharmony_ci list_add_tail(&avp->list, &avp->chanctx->vifs); 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci ath9k_calculate_summary_state(sc, avp->chanctx); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci ath9k_assign_hw_queues(hw, vif); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ath9k_set_txpower(sc, vif); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci an->sc = sc; 137062306a36Sopenharmony_ci an->sta = NULL; 137162306a36Sopenharmony_ci an->vif = vif; 137262306a36Sopenharmony_ci an->no_ps_filter = true; 137362306a36Sopenharmony_ci ath_tx_node_init(sc, an); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 137662306a36Sopenharmony_ci return 0; 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic int ath9k_change_interface(struct ieee80211_hw *hw, 138062306a36Sopenharmony_ci struct ieee80211_vif *vif, 138162306a36Sopenharmony_ci enum nl80211_iftype new_type, 138262306a36Sopenharmony_ci bool p2p) 138362306a36Sopenharmony_ci{ 138462306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 138562306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 138662306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci mutex_lock(&sc->mutex); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH9K_TX99)) { 139162306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 139262306a36Sopenharmony_ci return -EOPNOTSUPP; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Change Interface\n"); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (ath9k_uses_beacons(vif->type)) 139862306a36Sopenharmony_ci ath9k_beacon_remove_slot(sc, vif); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci vif->type = new_type; 140162306a36Sopenharmony_ci vif->p2p = p2p; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (ath9k_uses_beacons(vif->type)) 140462306a36Sopenharmony_ci ath9k_beacon_assign_slot(sc, vif); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci ath9k_assign_hw_queues(hw, vif); 140762306a36Sopenharmony_ci ath9k_calculate_summary_state(sc, avp->chanctx); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci ath9k_set_txpower(sc, vif); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 141262306a36Sopenharmony_ci return 0; 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic void ath9k_remove_interface(struct ieee80211_hw *hw, 141662306a36Sopenharmony_ci struct ieee80211_vif *vif) 141762306a36Sopenharmony_ci{ 141862306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 141962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 142062306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Detach Interface\n"); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci mutex_lock(&sc->mutex); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci ath9k_p2p_remove_vif(sc, vif); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci sc->cur_chan->nvifs--; 142962306a36Sopenharmony_ci sc->tx99_vif = NULL; 143062306a36Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) 143162306a36Sopenharmony_ci list_del(&avp->list); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (ath9k_uses_beacons(vif->type)) 143462306a36Sopenharmony_ci ath9k_beacon_remove_slot(sc, vif); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci ath_tx_node_cleanup(sc, &avp->mcast_node); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci ath9k_calculate_summary_state(sc, avp->chanctx); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci ath9k_set_txpower(sc, NULL); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic void ath9k_enable_ps(struct ath_softc *sc) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 144862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH9K_TX99)) 145162306a36Sopenharmony_ci return; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci sc->ps_enabled = true; 145462306a36Sopenharmony_ci if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { 145562306a36Sopenharmony_ci if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { 145662306a36Sopenharmony_ci ah->imask |= ATH9K_INT_TIM_TIMER; 145762306a36Sopenharmony_ci ath9k_hw_set_interrupts(ah); 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci ath9k_hw_setrxabort(ah, 1); 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci ath_dbg(common, PS, "PowerSave enabled\n"); 146262306a36Sopenharmony_ci} 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_cistatic void ath9k_disable_ps(struct ath_softc *sc) 146562306a36Sopenharmony_ci{ 146662306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 146762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH9K_TX99)) 147062306a36Sopenharmony_ci return; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci sc->ps_enabled = false; 147362306a36Sopenharmony_ci ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); 147462306a36Sopenharmony_ci if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { 147562306a36Sopenharmony_ci ath9k_hw_setrxabort(ah, 0); 147662306a36Sopenharmony_ci sc->ps_flags &= ~(PS_WAIT_FOR_BEACON | 147762306a36Sopenharmony_ci PS_WAIT_FOR_CAB | 147862306a36Sopenharmony_ci PS_WAIT_FOR_PSPOLL_DATA | 147962306a36Sopenharmony_ci PS_WAIT_FOR_TX_ACK); 148062306a36Sopenharmony_ci if (ah->imask & ATH9K_INT_TIM_TIMER) { 148162306a36Sopenharmony_ci ah->imask &= ~ATH9K_INT_TIM_TIMER; 148262306a36Sopenharmony_ci ath9k_hw_set_interrupts(ah); 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci ath_dbg(common, PS, "PowerSave disabled\n"); 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_cistatic int ath9k_config(struct ieee80211_hw *hw, u32 changed) 148962306a36Sopenharmony_ci{ 149062306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 149162306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 149262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 149362306a36Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 149462306a36Sopenharmony_ci struct ath_chanctx *ctx = sc->cur_chan; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 149762306a36Sopenharmony_ci mutex_lock(&sc->mutex); 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_IDLE) { 150062306a36Sopenharmony_ci sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); 150162306a36Sopenharmony_ci if (sc->ps_idle) { 150262306a36Sopenharmony_ci ath_cancel_work(sc); 150362306a36Sopenharmony_ci ath9k_stop_btcoex(sc); 150462306a36Sopenharmony_ci } else { 150562306a36Sopenharmony_ci ath9k_start_btcoex(sc); 150662306a36Sopenharmony_ci /* 150762306a36Sopenharmony_ci * The chip needs a reset to properly wake up from 150862306a36Sopenharmony_ci * full sleep 150962306a36Sopenharmony_ci */ 151062306a36Sopenharmony_ci ath_chanctx_set_channel(sc, ctx, &ctx->chandef); 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci /* 151562306a36Sopenharmony_ci * We just prepare to enable PS. We have to wait until our AP has 151662306a36Sopenharmony_ci * ACK'd our null data frame to disable RX otherwise we'll ignore 151762306a36Sopenharmony_ci * those ACKs and end up retransmitting the same null data frames. 151862306a36Sopenharmony_ci * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode. 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_PS) { 152162306a36Sopenharmony_ci unsigned long flags; 152262306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_pm_lock, flags); 152362306a36Sopenharmony_ci if (conf->flags & IEEE80211_CONF_PS) 152462306a36Sopenharmony_ci ath9k_enable_ps(sc); 152562306a36Sopenharmony_ci else 152662306a36Sopenharmony_ci ath9k_disable_ps(sc); 152762306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 153162306a36Sopenharmony_ci if (conf->flags & IEEE80211_CONF_MONITOR) { 153262306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Monitor mode is enabled\n"); 153362306a36Sopenharmony_ci sc->sc_ah->is_monitoring = true; 153462306a36Sopenharmony_ci } else { 153562306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Monitor mode is disabled\n"); 153662306a36Sopenharmony_ci sc->sc_ah->is_monitoring = false; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { 154162306a36Sopenharmony_ci ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL); 154262306a36Sopenharmony_ci ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef); 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_POWER) 154662306a36Sopenharmony_ci ath9k_set_txpower(sc, NULL); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 154962306a36Sopenharmony_ci ath9k_ps_restore(sc); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci return 0; 155262306a36Sopenharmony_ci} 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci#define SUPPORTED_FILTERS \ 155562306a36Sopenharmony_ci (FIF_ALLMULTI | \ 155662306a36Sopenharmony_ci FIF_CONTROL | \ 155762306a36Sopenharmony_ci FIF_PSPOLL | \ 155862306a36Sopenharmony_ci FIF_OTHER_BSS | \ 155962306a36Sopenharmony_ci FIF_BCN_PRBRESP_PROMISC | \ 156062306a36Sopenharmony_ci FIF_PROBE_REQ | \ 156162306a36Sopenharmony_ci FIF_MCAST_ACTION | \ 156262306a36Sopenharmony_ci FIF_FCSFAIL) 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci/* FIXME: sc->sc_full_reset ? */ 156562306a36Sopenharmony_cistatic void ath9k_configure_filter(struct ieee80211_hw *hw, 156662306a36Sopenharmony_ci unsigned int changed_flags, 156762306a36Sopenharmony_ci unsigned int *total_flags, 156862306a36Sopenharmony_ci u64 multicast) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 157162306a36Sopenharmony_ci struct ath_chanctx *ctx; 157262306a36Sopenharmony_ci u32 rfilt; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci *total_flags &= SUPPORTED_FILTERS; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 157762306a36Sopenharmony_ci ath_for_each_chanctx(sc, ctx) 157862306a36Sopenharmony_ci ctx->rxfilter = *total_flags; 157962306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 158062306a36Sopenharmony_ci sc->offchannel.chan.rxfilter = *total_flags; 158162306a36Sopenharmony_ci#endif 158262306a36Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 158562306a36Sopenharmony_ci rfilt = ath_calcrxfilter(sc); 158662306a36Sopenharmony_ci ath9k_hw_setrxfilter(sc->sc_ah, rfilt); 158762306a36Sopenharmony_ci ath9k_ps_restore(sc); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, "Set HW RX filter: 0x%x\n", 159062306a36Sopenharmony_ci rfilt); 159162306a36Sopenharmony_ci} 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_cistatic int ath9k_sta_add(struct ieee80211_hw *hw, 159462306a36Sopenharmony_ci struct ieee80211_vif *vif, 159562306a36Sopenharmony_ci struct ieee80211_sta *sta) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 159862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 159962306a36Sopenharmony_ci struct ath_node *an = (struct ath_node *) sta->drv_priv; 160062306a36Sopenharmony_ci struct ieee80211_key_conf ps_key = { }; 160162306a36Sopenharmony_ci int key; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci ath_node_attach(sc, sta, vif); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP && 160662306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_AP_VLAN) 160762306a36Sopenharmony_ci return 0; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci key = ath_key_config(common, vif, sta, &ps_key); 161062306a36Sopenharmony_ci if (key > 0) { 161162306a36Sopenharmony_ci an->ps_key = key; 161262306a36Sopenharmony_ci an->key_idx[0] = key; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci return 0; 161662306a36Sopenharmony_ci} 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_cistatic void ath9k_del_ps_key(struct ath_softc *sc, 161962306a36Sopenharmony_ci struct ieee80211_vif *vif, 162062306a36Sopenharmony_ci struct ieee80211_sta *sta) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 162362306a36Sopenharmony_ci struct ath_node *an = (struct ath_node *) sta->drv_priv; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci if (!an->ps_key) 162662306a36Sopenharmony_ci return; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci ath_key_delete(common, an->ps_key); 162962306a36Sopenharmony_ci an->ps_key = 0; 163062306a36Sopenharmony_ci an->key_idx[0] = 0; 163162306a36Sopenharmony_ci} 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_cistatic int ath9k_sta_remove(struct ieee80211_hw *hw, 163462306a36Sopenharmony_ci struct ieee80211_vif *vif, 163562306a36Sopenharmony_ci struct ieee80211_sta *sta) 163662306a36Sopenharmony_ci{ 163762306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci ath9k_del_ps_key(sc, vif, sta); 164062306a36Sopenharmony_ci ath_node_detach(sc, sta); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci return 0; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic int ath9k_sta_state(struct ieee80211_hw *hw, 164662306a36Sopenharmony_ci struct ieee80211_vif *vif, 164762306a36Sopenharmony_ci struct ieee80211_sta *sta, 164862306a36Sopenharmony_ci enum ieee80211_sta_state old_state, 164962306a36Sopenharmony_ci enum ieee80211_sta_state new_state) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 165262306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 165362306a36Sopenharmony_ci int ret = 0; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci if (old_state == IEEE80211_STA_NOTEXIST && 165662306a36Sopenharmony_ci new_state == IEEE80211_STA_NONE) { 165762306a36Sopenharmony_ci ret = ath9k_sta_add(hw, vif, sta); 165862306a36Sopenharmony_ci ath_dbg(common, CONFIG, 165962306a36Sopenharmony_ci "Add station: %pM\n", sta->addr); 166062306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_NONE && 166162306a36Sopenharmony_ci new_state == IEEE80211_STA_NOTEXIST) { 166262306a36Sopenharmony_ci ret = ath9k_sta_remove(hw, vif, sta); 166362306a36Sopenharmony_ci ath_dbg(common, CONFIG, 166462306a36Sopenharmony_ci "Remove station: %pM\n", sta->addr); 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) { 166862306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) { 166962306a36Sopenharmony_ci if (old_state == IEEE80211_STA_ASSOC && 167062306a36Sopenharmony_ci new_state == IEEE80211_STA_AUTHORIZED) 167162306a36Sopenharmony_ci ath_chanctx_event(sc, vif, 167262306a36Sopenharmony_ci ATH_CHANCTX_EVENT_AUTHORIZED); 167362306a36Sopenharmony_ci } 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci return ret; 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cistatic void ath9k_sta_set_tx_filter(struct ath_hw *ah, 168062306a36Sopenharmony_ci struct ath_node *an, 168162306a36Sopenharmony_ci bool set) 168262306a36Sopenharmony_ci{ 168362306a36Sopenharmony_ci int i; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { 168662306a36Sopenharmony_ci if (!an->key_idx[i]) 168762306a36Sopenharmony_ci continue; 168862306a36Sopenharmony_ci ath9k_hw_set_tx_filter(ah, an->key_idx[i], set); 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci} 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_cistatic void ath9k_sta_notify(struct ieee80211_hw *hw, 169362306a36Sopenharmony_ci struct ieee80211_vif *vif, 169462306a36Sopenharmony_ci enum sta_notify_cmd cmd, 169562306a36Sopenharmony_ci struct ieee80211_sta *sta) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 169862306a36Sopenharmony_ci struct ath_node *an = (struct ath_node *) sta->drv_priv; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci switch (cmd) { 170162306a36Sopenharmony_ci case STA_NOTIFY_SLEEP: 170262306a36Sopenharmony_ci an->sleeping = true; 170362306a36Sopenharmony_ci ath_tx_aggr_sleep(sta, sc, an); 170462306a36Sopenharmony_ci ath9k_sta_set_tx_filter(sc->sc_ah, an, true); 170562306a36Sopenharmony_ci break; 170662306a36Sopenharmony_ci case STA_NOTIFY_AWAKE: 170762306a36Sopenharmony_ci ath9k_sta_set_tx_filter(sc->sc_ah, an, false); 170862306a36Sopenharmony_ci an->sleeping = false; 170962306a36Sopenharmony_ci ath_tx_aggr_wakeup(sc, an); 171062306a36Sopenharmony_ci break; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci} 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_cistatic int ath9k_conf_tx(struct ieee80211_hw *hw, 171562306a36Sopenharmony_ci struct ieee80211_vif *vif, 171662306a36Sopenharmony_ci unsigned int link_id, u16 queue, 171762306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 172062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 172162306a36Sopenharmony_ci struct ath_txq *txq; 172262306a36Sopenharmony_ci struct ath9k_tx_queue_info qi; 172362306a36Sopenharmony_ci int ret = 0; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci if (queue >= IEEE80211_NUM_ACS) 172662306a36Sopenharmony_ci return 0; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci txq = sc->tx.txq_map[queue]; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 173162306a36Sopenharmony_ci mutex_lock(&sc->mutex); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci qi.tqi_aifs = params->aifs; 173662306a36Sopenharmony_ci qi.tqi_cwmin = params->cw_min; 173762306a36Sopenharmony_ci qi.tqi_cwmax = params->cw_max; 173862306a36Sopenharmony_ci qi.tqi_burstTime = params->txop * 32; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci ath_dbg(common, CONFIG, 174162306a36Sopenharmony_ci "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", 174262306a36Sopenharmony_ci queue, txq->axq_qnum, params->aifs, params->cw_min, 174362306a36Sopenharmony_ci params->cw_max, params->txop); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci ath_update_max_aggr_framelen(sc, queue, qi.tqi_burstTime); 174662306a36Sopenharmony_ci ret = ath_txq_update(sc, txq->axq_qnum, &qi); 174762306a36Sopenharmony_ci if (ret) 174862306a36Sopenharmony_ci ath_err(common, "TXQ Update failed\n"); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 175162306a36Sopenharmony_ci ath9k_ps_restore(sc); 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci return ret; 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic int ath9k_set_key(struct ieee80211_hw *hw, 175762306a36Sopenharmony_ci enum set_key_cmd cmd, 175862306a36Sopenharmony_ci struct ieee80211_vif *vif, 175962306a36Sopenharmony_ci struct ieee80211_sta *sta, 176062306a36Sopenharmony_ci struct ieee80211_key_conf *key) 176162306a36Sopenharmony_ci{ 176262306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 176362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 176462306a36Sopenharmony_ci struct ath_node *an = NULL; 176562306a36Sopenharmony_ci int ret = 0, i; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci if (ath9k_modparam_nohwcrypt) 176862306a36Sopenharmony_ci return -ENOSPC; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_ADHOC || 177162306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT) && 177262306a36Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_TKIP || 177362306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_CCMP) && 177462306a36Sopenharmony_ci !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { 177562306a36Sopenharmony_ci /* 177662306a36Sopenharmony_ci * For now, disable hw crypto for the RSN IBSS group keys. This 177762306a36Sopenharmony_ci * could be optimized in the future to use a modified key cache 177862306a36Sopenharmony_ci * design to support per-STA RX GTK, but until that gets 177962306a36Sopenharmony_ci * implemented, use of software crypto for group addressed 178062306a36Sopenharmony_ci * frames is a acceptable to allow RSN IBSS to be used. 178162306a36Sopenharmony_ci */ 178262306a36Sopenharmony_ci return -EOPNOTSUPP; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci /* There may be MPDUs queued for the outgoing PTK key. Flush queues to 178662306a36Sopenharmony_ci * make sure these are not send unencrypted or with a wrong (new) key 178762306a36Sopenharmony_ci */ 178862306a36Sopenharmony_ci if (cmd == DISABLE_KEY && key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 178962306a36Sopenharmony_ci ieee80211_stop_queues(hw); 179062306a36Sopenharmony_ci ath9k_flush(hw, vif, 0, true); 179162306a36Sopenharmony_ci ieee80211_wake_queues(hw); 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci mutex_lock(&sc->mutex); 179562306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 179662306a36Sopenharmony_ci ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd); 179762306a36Sopenharmony_ci if (sta) 179862306a36Sopenharmony_ci an = (struct ath_node *)sta->drv_priv; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci /* Delete pending key cache entries if no more frames are pointing to 180162306a36Sopenharmony_ci * them in TXQs. 180262306a36Sopenharmony_ci */ 180362306a36Sopenharmony_ci for (i = 0; i < ATH_KEYMAX; i++) 180462306a36Sopenharmony_ci ath9k_pending_key_del(sc, i); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci switch (cmd) { 180762306a36Sopenharmony_ci case SET_KEY: 180862306a36Sopenharmony_ci if (sta) 180962306a36Sopenharmony_ci ath9k_del_ps_key(sc, vif, sta); 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci key->hw_key_idx = 0; 181262306a36Sopenharmony_ci ret = ath_key_config(common, vif, sta, key); 181362306a36Sopenharmony_ci if (ret >= 0) { 181462306a36Sopenharmony_ci key->hw_key_idx = ret; 181562306a36Sopenharmony_ci /* push IV and Michael MIC generation to stack */ 181662306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 181762306a36Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_TKIP) 181862306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; 181962306a36Sopenharmony_ci if (sc->sc_ah->sw_mgmt_crypto_tx && 182062306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_CCMP) 182162306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 182262306a36Sopenharmony_ci ret = 0; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci if (an && key->hw_key_idx) { 182562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { 182662306a36Sopenharmony_ci if (an->key_idx[i]) 182762306a36Sopenharmony_ci continue; 182862306a36Sopenharmony_ci an->key_idx[i] = key->hw_key_idx; 182962306a36Sopenharmony_ci break; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci WARN_ON(i == ARRAY_SIZE(an->key_idx)); 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci break; 183462306a36Sopenharmony_ci case DISABLE_KEY: 183562306a36Sopenharmony_ci if (ath9k_txq_has_key(sc, key->hw_key_idx)) { 183662306a36Sopenharmony_ci /* Delay key cache entry deletion until there are no 183762306a36Sopenharmony_ci * remaining TXQ frames pointing to this entry. 183862306a36Sopenharmony_ci */ 183962306a36Sopenharmony_ci set_bit(key->hw_key_idx, sc->sc_ah->pending_del_keymap); 184062306a36Sopenharmony_ci ath_hw_keysetmac(common, key->hw_key_idx, NULL); 184162306a36Sopenharmony_ci } else { 184262306a36Sopenharmony_ci ath_key_delete(common, key->hw_key_idx); 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci if (an) { 184562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { 184662306a36Sopenharmony_ci if (an->key_idx[i] != key->hw_key_idx) 184762306a36Sopenharmony_ci continue; 184862306a36Sopenharmony_ci an->key_idx[i] = 0; 184962306a36Sopenharmony_ci break; 185062306a36Sopenharmony_ci } 185162306a36Sopenharmony_ci } 185262306a36Sopenharmony_ci key->hw_key_idx = 0; 185362306a36Sopenharmony_ci break; 185462306a36Sopenharmony_ci default: 185562306a36Sopenharmony_ci ret = -EINVAL; 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci ath9k_ps_restore(sc); 185962306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci return ret; 186262306a36Sopenharmony_ci} 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_cistatic void ath9k_bss_info_changed(struct ieee80211_hw *hw, 186562306a36Sopenharmony_ci struct ieee80211_vif *vif, 186662306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf, 186762306a36Sopenharmony_ci u64 changed) 186862306a36Sopenharmony_ci{ 186962306a36Sopenharmony_ci#define CHECK_ANI \ 187062306a36Sopenharmony_ci (BSS_CHANGED_ASSOC | \ 187162306a36Sopenharmony_ci BSS_CHANGED_IBSS | \ 187262306a36Sopenharmony_ci BSS_CHANGED_BEACON_ENABLED) 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 187562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 187662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 187762306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 187862306a36Sopenharmony_ci int slottime; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 188162306a36Sopenharmony_ci mutex_lock(&sc->mutex); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) { 188462306a36Sopenharmony_ci ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", 188562306a36Sopenharmony_ci bss_conf->bssid, vif->cfg.assoc); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); 188862306a36Sopenharmony_ci avp->aid = vif->cfg.aid; 188962306a36Sopenharmony_ci avp->assoc = vif->cfg.assoc; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci ath9k_calculate_summary_state(sc, avp->chanctx); 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci if ((changed & BSS_CHANGED_IBSS) || 189562306a36Sopenharmony_ci (changed & BSS_CHANGED_OCB)) { 189662306a36Sopenharmony_ci memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); 189762306a36Sopenharmony_ci common->curaid = vif->cfg.aid; 189862306a36Sopenharmony_ci ath9k_hw_write_associd(sc->sc_ah); 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci if ((changed & BSS_CHANGED_BEACON_ENABLED) || 190262306a36Sopenharmony_ci (changed & BSS_CHANGED_BEACON_INT) || 190362306a36Sopenharmony_ci (changed & BSS_CHANGED_BEACON_INFO)) { 190462306a36Sopenharmony_ci ath9k_calculate_summary_state(sc, avp->chanctx); 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci if ((avp->chanctx == sc->cur_chan) && 190862306a36Sopenharmony_ci (changed & BSS_CHANGED_ERP_SLOT)) { 190962306a36Sopenharmony_ci if (bss_conf->use_short_slot) 191062306a36Sopenharmony_ci slottime = 9; 191162306a36Sopenharmony_ci else 191262306a36Sopenharmony_ci slottime = 20; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP) { 191562306a36Sopenharmony_ci /* 191662306a36Sopenharmony_ci * Defer update, so that connected stations can adjust 191762306a36Sopenharmony_ci * their settings at the same time. 191862306a36Sopenharmony_ci * See beacon.c for more details 191962306a36Sopenharmony_ci */ 192062306a36Sopenharmony_ci sc->beacon.slottime = slottime; 192162306a36Sopenharmony_ci sc->beacon.updateslot = UPDATE; 192262306a36Sopenharmony_ci } else { 192362306a36Sopenharmony_ci ah->slottime = slottime; 192462306a36Sopenharmony_ci ath9k_hw_init_global_settings(ah); 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci if (changed & BSS_CHANGED_P2P_PS) 192962306a36Sopenharmony_ci ath9k_p2p_bss_info_changed(sc, vif); 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci if (changed & CHECK_ANI) 193262306a36Sopenharmony_ci ath_check_ani(sc); 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci if (changed & BSS_CHANGED_TXPOWER) { 193562306a36Sopenharmony_ci ath_dbg(common, CONFIG, "vif %pM power %d dbm power_type %d\n", 193662306a36Sopenharmony_ci vif->addr, bss_conf->txpower, bss_conf->txpower_type); 193762306a36Sopenharmony_ci ath9k_set_txpower(sc, vif); 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 194162306a36Sopenharmony_ci ath9k_ps_restore(sc); 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci#undef CHECK_ANI 194462306a36Sopenharmony_ci} 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_cistatic u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 194762306a36Sopenharmony_ci{ 194862306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 194962306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 195062306a36Sopenharmony_ci u64 tsf; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci mutex_lock(&sc->mutex); 195362306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 195462306a36Sopenharmony_ci /* Get current TSF either from HW or kernel time. */ 195562306a36Sopenharmony_ci if (sc->cur_chan == avp->chanctx) { 195662306a36Sopenharmony_ci tsf = ath9k_hw_gettsf64(sc->sc_ah); 195762306a36Sopenharmony_ci } else { 195862306a36Sopenharmony_ci tsf = sc->cur_chan->tsf_val + 195962306a36Sopenharmony_ci ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); 196062306a36Sopenharmony_ci } 196162306a36Sopenharmony_ci tsf += le64_to_cpu(avp->tsf_adjust); 196262306a36Sopenharmony_ci ath9k_ps_restore(sc); 196362306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci return tsf; 196662306a36Sopenharmony_ci} 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_cistatic void ath9k_set_tsf(struct ieee80211_hw *hw, 196962306a36Sopenharmony_ci struct ieee80211_vif *vif, 197062306a36Sopenharmony_ci u64 tsf) 197162306a36Sopenharmony_ci{ 197262306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 197362306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci mutex_lock(&sc->mutex); 197662306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 197762306a36Sopenharmony_ci tsf -= le64_to_cpu(avp->tsf_adjust); 197862306a36Sopenharmony_ci ktime_get_raw_ts64(&avp->chanctx->tsf_ts); 197962306a36Sopenharmony_ci if (sc->cur_chan == avp->chanctx) 198062306a36Sopenharmony_ci ath9k_hw_settsf64(sc->sc_ah, tsf); 198162306a36Sopenharmony_ci avp->chanctx->tsf_val = tsf; 198262306a36Sopenharmony_ci ath9k_ps_restore(sc); 198362306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 198462306a36Sopenharmony_ci} 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_cistatic void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 198762306a36Sopenharmony_ci{ 198862306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 198962306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci mutex_lock(&sc->mutex); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 199462306a36Sopenharmony_ci ktime_get_raw_ts64(&avp->chanctx->tsf_ts); 199562306a36Sopenharmony_ci if (sc->cur_chan == avp->chanctx) 199662306a36Sopenharmony_ci ath9k_hw_reset_tsf(sc->sc_ah); 199762306a36Sopenharmony_ci avp->chanctx->tsf_val = 0; 199862306a36Sopenharmony_ci ath9k_ps_restore(sc); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 200162306a36Sopenharmony_ci} 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_cistatic int ath9k_ampdu_action(struct ieee80211_hw *hw, 200462306a36Sopenharmony_ci struct ieee80211_vif *vif, 200562306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 200662306a36Sopenharmony_ci{ 200762306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 200862306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 200962306a36Sopenharmony_ci bool flush = false; 201062306a36Sopenharmony_ci int ret = 0; 201162306a36Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 201262306a36Sopenharmony_ci struct ath_node *an = (struct ath_node *)sta->drv_priv; 201362306a36Sopenharmony_ci enum ieee80211_ampdu_mlme_action action = params->action; 201462306a36Sopenharmony_ci u16 tid = params->tid; 201562306a36Sopenharmony_ci u16 *ssn = ¶ms->ssn; 201662306a36Sopenharmony_ci struct ath_atx_tid *atid; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci mutex_lock(&sc->mutex); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci switch (action) { 202162306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 202262306a36Sopenharmony_ci break; 202362306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 202462306a36Sopenharmony_ci break; 202562306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 202662306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) { 202762306a36Sopenharmony_ci if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { 202862306a36Sopenharmony_ci ret = -EBUSY; 202962306a36Sopenharmony_ci break; 203062306a36Sopenharmony_ci } 203162306a36Sopenharmony_ci } 203262306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 203362306a36Sopenharmony_ci ret = ath_tx_aggr_start(sc, sta, tid, ssn); 203462306a36Sopenharmony_ci if (!ret) 203562306a36Sopenharmony_ci ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 203662306a36Sopenharmony_ci ath9k_ps_restore(sc); 203762306a36Sopenharmony_ci break; 203862306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 203962306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 204062306a36Sopenharmony_ci flush = true; 204162306a36Sopenharmony_ci fallthrough; 204262306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 204362306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 204462306a36Sopenharmony_ci ath_tx_aggr_stop(sc, sta, tid); 204562306a36Sopenharmony_ci if (!flush) 204662306a36Sopenharmony_ci ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 204762306a36Sopenharmony_ci ath9k_ps_restore(sc); 204862306a36Sopenharmony_ci break; 204962306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 205062306a36Sopenharmony_ci atid = ath_node_to_tid(an, tid); 205162306a36Sopenharmony_ci atid->baw_size = IEEE80211_MIN_AMPDU_BUF << 205262306a36Sopenharmony_ci sta->deflink.ht_cap.ampdu_factor; 205362306a36Sopenharmony_ci break; 205462306a36Sopenharmony_ci default: 205562306a36Sopenharmony_ci ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); 205662306a36Sopenharmony_ci } 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci return ret; 206162306a36Sopenharmony_ci} 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_cistatic int ath9k_get_survey(struct ieee80211_hw *hw, int idx, 206462306a36Sopenharmony_ci struct survey_info *survey) 206562306a36Sopenharmony_ci{ 206662306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 206762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 206862306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 206962306a36Sopenharmony_ci struct ieee80211_channel *chan; 207062306a36Sopenharmony_ci unsigned long flags; 207162306a36Sopenharmony_ci int pos; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH9K_TX99)) 207462306a36Sopenharmony_ci return -EOPNOTSUPP; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci spin_lock_irqsave(&common->cc_lock, flags); 207762306a36Sopenharmony_ci if (idx == 0) 207862306a36Sopenharmony_ci ath_update_survey_stats(sc); 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci sband = hw->wiphy->bands[NL80211_BAND_2GHZ]; 208162306a36Sopenharmony_ci if (sband && idx >= sband->n_channels) { 208262306a36Sopenharmony_ci idx -= sband->n_channels; 208362306a36Sopenharmony_ci sband = NULL; 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci if (!sband) 208762306a36Sopenharmony_ci sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci if (!sband || idx >= sband->n_channels) { 209062306a36Sopenharmony_ci spin_unlock_irqrestore(&common->cc_lock, flags); 209162306a36Sopenharmony_ci return -ENOENT; 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci chan = &sband->channels[idx]; 209562306a36Sopenharmony_ci pos = chan->hw_value; 209662306a36Sopenharmony_ci memcpy(survey, &sc->survey[pos], sizeof(*survey)); 209762306a36Sopenharmony_ci survey->channel = chan; 209862306a36Sopenharmony_ci spin_unlock_irqrestore(&common->cc_lock, flags); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci return 0; 210162306a36Sopenharmony_ci} 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_cistatic void ath9k_enable_dynack(struct ath_softc *sc) 210462306a36Sopenharmony_ci{ 210562306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_DYNACK 210662306a36Sopenharmony_ci u32 rfilt; 210762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci ath_dynack_reset(ah); 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci ah->dynack.enabled = true; 211262306a36Sopenharmony_ci rfilt = ath_calcrxfilter(sc); 211362306a36Sopenharmony_ci ath9k_hw_setrxfilter(ah, rfilt); 211462306a36Sopenharmony_ci#endif 211562306a36Sopenharmony_ci} 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_cistatic void ath9k_set_coverage_class(struct ieee80211_hw *hw, 211862306a36Sopenharmony_ci s16 coverage_class) 211962306a36Sopenharmony_ci{ 212062306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 212162306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH9K_TX99)) 212462306a36Sopenharmony_ci return; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci mutex_lock(&sc->mutex); 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci if (coverage_class >= 0) { 212962306a36Sopenharmony_ci ah->coverage_class = coverage_class; 213062306a36Sopenharmony_ci if (ah->dynack.enabled) { 213162306a36Sopenharmony_ci u32 rfilt; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci ah->dynack.enabled = false; 213462306a36Sopenharmony_ci rfilt = ath_calcrxfilter(sc); 213562306a36Sopenharmony_ci ath9k_hw_setrxfilter(ah, rfilt); 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 213862306a36Sopenharmony_ci ath9k_hw_init_global_settings(ah); 213962306a36Sopenharmony_ci ath9k_ps_restore(sc); 214062306a36Sopenharmony_ci } else if (!ah->dynack.enabled) { 214162306a36Sopenharmony_ci ath9k_enable_dynack(sc); 214262306a36Sopenharmony_ci } 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 214562306a36Sopenharmony_ci} 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_cistatic bool ath9k_has_tx_pending(struct ath_softc *sc, 214862306a36Sopenharmony_ci bool sw_pending) 214962306a36Sopenharmony_ci{ 215062306a36Sopenharmony_ci int i, npend = 0; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { 215362306a36Sopenharmony_ci if (!ATH_TXQ_SETUP(sc, i)) 215462306a36Sopenharmony_ci continue; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i], 215762306a36Sopenharmony_ci sw_pending); 215862306a36Sopenharmony_ci if (npend) 215962306a36Sopenharmony_ci break; 216062306a36Sopenharmony_ci } 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci return !!npend; 216362306a36Sopenharmony_ci} 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_cistatic void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 216662306a36Sopenharmony_ci u32 queues, bool drop) 216762306a36Sopenharmony_ci{ 216862306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 216962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) { 217262306a36Sopenharmony_ci if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) 217362306a36Sopenharmony_ci goto flush; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci /* 217662306a36Sopenharmony_ci * If MCC is active, extend the flush timeout 217762306a36Sopenharmony_ci * and wait for the HW/SW queues to become 217862306a36Sopenharmony_ci * empty. This needs to be done outside the 217962306a36Sopenharmony_ci * sc->mutex lock to allow the channel scheduler 218062306a36Sopenharmony_ci * to switch channel contexts. 218162306a36Sopenharmony_ci * 218262306a36Sopenharmony_ci * The vif queues have been stopped in mac80211, 218362306a36Sopenharmony_ci * so there won't be any incoming frames. 218462306a36Sopenharmony_ci */ 218562306a36Sopenharmony_ci __ath9k_flush(hw, queues, drop, true, true); 218662306a36Sopenharmony_ci return; 218762306a36Sopenharmony_ci } 218862306a36Sopenharmony_ciflush: 218962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 219062306a36Sopenharmony_ci __ath9k_flush(hw, queues, drop, true, false); 219162306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_civoid __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop, 219562306a36Sopenharmony_ci bool sw_pending, bool timeout_override) 219662306a36Sopenharmony_ci{ 219762306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 219862306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 219962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 220062306a36Sopenharmony_ci int timeout; 220162306a36Sopenharmony_ci bool drain_txq; 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci cancel_delayed_work_sync(&sc->hw_check_work); 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci if (ah->ah_flags & AH_UNPLUGGED) { 220662306a36Sopenharmony_ci ath_dbg(common, ANY, "Device has been unplugged!\n"); 220762306a36Sopenharmony_ci return; 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci if (test_bit(ATH_OP_INVALID, &common->op_flags)) { 221162306a36Sopenharmony_ci ath_dbg(common, ANY, "Device not present\n"); 221262306a36Sopenharmony_ci return; 221362306a36Sopenharmony_ci } 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 221662306a36Sopenharmony_ci if (timeout_override) 221762306a36Sopenharmony_ci timeout = HZ / 5; 221862306a36Sopenharmony_ci else 221962306a36Sopenharmony_ci timeout = sc->cur_chan->flush_timeout; 222062306a36Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 222362306a36Sopenharmony_ci "Flush timeout: %d\n", jiffies_to_msecs(timeout)); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc, sw_pending), 222662306a36Sopenharmony_ci timeout) > 0) 222762306a36Sopenharmony_ci drop = false; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci if (drop) { 223062306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 223162306a36Sopenharmony_ci spin_lock_bh(&sc->sc_pcu_lock); 223262306a36Sopenharmony_ci drain_txq = ath_drain_all_txq(sc); 223362306a36Sopenharmony_ci spin_unlock_bh(&sc->sc_pcu_lock); 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci if (!drain_txq) 223662306a36Sopenharmony_ci ath_reset(sc, NULL); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci ath9k_ps_restore(sc); 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci ieee80211_queue_delayed_work(hw, &sc->hw_check_work, 224262306a36Sopenharmony_ci msecs_to_jiffies(ATH_HW_CHECK_POLL_INT)); 224362306a36Sopenharmony_ci} 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_cistatic bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) 224662306a36Sopenharmony_ci{ 224762306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci return ath9k_has_tx_pending(sc, true); 225062306a36Sopenharmony_ci} 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_cistatic int ath9k_tx_last_beacon(struct ieee80211_hw *hw) 225362306a36Sopenharmony_ci{ 225462306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 225562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 225662306a36Sopenharmony_ci struct ieee80211_vif *vif; 225762306a36Sopenharmony_ci struct ath_vif *avp; 225862306a36Sopenharmony_ci struct ath_buf *bf; 225962306a36Sopenharmony_ci struct ath_tx_status ts; 226062306a36Sopenharmony_ci bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); 226162306a36Sopenharmony_ci int status; 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci vif = sc->beacon.bslot[0]; 226462306a36Sopenharmony_ci if (!vif) 226562306a36Sopenharmony_ci return 0; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci if (!vif->bss_conf.enable_beacon) 226862306a36Sopenharmony_ci return 0; 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci avp = (void *)vif->drv_priv; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci if (!sc->beacon.tx_processed && !edma) { 227362306a36Sopenharmony_ci tasklet_disable(&sc->bcon_tasklet); 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci bf = avp->av_bcbuf; 227662306a36Sopenharmony_ci if (!bf || !bf->bf_mpdu) 227762306a36Sopenharmony_ci goto skip; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts); 228062306a36Sopenharmony_ci if (status == -EINPROGRESS) 228162306a36Sopenharmony_ci goto skip; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci sc->beacon.tx_processed = true; 228462306a36Sopenharmony_ci sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ciskip: 228762306a36Sopenharmony_ci tasklet_enable(&sc->bcon_tasklet); 228862306a36Sopenharmony_ci } 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci return sc->beacon.tx_last; 229162306a36Sopenharmony_ci} 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_cistatic int ath9k_get_stats(struct ieee80211_hw *hw, 229462306a36Sopenharmony_ci struct ieee80211_low_level_stats *stats) 229562306a36Sopenharmony_ci{ 229662306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 229762306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 229862306a36Sopenharmony_ci struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats; 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci stats->dot11ACKFailureCount = mib_stats->ackrcv_bad; 230162306a36Sopenharmony_ci stats->dot11RTSFailureCount = mib_stats->rts_bad; 230262306a36Sopenharmony_ci stats->dot11FCSErrorCount = mib_stats->fcs_bad; 230362306a36Sopenharmony_ci stats->dot11RTSSuccessCount = mib_stats->rts_good; 230462306a36Sopenharmony_ci return 0; 230562306a36Sopenharmony_ci} 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_cistatic u32 fill_chainmask(u32 cap, u32 new) 230862306a36Sopenharmony_ci{ 230962306a36Sopenharmony_ci u32 filled = 0; 231062306a36Sopenharmony_ci int i; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci for (i = 0; cap && new; i++, cap >>= 1) { 231362306a36Sopenharmony_ci if (!(cap & BIT(0))) 231462306a36Sopenharmony_ci continue; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci if (new & BIT(0)) 231762306a36Sopenharmony_ci filled |= BIT(i); 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci new >>= 1; 232062306a36Sopenharmony_ci } 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci return filled; 232362306a36Sopenharmony_ci} 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_cistatic bool validate_antenna_mask(struct ath_hw *ah, u32 val) 232662306a36Sopenharmony_ci{ 232762306a36Sopenharmony_ci if (AR_SREV_9300_20_OR_LATER(ah)) 232862306a36Sopenharmony_ci return true; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci switch (val & 0x7) { 233162306a36Sopenharmony_ci case 0x1: 233262306a36Sopenharmony_ci case 0x3: 233362306a36Sopenharmony_ci case 0x7: 233462306a36Sopenharmony_ci return true; 233562306a36Sopenharmony_ci case 0x2: 233662306a36Sopenharmony_ci return (ah->caps.rx_chainmask == 1); 233762306a36Sopenharmony_ci default: 233862306a36Sopenharmony_ci return false; 233962306a36Sopenharmony_ci } 234062306a36Sopenharmony_ci} 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_cistatic int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 234562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci if (ah->caps.rx_chainmask != 1) 234862306a36Sopenharmony_ci rx_ant |= tx_ant; 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci if (!validate_antenna_mask(ah, rx_ant) || !tx_ant) 235162306a36Sopenharmony_ci return -EINVAL; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci sc->ant_rx = rx_ant; 235462306a36Sopenharmony_ci sc->ant_tx = tx_ant; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci if (ah->caps.rx_chainmask == 1) 235762306a36Sopenharmony_ci return 0; 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci /* AR9100 runs into calibration issues if not all rx chains are enabled */ 236062306a36Sopenharmony_ci if (AR_SREV_9100(ah)) 236162306a36Sopenharmony_ci ah->rxchainmask = 0x7; 236262306a36Sopenharmony_ci else 236362306a36Sopenharmony_ci ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant); 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); 236662306a36Sopenharmony_ci ath9k_cmn_reload_chainmask(ah); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci return 0; 236962306a36Sopenharmony_ci} 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_cistatic int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 237262306a36Sopenharmony_ci{ 237362306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci *tx_ant = sc->ant_tx; 237662306a36Sopenharmony_ci *rx_ant = sc->ant_rx; 237762306a36Sopenharmony_ci return 0; 237862306a36Sopenharmony_ci} 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_cistatic void ath9k_sw_scan_start(struct ieee80211_hw *hw, 238162306a36Sopenharmony_ci struct ieee80211_vif *vif, 238262306a36Sopenharmony_ci const u8 *mac_addr) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 238562306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 238662306a36Sopenharmony_ci set_bit(ATH_OP_SCANNING, &common->op_flags); 238762306a36Sopenharmony_ci} 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_cistatic void ath9k_sw_scan_complete(struct ieee80211_hw *hw, 239062306a36Sopenharmony_ci struct ieee80211_vif *vif) 239162306a36Sopenharmony_ci{ 239262306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 239362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 239462306a36Sopenharmony_ci clear_bit(ATH_OP_SCANNING, &common->op_flags); 239562306a36Sopenharmony_ci} 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_cistatic void ath9k_cancel_pending_offchannel(struct ath_softc *sc) 240062306a36Sopenharmony_ci{ 240162306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci if (sc->offchannel.roc_vif) { 240462306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 240562306a36Sopenharmony_ci "%s: Aborting RoC\n", __func__); 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci del_timer_sync(&sc->offchannel.timer); 240862306a36Sopenharmony_ci if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) 240962306a36Sopenharmony_ci ath_roc_complete(sc, ATH_ROC_COMPLETE_ABORT); 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { 241362306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 241462306a36Sopenharmony_ci "%s: Aborting HW scan\n", __func__); 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci del_timer_sync(&sc->offchannel.timer); 241762306a36Sopenharmony_ci ath_scan_complete(sc, true); 241862306a36Sopenharmony_ci } 241962306a36Sopenharmony_ci} 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_cistatic int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 242262306a36Sopenharmony_ci struct ieee80211_scan_request *hw_req) 242362306a36Sopenharmony_ci{ 242462306a36Sopenharmony_ci struct cfg80211_scan_request *req = &hw_req->req; 242562306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 242662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 242762306a36Sopenharmony_ci int ret = 0; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci if (WARN_ON(sc->offchannel.scan_req)) { 243262306a36Sopenharmony_ci ret = -EBUSY; 243362306a36Sopenharmony_ci goto out; 243462306a36Sopenharmony_ci } 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 243762306a36Sopenharmony_ci set_bit(ATH_OP_SCANNING, &common->op_flags); 243862306a36Sopenharmony_ci sc->offchannel.scan_vif = vif; 243962306a36Sopenharmony_ci sc->offchannel.scan_req = req; 244062306a36Sopenharmony_ci sc->offchannel.scan_idx = 0; 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n", 244362306a36Sopenharmony_ci vif->addr); 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) { 244662306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, "Starting HW scan\n"); 244762306a36Sopenharmony_ci ath_offchannel_next(sc); 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ciout: 245162306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci return ret; 245462306a36Sopenharmony_ci} 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_cistatic void ath9k_cancel_hw_scan(struct ieee80211_hw *hw, 245762306a36Sopenharmony_ci struct ieee80211_vif *vif) 245862306a36Sopenharmony_ci{ 245962306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 246062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr); 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci mutex_lock(&sc->mutex); 246562306a36Sopenharmony_ci del_timer_sync(&sc->offchannel.timer); 246662306a36Sopenharmony_ci ath_scan_complete(sc, true); 246762306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 246862306a36Sopenharmony_ci} 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_cistatic int ath9k_remain_on_channel(struct ieee80211_hw *hw, 247162306a36Sopenharmony_ci struct ieee80211_vif *vif, 247262306a36Sopenharmony_ci struct ieee80211_channel *chan, int duration, 247362306a36Sopenharmony_ci enum ieee80211_roc_type type) 247462306a36Sopenharmony_ci{ 247562306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 247662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 247762306a36Sopenharmony_ci int ret = 0; 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci if (WARN_ON(sc->offchannel.roc_vif)) { 248262306a36Sopenharmony_ci ret = -EBUSY; 248362306a36Sopenharmony_ci goto out; 248462306a36Sopenharmony_ci } 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 248762306a36Sopenharmony_ci sc->offchannel.roc_vif = vif; 248862306a36Sopenharmony_ci sc->offchannel.roc_chan = chan; 248962306a36Sopenharmony_ci sc->offchannel.roc_duration = duration; 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 249262306a36Sopenharmony_ci "RoC request on vif: %pM, type: %d duration: %d\n", 249362306a36Sopenharmony_ci vif->addr, type, duration); 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) { 249662306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, "Starting RoC period\n"); 249762306a36Sopenharmony_ci ath_offchannel_next(sc); 249862306a36Sopenharmony_ci } 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ciout: 250162306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci return ret; 250462306a36Sopenharmony_ci} 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_cistatic int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw, 250762306a36Sopenharmony_ci struct ieee80211_vif *vif) 250862306a36Sopenharmony_ci{ 250962306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 251062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci mutex_lock(&sc->mutex); 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, "Cancel RoC\n"); 251562306a36Sopenharmony_ci del_timer_sync(&sc->offchannel.timer); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci if (sc->offchannel.roc_vif) { 251862306a36Sopenharmony_ci if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) 251962306a36Sopenharmony_ci ath_roc_complete(sc, ATH_ROC_COMPLETE_CANCEL); 252062306a36Sopenharmony_ci } 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci return 0; 252562306a36Sopenharmony_ci} 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_cistatic int ath9k_add_chanctx(struct ieee80211_hw *hw, 252862306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf) 252962306a36Sopenharmony_ci{ 253062306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 253162306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 253262306a36Sopenharmony_ci struct ath_chanctx *ctx, **ptr; 253362306a36Sopenharmony_ci int pos; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci mutex_lock(&sc->mutex); 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci ath_for_each_chanctx(sc, ctx) { 253862306a36Sopenharmony_ci if (ctx->assigned) 253962306a36Sopenharmony_ci continue; 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci ptr = (void *) conf->drv_priv; 254262306a36Sopenharmony_ci *ptr = ctx; 254362306a36Sopenharmony_ci ctx->assigned = true; 254462306a36Sopenharmony_ci pos = ctx - &sc->chanctx[0]; 254562306a36Sopenharmony_ci ctx->hw_queue_base = pos * IEEE80211_NUM_ACS; 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 254862306a36Sopenharmony_ci "Add channel context: %d MHz\n", 254962306a36Sopenharmony_ci conf->def.chan->center_freq); 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci ath_chanctx_set_channel(sc, ctx, &conf->def); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 255462306a36Sopenharmony_ci return 0; 255562306a36Sopenharmony_ci } 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 255862306a36Sopenharmony_ci return -ENOSPC; 255962306a36Sopenharmony_ci} 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_cistatic void ath9k_remove_chanctx(struct ieee80211_hw *hw, 256362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf) 256462306a36Sopenharmony_ci{ 256562306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 256662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 256762306a36Sopenharmony_ci struct ath_chanctx *ctx = ath_chanctx_get(conf); 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 257262306a36Sopenharmony_ci "Remove channel context: %d MHz\n", 257362306a36Sopenharmony_ci conf->def.chan->center_freq); 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci ctx->assigned = false; 257662306a36Sopenharmony_ci ctx->hw_queue_base = 0; 257762306a36Sopenharmony_ci ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN); 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 258062306a36Sopenharmony_ci} 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_cistatic void ath9k_change_chanctx(struct ieee80211_hw *hw, 258362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf, 258462306a36Sopenharmony_ci u32 changed) 258562306a36Sopenharmony_ci{ 258662306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 258762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 258862306a36Sopenharmony_ci struct ath_chanctx *ctx = ath_chanctx_get(conf); 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci mutex_lock(&sc->mutex); 259162306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 259262306a36Sopenharmony_ci "Change channel context: %d MHz\n", 259362306a36Sopenharmony_ci conf->def.chan->center_freq); 259462306a36Sopenharmony_ci ath_chanctx_set_channel(sc, ctx, &conf->def); 259562306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 259662306a36Sopenharmony_ci} 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_cistatic int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, 259962306a36Sopenharmony_ci struct ieee80211_vif *vif, 260062306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 260162306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf) 260262306a36Sopenharmony_ci{ 260362306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 260462306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 260562306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 260662306a36Sopenharmony_ci struct ath_chanctx *ctx = ath_chanctx_get(conf); 260762306a36Sopenharmony_ci int i; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci ath9k_cancel_pending_offchannel(sc); 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci mutex_lock(&sc->mutex); 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 261462306a36Sopenharmony_ci "Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n", 261562306a36Sopenharmony_ci vif->addr, vif->type, vif->p2p, 261662306a36Sopenharmony_ci conf->def.chan->center_freq); 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci avp->chanctx = ctx; 261962306a36Sopenharmony_ci ctx->nvifs_assigned++; 262062306a36Sopenharmony_ci list_add_tail(&avp->list, &ctx->vifs); 262162306a36Sopenharmony_ci ath9k_calculate_summary_state(sc, ctx); 262262306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) 262362306a36Sopenharmony_ci vif->hw_queue[i] = ctx->hw_queue_base + i; 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci return 0; 262862306a36Sopenharmony_ci} 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_cistatic void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, 263162306a36Sopenharmony_ci struct ieee80211_vif *vif, 263262306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 263362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf) 263462306a36Sopenharmony_ci{ 263562306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 263662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 263762306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 263862306a36Sopenharmony_ci struct ath_chanctx *ctx = ath_chanctx_get(conf); 263962306a36Sopenharmony_ci int ac; 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci ath9k_cancel_pending_offchannel(sc); 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci mutex_lock(&sc->mutex); 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 264662306a36Sopenharmony_ci "Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n", 264762306a36Sopenharmony_ci vif->addr, vif->type, vif->p2p, 264862306a36Sopenharmony_ci conf->def.chan->center_freq); 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci avp->chanctx = NULL; 265162306a36Sopenharmony_ci ctx->nvifs_assigned--; 265262306a36Sopenharmony_ci list_del(&avp->list); 265362306a36Sopenharmony_ci ath9k_calculate_summary_state(sc, ctx); 265462306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 265562306a36Sopenharmony_ci vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE; 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 265862306a36Sopenharmony_ci} 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_cistatic void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, 266162306a36Sopenharmony_ci struct ieee80211_vif *vif, 266262306a36Sopenharmony_ci struct ieee80211_prep_tx_info *info) 266362306a36Sopenharmony_ci{ 266462306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 266562306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 266662306a36Sopenharmony_ci struct ath_vif *avp = (struct ath_vif *) vif->drv_priv; 266762306a36Sopenharmony_ci struct ath_beacon_config *cur_conf; 266862306a36Sopenharmony_ci struct ath_chanctx *go_ctx; 266962306a36Sopenharmony_ci unsigned long timeout; 267062306a36Sopenharmony_ci bool changed = false; 267162306a36Sopenharmony_ci u32 beacon_int; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) 267462306a36Sopenharmony_ci return; 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci if (!avp->chanctx) 267762306a36Sopenharmony_ci return; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 268262306a36Sopenharmony_ci if (sc->next_chan || (sc->cur_chan != avp->chanctx)) 268362306a36Sopenharmony_ci changed = true; 268462306a36Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci if (!changed) 268762306a36Sopenharmony_ci goto out; 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci ath9k_cancel_pending_offchannel(sc); 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci go_ctx = ath_is_go_chanctx_present(sc); 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci if (go_ctx) { 269462306a36Sopenharmony_ci /* 269562306a36Sopenharmony_ci * Wait till the GO interface gets a chance 269662306a36Sopenharmony_ci * to send out an NoA. 269762306a36Sopenharmony_ci */ 269862306a36Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 269962306a36Sopenharmony_ci sc->sched.mgd_prepare_tx = true; 270062306a36Sopenharmony_ci cur_conf = &go_ctx->beacon; 270162306a36Sopenharmony_ci beacon_int = TU_TO_USEC(cur_conf->beacon_interval); 270262306a36Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci timeout = usecs_to_jiffies(beacon_int * 2); 270562306a36Sopenharmony_ci init_completion(&sc->go_beacon); 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci if (wait_for_completion_timeout(&sc->go_beacon, 271062306a36Sopenharmony_ci timeout) == 0) { 271162306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 271262306a36Sopenharmony_ci "Failed to send new NoA\n"); 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 271562306a36Sopenharmony_ci sc->sched.mgd_prepare_tx = false; 271662306a36Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 271762306a36Sopenharmony_ci } 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci mutex_lock(&sc->mutex); 272062306a36Sopenharmony_ci } 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, 272362306a36Sopenharmony_ci "%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n", 272462306a36Sopenharmony_ci __func__, vif->addr); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci spin_lock_bh(&sc->chan_lock); 272762306a36Sopenharmony_ci sc->next_chan = avp->chanctx; 272862306a36Sopenharmony_ci sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; 272962306a36Sopenharmony_ci spin_unlock_bh(&sc->chan_lock); 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci ath_chanctx_set_next(sc, true); 273262306a36Sopenharmony_ciout: 273362306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 273462306a36Sopenharmony_ci} 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_civoid ath9k_fill_chanctx_ops(void) 273762306a36Sopenharmony_ci{ 273862306a36Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) 273962306a36Sopenharmony_ci return; 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci ath9k_ops.hw_scan = ath9k_hw_scan; 274262306a36Sopenharmony_ci ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; 274362306a36Sopenharmony_ci ath9k_ops.remain_on_channel = ath9k_remain_on_channel; 274462306a36Sopenharmony_ci ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel; 274562306a36Sopenharmony_ci ath9k_ops.add_chanctx = ath9k_add_chanctx; 274662306a36Sopenharmony_ci ath9k_ops.remove_chanctx = ath9k_remove_chanctx; 274762306a36Sopenharmony_ci ath9k_ops.change_chanctx = ath9k_change_chanctx; 274862306a36Sopenharmony_ci ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; 274962306a36Sopenharmony_ci ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; 275062306a36Sopenharmony_ci ath9k_ops.mgd_prepare_tx = ath9k_mgd_prepare_tx; 275162306a36Sopenharmony_ci} 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci#endif 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_cistatic int ath9k_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 275662306a36Sopenharmony_ci int *dbm) 275762306a36Sopenharmony_ci{ 275862306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 275962306a36Sopenharmony_ci struct ath_vif *avp = (void *)vif->drv_priv; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci mutex_lock(&sc->mutex); 276262306a36Sopenharmony_ci if (avp->chanctx) 276362306a36Sopenharmony_ci *dbm = avp->chanctx->cur_txpower; 276462306a36Sopenharmony_ci else 276562306a36Sopenharmony_ci *dbm = sc->cur_chan->cur_txpower; 276662306a36Sopenharmony_ci mutex_unlock(&sc->mutex); 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci *dbm /= 2; 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci return 0; 277162306a36Sopenharmony_ci} 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_cistruct ieee80211_ops ath9k_ops = { 277462306a36Sopenharmony_ci .tx = ath9k_tx, 277562306a36Sopenharmony_ci .start = ath9k_start, 277662306a36Sopenharmony_ci .stop = ath9k_stop, 277762306a36Sopenharmony_ci .add_interface = ath9k_add_interface, 277862306a36Sopenharmony_ci .change_interface = ath9k_change_interface, 277962306a36Sopenharmony_ci .remove_interface = ath9k_remove_interface, 278062306a36Sopenharmony_ci .config = ath9k_config, 278162306a36Sopenharmony_ci .configure_filter = ath9k_configure_filter, 278262306a36Sopenharmony_ci .sta_state = ath9k_sta_state, 278362306a36Sopenharmony_ci .sta_notify = ath9k_sta_notify, 278462306a36Sopenharmony_ci .conf_tx = ath9k_conf_tx, 278562306a36Sopenharmony_ci .bss_info_changed = ath9k_bss_info_changed, 278662306a36Sopenharmony_ci .set_key = ath9k_set_key, 278762306a36Sopenharmony_ci .get_tsf = ath9k_get_tsf, 278862306a36Sopenharmony_ci .set_tsf = ath9k_set_tsf, 278962306a36Sopenharmony_ci .reset_tsf = ath9k_reset_tsf, 279062306a36Sopenharmony_ci .ampdu_action = ath9k_ampdu_action, 279162306a36Sopenharmony_ci .get_survey = ath9k_get_survey, 279262306a36Sopenharmony_ci .rfkill_poll = ath9k_rfkill_poll_state, 279362306a36Sopenharmony_ci .set_coverage_class = ath9k_set_coverage_class, 279462306a36Sopenharmony_ci .flush = ath9k_flush, 279562306a36Sopenharmony_ci .tx_frames_pending = ath9k_tx_frames_pending, 279662306a36Sopenharmony_ci .tx_last_beacon = ath9k_tx_last_beacon, 279762306a36Sopenharmony_ci .release_buffered_frames = ath9k_release_buffered_frames, 279862306a36Sopenharmony_ci .get_stats = ath9k_get_stats, 279962306a36Sopenharmony_ci .set_antenna = ath9k_set_antenna, 280062306a36Sopenharmony_ci .get_antenna = ath9k_get_antenna, 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_WOW 280362306a36Sopenharmony_ci .suspend = ath9k_suspend, 280462306a36Sopenharmony_ci .resume = ath9k_resume, 280562306a36Sopenharmony_ci .set_wakeup = ath9k_set_wakeup, 280662306a36Sopenharmony_ci#endif 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_DEBUGFS 280962306a36Sopenharmony_ci .get_et_sset_count = ath9k_get_et_sset_count, 281062306a36Sopenharmony_ci .get_et_stats = ath9k_get_et_stats, 281162306a36Sopenharmony_ci .get_et_strings = ath9k_get_et_strings, 281262306a36Sopenharmony_ci#endif 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_STATION_STATISTICS) 281562306a36Sopenharmony_ci .sta_add_debugfs = ath9k_sta_add_debugfs, 281662306a36Sopenharmony_ci#endif 281762306a36Sopenharmony_ci .sw_scan_start = ath9k_sw_scan_start, 281862306a36Sopenharmony_ci .sw_scan_complete = ath9k_sw_scan_complete, 281962306a36Sopenharmony_ci .get_txpower = ath9k_get_txpower, 282062306a36Sopenharmony_ci .wake_tx_queue = ath9k_wake_tx_queue, 282162306a36Sopenharmony_ci}; 2822