18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/nl80211.h>
188c2ecf20Sopenharmony_ci#include <linux/delay.h>
198c2ecf20Sopenharmony_ci#include "ath9k.h"
208c2ecf20Sopenharmony_ci#include "btcoex.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
238c2ecf20Sopenharmony_ci			u32 queues, bool drop);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciu8 ath9k_parse_mpdudensity(u8 mpdudensity)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	/*
288c2ecf20Sopenharmony_ci	 * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
298c2ecf20Sopenharmony_ci	 *   0 for no restriction
308c2ecf20Sopenharmony_ci	 *   1 for 1/4 us
318c2ecf20Sopenharmony_ci	 *   2 for 1/2 us
328c2ecf20Sopenharmony_ci	 *   3 for 1 us
338c2ecf20Sopenharmony_ci	 *   4 for 2 us
348c2ecf20Sopenharmony_ci	 *   5 for 4 us
358c2ecf20Sopenharmony_ci	 *   6 for 8 us
368c2ecf20Sopenharmony_ci	 *   7 for 16 us
378c2ecf20Sopenharmony_ci	 */
388c2ecf20Sopenharmony_ci	switch (mpdudensity) {
398c2ecf20Sopenharmony_ci	case 0:
408c2ecf20Sopenharmony_ci		return 0;
418c2ecf20Sopenharmony_ci	case 1:
428c2ecf20Sopenharmony_ci	case 2:
438c2ecf20Sopenharmony_ci	case 3:
448c2ecf20Sopenharmony_ci		/* Our lower layer calculations limit our precision to
458c2ecf20Sopenharmony_ci		   1 microsecond */
468c2ecf20Sopenharmony_ci		return 1;
478c2ecf20Sopenharmony_ci	case 4:
488c2ecf20Sopenharmony_ci		return 2;
498c2ecf20Sopenharmony_ci	case 5:
508c2ecf20Sopenharmony_ci		return 4;
518c2ecf20Sopenharmony_ci	case 6:
528c2ecf20Sopenharmony_ci		return 8;
538c2ecf20Sopenharmony_ci	case 7:
548c2ecf20Sopenharmony_ci		return 16;
558c2ecf20Sopenharmony_ci	default:
568c2ecf20Sopenharmony_ci		return 0;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq,
618c2ecf20Sopenharmony_ci				     bool sw_pending)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	bool pending = false;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	spin_lock_bh(&txq->axq_lock);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (txq->axq_depth) {
688c2ecf20Sopenharmony_ci		pending = true;
698c2ecf20Sopenharmony_ci		goto out;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (!sw_pending)
738c2ecf20Sopenharmony_ci		goto out;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (txq->mac80211_qnum >= 0) {
768c2ecf20Sopenharmony_ci		struct ath_acq *acq;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		acq = &sc->cur_chan->acq[txq->mac80211_qnum];
798c2ecf20Sopenharmony_ci		if (!list_empty(&acq->acq_new) || !list_empty(&acq->acq_old))
808c2ecf20Sopenharmony_ci			pending = true;
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ciout:
838c2ecf20Sopenharmony_ci	spin_unlock_bh(&txq->axq_lock);
848c2ecf20Sopenharmony_ci	return pending;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	unsigned long flags;
908c2ecf20Sopenharmony_ci	bool ret;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sc->sc_pm_lock, flags);
938c2ecf20Sopenharmony_ci	ret = ath9k_hw_setpower(sc->sc_ah, mode);
948c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	return ret;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_civoid ath_ps_full_sleep(struct timer_list *t)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct ath_softc *sc = from_timer(sc, t, sleep_timer);
1028c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1038c2ecf20Sopenharmony_ci	unsigned long flags;
1048c2ecf20Sopenharmony_ci	bool reset;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	spin_lock_irqsave(&common->cc_lock, flags);
1078c2ecf20Sopenharmony_ci	ath_hw_cycle_counters_update(common);
1088c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&common->cc_lock, flags);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	ath9k_hw_setrxabort(sc->sc_ah, 1);
1118c2ecf20Sopenharmony_ci	ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_civoid ath9k_ps_wakeup(struct ath_softc *sc)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1198c2ecf20Sopenharmony_ci	unsigned long flags;
1208c2ecf20Sopenharmony_ci	enum ath9k_power_mode power_mode;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sc->sc_pm_lock, flags);
1238c2ecf20Sopenharmony_ci	if (++sc->ps_usecount != 1)
1248c2ecf20Sopenharmony_ci		goto unlock;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	del_timer_sync(&sc->sleep_timer);
1278c2ecf20Sopenharmony_ci	power_mode = sc->sc_ah->power_mode;
1288c2ecf20Sopenharmony_ci	ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/*
1318c2ecf20Sopenharmony_ci	 * While the hardware is asleep, the cycle counters contain no
1328c2ecf20Sopenharmony_ci	 * useful data. Better clear them now so that they don't mess up
1338c2ecf20Sopenharmony_ci	 * survey data results.
1348c2ecf20Sopenharmony_ci	 */
1358c2ecf20Sopenharmony_ci	if (power_mode != ATH9K_PM_AWAKE) {
1368c2ecf20Sopenharmony_ci		spin_lock(&common->cc_lock);
1378c2ecf20Sopenharmony_ci		ath_hw_cycle_counters_update(common);
1388c2ecf20Sopenharmony_ci		memset(&common->cc_survey, 0, sizeof(common->cc_survey));
1398c2ecf20Sopenharmony_ci		memset(&common->cc_ani, 0, sizeof(common->cc_ani));
1408c2ecf20Sopenharmony_ci		spin_unlock(&common->cc_lock);
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci unlock:
1448c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_civoid ath9k_ps_restore(struct ath_softc *sc)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
1508c2ecf20Sopenharmony_ci	enum ath9k_power_mode mode;
1518c2ecf20Sopenharmony_ci	unsigned long flags;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sc->sc_pm_lock, flags);
1548c2ecf20Sopenharmony_ci	if (--sc->ps_usecount != 0)
1558c2ecf20Sopenharmony_ci		goto unlock;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (sc->ps_idle) {
1588c2ecf20Sopenharmony_ci		mod_timer(&sc->sleep_timer, jiffies + HZ / 10);
1598c2ecf20Sopenharmony_ci		goto unlock;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (sc->ps_enabled &&
1638c2ecf20Sopenharmony_ci		   !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
1648c2ecf20Sopenharmony_ci				     PS_WAIT_FOR_CAB |
1658c2ecf20Sopenharmony_ci				     PS_WAIT_FOR_PSPOLL_DATA |
1668c2ecf20Sopenharmony_ci				     PS_WAIT_FOR_TX_ACK |
1678c2ecf20Sopenharmony_ci				     PS_WAIT_FOR_ANI))) {
1688c2ecf20Sopenharmony_ci		mode = ATH9K_PM_NETWORK_SLEEP;
1698c2ecf20Sopenharmony_ci		if (ath9k_hw_btcoex_is_enabled(sc->sc_ah))
1708c2ecf20Sopenharmony_ci			ath9k_btcoex_stop_gen_timer(sc);
1718c2ecf20Sopenharmony_ci	} else {
1728c2ecf20Sopenharmony_ci		goto unlock;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	spin_lock(&common->cc_lock);
1768c2ecf20Sopenharmony_ci	ath_hw_cycle_counters_update(common);
1778c2ecf20Sopenharmony_ci	spin_unlock(&common->cc_lock);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	ath9k_hw_setpower(sc->sc_ah, mode);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci unlock:
1828c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic void __ath_cancel_work(struct ath_softc *sc)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	cancel_work_sync(&sc->paprd_work);
1888c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&sc->hw_check_work);
1898c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&sc->hw_pll_work);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
1928c2ecf20Sopenharmony_ci	if (ath9k_hw_mci_is_enabled(sc->sc_ah))
1938c2ecf20Sopenharmony_ci		cancel_work_sync(&sc->mci_work);
1948c2ecf20Sopenharmony_ci#endif
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_civoid ath_cancel_work(struct ath_softc *sc)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	__ath_cancel_work(sc);
2008c2ecf20Sopenharmony_ci	cancel_work_sync(&sc->hw_reset_work);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_civoid ath_restart_work(struct ath_softc *sc)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
2068c2ecf20Sopenharmony_ci				     msecs_to_jiffies(ATH_HW_CHECK_POLL_INT));
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
2098c2ecf20Sopenharmony_ci		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
2108c2ecf20Sopenharmony_ci				     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	ath_start_ani(sc);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic bool ath_prepare_reset(struct ath_softc *sc)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
2188c2ecf20Sopenharmony_ci	bool ret = true;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	ieee80211_stop_queues(sc->hw);
2218c2ecf20Sopenharmony_ci	ath_stop_ani(sc);
2228c2ecf20Sopenharmony_ci	ath9k_hw_disable_interrupts(ah);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (AR_SREV_9300_20_OR_LATER(ah)) {
2258c2ecf20Sopenharmony_ci		ret &= ath_stoprecv(sc);
2268c2ecf20Sopenharmony_ci		ret &= ath_drain_all_txq(sc);
2278c2ecf20Sopenharmony_ci	} else {
2288c2ecf20Sopenharmony_ci		ret &= ath_drain_all_txq(sc);
2298c2ecf20Sopenharmony_ci		ret &= ath_stoprecv(sc);
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return ret;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic bool ath_complete_reset(struct ath_softc *sc, bool start)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
2388c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
2398c2ecf20Sopenharmony_ci	unsigned long flags;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	ath9k_calculate_summary_state(sc, sc->cur_chan);
2428c2ecf20Sopenharmony_ci	ath_startrecv(sc);
2438c2ecf20Sopenharmony_ci	ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
2448c2ecf20Sopenharmony_ci			       sc->cur_chan->txpower,
2458c2ecf20Sopenharmony_ci			       &sc->cur_chan->cur_txpower);
2468c2ecf20Sopenharmony_ci	clear_bit(ATH_OP_HW_RESET, &common->op_flags);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (!sc->cur_chan->offchannel && start) {
2498c2ecf20Sopenharmony_ci		/* restore per chanctx TSF timer */
2508c2ecf20Sopenharmony_ci		if (sc->cur_chan->tsf_val) {
2518c2ecf20Sopenharmony_ci			u32 offset;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci			offset = ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts,
2548c2ecf20Sopenharmony_ci							 NULL);
2558c2ecf20Sopenharmony_ci			ath9k_hw_settsf64(ah, sc->cur_chan->tsf_val + offset);
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci		if (!test_bit(ATH_OP_BEACONS, &common->op_flags))
2608c2ecf20Sopenharmony_ci			goto work;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		if (ah->opmode == NL80211_IFTYPE_STATION &&
2638c2ecf20Sopenharmony_ci		    test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
2648c2ecf20Sopenharmony_ci			spin_lock_irqsave(&sc->sc_pm_lock, flags);
2658c2ecf20Sopenharmony_ci			sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
2668c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
2678c2ecf20Sopenharmony_ci		} else {
2688c2ecf20Sopenharmony_ci			ath9k_set_beacon(sc);
2698c2ecf20Sopenharmony_ci		}
2708c2ecf20Sopenharmony_ci	work:
2718c2ecf20Sopenharmony_ci		ath_restart_work(sc);
2728c2ecf20Sopenharmony_ci		ath_txq_schedule_all(sc);
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	sc->gtt_cnt = 0;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	ath9k_hw_set_interrupts(ah);
2788c2ecf20Sopenharmony_ci	ath9k_hw_enable_interrupts(ah);
2798c2ecf20Sopenharmony_ci	ieee80211_wake_queues(sc->hw);
2808c2ecf20Sopenharmony_ci	ath9k_p2p_ps_timer(sc);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return true;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
2888c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
2898c2ecf20Sopenharmony_ci	struct ath9k_hw_cal_data *caldata = NULL;
2908c2ecf20Sopenharmony_ci	bool fastcc = true;
2918c2ecf20Sopenharmony_ci	int r;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	__ath_cancel_work(sc);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	disable_irq(sc->irq);
2968c2ecf20Sopenharmony_ci	tasklet_disable(&sc->intr_tq);
2978c2ecf20Sopenharmony_ci	tasklet_disable(&sc->bcon_tasklet);
2988c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->sc_pcu_lock);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (!sc->cur_chan->offchannel) {
3018c2ecf20Sopenharmony_ci		fastcc = false;
3028c2ecf20Sopenharmony_ci		caldata = &sc->cur_chan->caldata;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (!hchan) {
3068c2ecf20Sopenharmony_ci		fastcc = false;
3078c2ecf20Sopenharmony_ci		hchan = ah->curchan;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (!hchan) {
3118c2ecf20Sopenharmony_ci		fastcc = false;
3128c2ecf20Sopenharmony_ci		hchan = ath9k_cmn_get_channel(sc->hw, ah, &sc->cur_chan->chandef);
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	if (!ath_prepare_reset(sc))
3168c2ecf20Sopenharmony_ci		fastcc = false;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (ath9k_is_chanctx_enabled())
3198c2ecf20Sopenharmony_ci		fastcc = false;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->chan_lock);
3228c2ecf20Sopenharmony_ci	sc->cur_chandef = sc->cur_chan->chandef;
3238c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->chan_lock);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
3268c2ecf20Sopenharmony_ci		hchan->channel, IS_CHAN_HT40(hchan), fastcc);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
3298c2ecf20Sopenharmony_ci	if (r) {
3308c2ecf20Sopenharmony_ci		ath_err(common,
3318c2ecf20Sopenharmony_ci			"Unable to reset channel, reset status %d\n", r);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		ath9k_hw_enable_interrupts(ah);
3348c2ecf20Sopenharmony_ci		ath9k_queue_reset(sc, RESET_TYPE_BB_HANG);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		goto out;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (ath9k_hw_mci_is_enabled(sc->sc_ah) &&
3408c2ecf20Sopenharmony_ci	    sc->cur_chan->offchannel)
3418c2ecf20Sopenharmony_ci		ath9k_mci_set_txpower(sc, true, false);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (!ath_complete_reset(sc, true))
3448c2ecf20Sopenharmony_ci		r = -EIO;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ciout:
3478c2ecf20Sopenharmony_ci	enable_irq(sc->irq);
3488c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->sc_pcu_lock);
3498c2ecf20Sopenharmony_ci	tasklet_enable(&sc->bcon_tasklet);
3508c2ecf20Sopenharmony_ci	tasklet_enable(&sc->intr_tq);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	return r;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
3568c2ecf20Sopenharmony_ci			    struct ieee80211_vif *vif)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	struct ath_node *an;
3598c2ecf20Sopenharmony_ci	an = (struct ath_node *)sta->drv_priv;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	an->sc = sc;
3628c2ecf20Sopenharmony_ci	an->sta = sta;
3638c2ecf20Sopenharmony_ci	an->vif = vif;
3648c2ecf20Sopenharmony_ci	memset(&an->key_idx, 0, sizeof(an->key_idx));
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	ath_tx_node_init(sc, an);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	ath_dynack_node_init(sc->sc_ah, an);
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct ath_node *an = (struct ath_node *)sta->drv_priv;
3748c2ecf20Sopenharmony_ci	ath_tx_node_cleanup(sc, an);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	ath_dynack_node_deinit(sc->sc_ah, an);
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_civoid ath9k_tasklet(struct tasklet_struct *t)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct ath_softc *sc = from_tasklet(sc, t, intr_tq);
3828c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
3838c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
3848c2ecf20Sopenharmony_ci	enum ath_reset_type type;
3858c2ecf20Sopenharmony_ci	unsigned long flags;
3868c2ecf20Sopenharmony_ci	u32 status;
3878c2ecf20Sopenharmony_ci	u32 rxmask;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sc->intr_lock, flags);
3908c2ecf20Sopenharmony_ci	status = sc->intrstatus;
3918c2ecf20Sopenharmony_ci	sc->intrstatus = 0;
3928c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sc->intr_lock, flags);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
3958c2ecf20Sopenharmony_ci	spin_lock(&sc->sc_pcu_lock);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (status & ATH9K_INT_FATAL) {
3988c2ecf20Sopenharmony_ci		type = RESET_TYPE_FATAL_INT;
3998c2ecf20Sopenharmony_ci		ath9k_queue_reset(sc, type);
4008c2ecf20Sopenharmony_ci		ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
4018c2ecf20Sopenharmony_ci		goto out;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
4058c2ecf20Sopenharmony_ci	    (status & ATH9K_INT_BB_WATCHDOG)) {
4068c2ecf20Sopenharmony_ci		spin_lock_irqsave(&common->cc_lock, flags);
4078c2ecf20Sopenharmony_ci		ath_hw_cycle_counters_update(common);
4088c2ecf20Sopenharmony_ci		ar9003_hw_bb_watchdog_dbg_info(ah);
4098c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&common->cc_lock, flags);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci		if (ar9003_hw_bb_watchdog_check(ah)) {
4128c2ecf20Sopenharmony_ci			type = RESET_TYPE_BB_WATCHDOG;
4138c2ecf20Sopenharmony_ci			ath9k_queue_reset(sc, type);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci			ath_dbg(common, RESET,
4168c2ecf20Sopenharmony_ci				"BB_WATCHDOG: Skipping interrupts\n");
4178c2ecf20Sopenharmony_ci			goto out;
4188c2ecf20Sopenharmony_ci		}
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (status & ATH9K_INT_GTT) {
4228c2ecf20Sopenharmony_ci		sc->gtt_cnt++;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) {
4258c2ecf20Sopenharmony_ci			type = RESET_TYPE_TX_GTT;
4268c2ecf20Sopenharmony_ci			ath9k_queue_reset(sc, type);
4278c2ecf20Sopenharmony_ci			ath_dbg(common, RESET,
4288c2ecf20Sopenharmony_ci				"GTT: Skipping interrupts\n");
4298c2ecf20Sopenharmony_ci			goto out;
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sc->sc_pm_lock, flags);
4348c2ecf20Sopenharmony_ci	if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
4358c2ecf20Sopenharmony_ci		/*
4368c2ecf20Sopenharmony_ci		 * TSF sync does not look correct; remain awake to sync with
4378c2ecf20Sopenharmony_ci		 * the next Beacon.
4388c2ecf20Sopenharmony_ci		 */
4398c2ecf20Sopenharmony_ci		ath_dbg(common, PS, "TSFOOR - Sync with next Beacon\n");
4408c2ecf20Sopenharmony_ci		sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
4458c2ecf20Sopenharmony_ci		rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
4468c2ecf20Sopenharmony_ci			  ATH9K_INT_RXORN);
4478c2ecf20Sopenharmony_ci	else
4488c2ecf20Sopenharmony_ci		rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (status & rxmask) {
4518c2ecf20Sopenharmony_ci		/* Check for high priority Rx first */
4528c2ecf20Sopenharmony_ci		if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
4538c2ecf20Sopenharmony_ci		    (status & ATH9K_INT_RXHP))
4548c2ecf20Sopenharmony_ci			ath_rx_tasklet(sc, 0, true);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		ath_rx_tasklet(sc, 0, false);
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (status & ATH9K_INT_TX) {
4608c2ecf20Sopenharmony_ci		if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
4618c2ecf20Sopenharmony_ci			/*
4628c2ecf20Sopenharmony_ci			 * For EDMA chips, TX completion is enabled for the
4638c2ecf20Sopenharmony_ci			 * beacon queue, so if a beacon has been transmitted
4648c2ecf20Sopenharmony_ci			 * successfully after a GTT interrupt, the GTT counter
4658c2ecf20Sopenharmony_ci			 * gets reset to zero here.
4668c2ecf20Sopenharmony_ci			 */
4678c2ecf20Sopenharmony_ci			sc->gtt_cnt = 0;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci			ath_tx_edma_tasklet(sc);
4708c2ecf20Sopenharmony_ci		} else {
4718c2ecf20Sopenharmony_ci			ath_tx_tasklet(sc);
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		wake_up(&sc->tx_wait);
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (status & ATH9K_INT_GENTIMER)
4788c2ecf20Sopenharmony_ci		ath_gen_timer_isr(sc->sc_ah);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	ath9k_btcoex_handle_interrupt(sc, status);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	/* re-enable hardware interrupt */
4838c2ecf20Sopenharmony_ci	ath9k_hw_resume_interrupts(ah);
4848c2ecf20Sopenharmony_ciout:
4858c2ecf20Sopenharmony_ci	spin_unlock(&sc->sc_pcu_lock);
4868c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ciirqreturn_t ath_isr(int irq, void *dev)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci#define SCHED_INTR (				\
4928c2ecf20Sopenharmony_ci		ATH9K_INT_FATAL |		\
4938c2ecf20Sopenharmony_ci		ATH9K_INT_BB_WATCHDOG |		\
4948c2ecf20Sopenharmony_ci		ATH9K_INT_RXORN |		\
4958c2ecf20Sopenharmony_ci		ATH9K_INT_RXEOL |		\
4968c2ecf20Sopenharmony_ci		ATH9K_INT_RX |			\
4978c2ecf20Sopenharmony_ci		ATH9K_INT_RXLP |		\
4988c2ecf20Sopenharmony_ci		ATH9K_INT_RXHP |		\
4998c2ecf20Sopenharmony_ci		ATH9K_INT_TX |			\
5008c2ecf20Sopenharmony_ci		ATH9K_INT_BMISS |		\
5018c2ecf20Sopenharmony_ci		ATH9K_INT_CST |			\
5028c2ecf20Sopenharmony_ci		ATH9K_INT_GTT |			\
5038c2ecf20Sopenharmony_ci		ATH9K_INT_TSFOOR |		\
5048c2ecf20Sopenharmony_ci		ATH9K_INT_GENTIMER |		\
5058c2ecf20Sopenharmony_ci		ATH9K_INT_MCI)
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	struct ath_softc *sc = dev;
5088c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
5098c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
5108c2ecf20Sopenharmony_ci	enum ath9k_int status;
5118c2ecf20Sopenharmony_ci	u32 sync_cause = 0;
5128c2ecf20Sopenharmony_ci	bool sched = false;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/*
5158c2ecf20Sopenharmony_ci	 * The hardware is not ready/present, don't
5168c2ecf20Sopenharmony_ci	 * touch anything. Note this can happen early
5178c2ecf20Sopenharmony_ci	 * on if the IRQ is shared.
5188c2ecf20Sopenharmony_ci	 */
5198c2ecf20Sopenharmony_ci	if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
5208c2ecf20Sopenharmony_ci		return IRQ_NONE;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	/* shared irq, not for us */
5238c2ecf20Sopenharmony_ci	if (!ath9k_hw_intrpend(ah))
5248c2ecf20Sopenharmony_ci		return IRQ_NONE;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	/*
5278c2ecf20Sopenharmony_ci	 * Figure out the reason(s) for the interrupt.  Note
5288c2ecf20Sopenharmony_ci	 * that the hal returns a pseudo-ISR that may include
5298c2ecf20Sopenharmony_ci	 * bits we haven't explicitly enabled so we mask the
5308c2ecf20Sopenharmony_ci	 * value to insure we only process bits we requested.
5318c2ecf20Sopenharmony_ci	 */
5328c2ecf20Sopenharmony_ci	ath9k_hw_getisr(ah, &status, &sync_cause); /* NB: clears ISR too */
5338c2ecf20Sopenharmony_ci	ath9k_debug_sync_cause(sc, sync_cause);
5348c2ecf20Sopenharmony_ci	status &= ah->imask;	/* discard unasked-for bits */
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) {
5378c2ecf20Sopenharmony_ci		ath9k_hw_kill_interrupts(sc->sc_ah);
5388c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	/*
5428c2ecf20Sopenharmony_ci	 * If there are no status bits set, then this interrupt was not
5438c2ecf20Sopenharmony_ci	 * for me (should have been caught above).
5448c2ecf20Sopenharmony_ci	 */
5458c2ecf20Sopenharmony_ci	if (!status)
5468c2ecf20Sopenharmony_ci		return IRQ_NONE;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	/* Cache the status */
5498c2ecf20Sopenharmony_ci	spin_lock(&sc->intr_lock);
5508c2ecf20Sopenharmony_ci	sc->intrstatus |= status;
5518c2ecf20Sopenharmony_ci	spin_unlock(&sc->intr_lock);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (status & SCHED_INTR)
5548c2ecf20Sopenharmony_ci		sched = true;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	/*
5578c2ecf20Sopenharmony_ci	 * If a FATAL interrupt is received, we have to reset the chip
5588c2ecf20Sopenharmony_ci	 * immediately.
5598c2ecf20Sopenharmony_ci	 */
5608c2ecf20Sopenharmony_ci	if (status & ATH9K_INT_FATAL)
5618c2ecf20Sopenharmony_ci		goto chip_reset;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
5648c2ecf20Sopenharmony_ci	    (status & ATH9K_INT_BB_WATCHDOG))
5658c2ecf20Sopenharmony_ci		goto chip_reset;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (status & ATH9K_INT_SWBA)
5688c2ecf20Sopenharmony_ci		tasklet_schedule(&sc->bcon_tasklet);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (status & ATH9K_INT_TXURN)
5718c2ecf20Sopenharmony_ci		ath9k_hw_updatetxtriglevel(ah, true);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	if (status & ATH9K_INT_RXEOL) {
5748c2ecf20Sopenharmony_ci		ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
5758c2ecf20Sopenharmony_ci		ath9k_hw_set_interrupts(ah);
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
5798c2ecf20Sopenharmony_ci		if (status & ATH9K_INT_TIM_TIMER) {
5808c2ecf20Sopenharmony_ci			if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle))
5818c2ecf20Sopenharmony_ci				goto chip_reset;
5828c2ecf20Sopenharmony_ci			/* Clear RxAbort bit so that we can
5838c2ecf20Sopenharmony_ci			 * receive frames */
5848c2ecf20Sopenharmony_ci			ath9k_setpower(sc, ATH9K_PM_AWAKE);
5858c2ecf20Sopenharmony_ci			spin_lock(&sc->sc_pm_lock);
5868c2ecf20Sopenharmony_ci			ath9k_hw_setrxabort(sc->sc_ah, 0);
5878c2ecf20Sopenharmony_ci			sc->ps_flags |= PS_WAIT_FOR_BEACON;
5888c2ecf20Sopenharmony_ci			spin_unlock(&sc->sc_pm_lock);
5898c2ecf20Sopenharmony_ci		}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cichip_reset:
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	ath_debug_stat_interrupt(sc, status);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	if (sched) {
5968c2ecf20Sopenharmony_ci		/* turn off every interrupt */
5978c2ecf20Sopenharmony_ci		ath9k_hw_kill_interrupts(ah);
5988c2ecf20Sopenharmony_ci		tasklet_schedule(&sc->intr_tq);
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci#undef SCHED_INTR
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci/*
6078c2ecf20Sopenharmony_ci * This function is called when a HW reset cannot be deferred
6088c2ecf20Sopenharmony_ci * and has to be immediate.
6098c2ecf20Sopenharmony_ci */
6108c2ecf20Sopenharmony_ciint ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
6138c2ecf20Sopenharmony_ci	int r;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	ath9k_hw_kill_interrupts(sc->sc_ah);
6168c2ecf20Sopenharmony_ci	set_bit(ATH_OP_HW_RESET, &common->op_flags);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
6198c2ecf20Sopenharmony_ci	r = ath_reset_internal(sc, hchan);
6208c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	return r;
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci/*
6268c2ecf20Sopenharmony_ci * When a HW reset can be deferred, it is added to the
6278c2ecf20Sopenharmony_ci * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before
6288c2ecf20Sopenharmony_ci * queueing.
6298c2ecf20Sopenharmony_ci */
6308c2ecf20Sopenharmony_civoid ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
6338c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_DEBUGFS
6348c2ecf20Sopenharmony_ci	RESET_STAT_INC(sc, type);
6358c2ecf20Sopenharmony_ci#endif
6368c2ecf20Sopenharmony_ci	ath9k_hw_kill_interrupts(sc->sc_ah);
6378c2ecf20Sopenharmony_ci	set_bit(ATH_OP_HW_RESET, &common->op_flags);
6388c2ecf20Sopenharmony_ci	ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_civoid ath_reset_work(struct work_struct *work)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
6468c2ecf20Sopenharmony_ci	ath_reset_internal(sc, NULL);
6478c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci/**********************/
6518c2ecf20Sopenharmony_ci/* mac80211 callbacks */
6528c2ecf20Sopenharmony_ci/**********************/
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic int ath9k_start(struct ieee80211_hw *hw)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
6578c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
6588c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
6598c2ecf20Sopenharmony_ci	struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
6608c2ecf20Sopenharmony_ci	struct ath_chanctx *ctx = sc->cur_chan;
6618c2ecf20Sopenharmony_ci	struct ath9k_channel *init_channel;
6628c2ecf20Sopenharmony_ci	int r;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG,
6658c2ecf20Sopenharmony_ci		"Starting driver with initial channel: %d MHz\n",
6668c2ecf20Sopenharmony_ci		curchan->center_freq);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
6698c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	init_channel = ath9k_cmn_get_channel(hw, ah, &ctx->chandef);
6728c2ecf20Sopenharmony_ci	sc->cur_chandef = hw->conf.chandef;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	/* Reset SERDES registers */
6758c2ecf20Sopenharmony_ci	ath9k_hw_configpcipowersave(ah, false);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	/*
6788c2ecf20Sopenharmony_ci	 * The basic interface to setting the hardware in a good
6798c2ecf20Sopenharmony_ci	 * state is ``reset''.  On return the hardware is known to
6808c2ecf20Sopenharmony_ci	 * be powered up and with interrupts disabled.  This must
6818c2ecf20Sopenharmony_ci	 * be followed by initialization of the appropriate bits
6828c2ecf20Sopenharmony_ci	 * and then setup of the interrupt mask.
6838c2ecf20Sopenharmony_ci	 */
6848c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->sc_pcu_lock);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	atomic_set(&ah->intr_ref_cnt, -1);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
6898c2ecf20Sopenharmony_ci	if (r) {
6908c2ecf20Sopenharmony_ci		ath_err(common,
6918c2ecf20Sopenharmony_ci			"Unable to reset hardware; reset status %d (freq %u MHz)\n",
6928c2ecf20Sopenharmony_ci			r, curchan->center_freq);
6938c2ecf20Sopenharmony_ci		ah->reset_power_on = false;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	/* Setup our intr mask. */
6978c2ecf20Sopenharmony_ci	ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
6988c2ecf20Sopenharmony_ci		    ATH9K_INT_RXORN | ATH9K_INT_FATAL |
6998c2ecf20Sopenharmony_ci		    ATH9K_INT_GLOBAL;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
7028c2ecf20Sopenharmony_ci		ah->imask |= ATH9K_INT_RXHP |
7038c2ecf20Sopenharmony_ci			     ATH9K_INT_RXLP;
7048c2ecf20Sopenharmony_ci	else
7058c2ecf20Sopenharmony_ci		ah->imask |= ATH9K_INT_RX;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (ah->config.hw_hang_checks & HW_BB_WATCHDOG)
7088c2ecf20Sopenharmony_ci		ah->imask |= ATH9K_INT_BB_WATCHDOG;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	/*
7118c2ecf20Sopenharmony_ci	 * Enable GTT interrupts only for AR9003/AR9004 chips
7128c2ecf20Sopenharmony_ci	 * for now.
7138c2ecf20Sopenharmony_ci	 */
7148c2ecf20Sopenharmony_ci	if (AR_SREV_9300_20_OR_LATER(ah))
7158c2ecf20Sopenharmony_ci		ah->imask |= ATH9K_INT_GTT;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
7188c2ecf20Sopenharmony_ci		ah->imask |= ATH9K_INT_CST;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	ath_mci_enable(sc);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	clear_bit(ATH_OP_INVALID, &common->op_flags);
7238c2ecf20Sopenharmony_ci	sc->sc_ah->is_monitoring = false;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	if (!ath_complete_reset(sc, false))
7268c2ecf20Sopenharmony_ci		ah->reset_power_on = false;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	if (ah->led_pin >= 0) {
7298c2ecf20Sopenharmony_ci		ath9k_hw_set_gpio(ah, ah->led_pin,
7308c2ecf20Sopenharmony_ci				  (ah->config.led_active_high) ? 1 : 0);
7318c2ecf20Sopenharmony_ci		ath9k_hw_gpio_request_out(ah, ah->led_pin, NULL,
7328c2ecf20Sopenharmony_ci					  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	/*
7368c2ecf20Sopenharmony_ci	 * Reset key cache to sane defaults (all entries cleared) instead of
7378c2ecf20Sopenharmony_ci	 * semi-random values after suspend/resume.
7388c2ecf20Sopenharmony_ci	 */
7398c2ecf20Sopenharmony_ci	ath9k_cmn_init_crypto(sc->sc_ah);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	ath9k_hw_reset_tsf(ah);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->sc_pcu_lock);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	ath9k_rng_start(sc);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	return 0;
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic void ath9k_tx(struct ieee80211_hw *hw,
7558c2ecf20Sopenharmony_ci		     struct ieee80211_tx_control *control,
7568c2ecf20Sopenharmony_ci		     struct sk_buff *skb)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
7598c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
7608c2ecf20Sopenharmony_ci	struct ath_tx_control txctl;
7618c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
7628c2ecf20Sopenharmony_ci	unsigned long flags;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (sc->ps_enabled) {
7658c2ecf20Sopenharmony_ci		/*
7668c2ecf20Sopenharmony_ci		 * mac80211 does not set PM field for normal data frames, so we
7678c2ecf20Sopenharmony_ci		 * need to update that based on the current PS mode.
7688c2ecf20Sopenharmony_ci		 */
7698c2ecf20Sopenharmony_ci		if (ieee80211_is_data(hdr->frame_control) &&
7708c2ecf20Sopenharmony_ci		    !ieee80211_is_nullfunc(hdr->frame_control) &&
7718c2ecf20Sopenharmony_ci		    !ieee80211_has_pm(hdr->frame_control)) {
7728c2ecf20Sopenharmony_ci			ath_dbg(common, PS,
7738c2ecf20Sopenharmony_ci				"Add PM=1 for a TX frame while in PS mode\n");
7748c2ecf20Sopenharmony_ci			hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
7758c2ecf20Sopenharmony_ci		}
7768c2ecf20Sopenharmony_ci	}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP)) {
7798c2ecf20Sopenharmony_ci		/*
7808c2ecf20Sopenharmony_ci		 * We are using PS-Poll and mac80211 can request TX while in
7818c2ecf20Sopenharmony_ci		 * power save mode. Need to wake up hardware for the TX to be
7828c2ecf20Sopenharmony_ci		 * completed and if needed, also for RX of buffered frames.
7838c2ecf20Sopenharmony_ci		 */
7848c2ecf20Sopenharmony_ci		ath9k_ps_wakeup(sc);
7858c2ecf20Sopenharmony_ci		spin_lock_irqsave(&sc->sc_pm_lock, flags);
7868c2ecf20Sopenharmony_ci		if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
7878c2ecf20Sopenharmony_ci			ath9k_hw_setrxabort(sc->sc_ah, 0);
7888c2ecf20Sopenharmony_ci		if (ieee80211_is_pspoll(hdr->frame_control)) {
7898c2ecf20Sopenharmony_ci			ath_dbg(common, PS,
7908c2ecf20Sopenharmony_ci				"Sending PS-Poll to pick a buffered frame\n");
7918c2ecf20Sopenharmony_ci			sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA;
7928c2ecf20Sopenharmony_ci		} else {
7938c2ecf20Sopenharmony_ci			ath_dbg(common, PS, "Wake up to complete TX\n");
7948c2ecf20Sopenharmony_ci			sc->ps_flags |= PS_WAIT_FOR_TX_ACK;
7958c2ecf20Sopenharmony_ci		}
7968c2ecf20Sopenharmony_ci		/*
7978c2ecf20Sopenharmony_ci		 * The actual restore operation will happen only after
7988c2ecf20Sopenharmony_ci		 * the ps_flags bit is cleared. We are just dropping
7998c2ecf20Sopenharmony_ci		 * the ps_usecount here.
8008c2ecf20Sopenharmony_ci		 */
8018c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
8028c2ecf20Sopenharmony_ci		ath9k_ps_restore(sc);
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	/*
8068c2ecf20Sopenharmony_ci	 * Cannot tx while the hardware is in full sleep, it first needs a full
8078c2ecf20Sopenharmony_ci	 * chip reset to recover from that
8088c2ecf20Sopenharmony_ci	 */
8098c2ecf20Sopenharmony_ci	if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) {
8108c2ecf20Sopenharmony_ci		ath_err(common, "TX while HW is in FULL_SLEEP mode\n");
8118c2ecf20Sopenharmony_ci		goto exit;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	memset(&txctl, 0, sizeof(struct ath_tx_control));
8158c2ecf20Sopenharmony_ci	txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)];
8168c2ecf20Sopenharmony_ci	txctl.sta = control->sta;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	ath_dbg(common, XMIT, "transmitting packet, skb: %p\n", skb);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	if (ath_tx_start(hw, skb, &txctl) != 0) {
8218c2ecf20Sopenharmony_ci		ath_dbg(common, XMIT, "TX failed\n");
8228c2ecf20Sopenharmony_ci		TX_STAT_INC(sc, txctl.txq->axq_qnum, txfailed);
8238c2ecf20Sopenharmony_ci		goto exit;
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	return;
8278c2ecf20Sopenharmony_ciexit:
8288c2ecf20Sopenharmony_ci	ieee80211_free_txskb(hw, skb);
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic bool ath9k_txq_list_has_key(struct list_head *txq_list, u32 keyix)
8328c2ecf20Sopenharmony_ci{
8338c2ecf20Sopenharmony_ci	struct ath_buf *bf;
8348c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *txinfo;
8358c2ecf20Sopenharmony_ci	struct ath_frame_info *fi;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	list_for_each_entry(bf, txq_list, list) {
8388c2ecf20Sopenharmony_ci		if (bf->bf_state.stale || !bf->bf_mpdu)
8398c2ecf20Sopenharmony_ci			continue;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		txinfo = IEEE80211_SKB_CB(bf->bf_mpdu);
8428c2ecf20Sopenharmony_ci		fi = (struct ath_frame_info *)&txinfo->status.status_driver_data[0];
8438c2ecf20Sopenharmony_ci		if (fi->keyix == keyix)
8448c2ecf20Sopenharmony_ci			return true;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	return false;
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
8538c2ecf20Sopenharmony_ci	int i, j;
8548c2ecf20Sopenharmony_ci	struct ath_txq *txq;
8558c2ecf20Sopenharmony_ci	bool key_in_use = false;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	for (i = 0; !key_in_use && i < ATH9K_NUM_TX_QUEUES; i++) {
8588c2ecf20Sopenharmony_ci		if (!ATH_TXQ_SETUP(sc, i))
8598c2ecf20Sopenharmony_ci			continue;
8608c2ecf20Sopenharmony_ci		txq = &sc->tx.txq[i];
8618c2ecf20Sopenharmony_ci		if (!txq->axq_depth)
8628c2ecf20Sopenharmony_ci			continue;
8638c2ecf20Sopenharmony_ci		if (!ath9k_hw_numtxpending(ah, txq->axq_qnum))
8648c2ecf20Sopenharmony_ci			continue;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		ath_txq_lock(sc, txq);
8678c2ecf20Sopenharmony_ci		key_in_use = ath9k_txq_list_has_key(&txq->axq_q, keyix);
8688c2ecf20Sopenharmony_ci		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
8698c2ecf20Sopenharmony_ci			int idx = txq->txq_tailidx;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci			for (j = 0; !key_in_use &&
8728c2ecf20Sopenharmony_ci			     !list_empty(&txq->txq_fifo[idx]) &&
8738c2ecf20Sopenharmony_ci			     j < ATH_TXFIFO_DEPTH; j++) {
8748c2ecf20Sopenharmony_ci				key_in_use = ath9k_txq_list_has_key(
8758c2ecf20Sopenharmony_ci					&txq->txq_fifo[idx], keyix);
8768c2ecf20Sopenharmony_ci				INCR(idx, ATH_TXFIFO_DEPTH);
8778c2ecf20Sopenharmony_ci			}
8788c2ecf20Sopenharmony_ci		}
8798c2ecf20Sopenharmony_ci		ath_txq_unlock(sc, txq);
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	return key_in_use;
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic void ath9k_pending_key_del(struct ath_softc *sc, u8 keyix)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
8888c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (!test_bit(keyix, ah->pending_del_keymap) ||
8918c2ecf20Sopenharmony_ci	    ath9k_txq_has_key(sc, keyix))
8928c2ecf20Sopenharmony_ci		return;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	/* No more TXQ frames point to this key cache entry, so delete it. */
8958c2ecf20Sopenharmony_ci	clear_bit(keyix, ah->pending_del_keymap);
8968c2ecf20Sopenharmony_ci	ath_key_delete(common, keyix);
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic void ath9k_stop(struct ieee80211_hw *hw)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
9028c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
9038c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
9048c2ecf20Sopenharmony_ci	bool prev_idle;
9058c2ecf20Sopenharmony_ci	int i;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	ath9k_deinit_channel_context(sc);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	ath9k_rng_stop(sc);
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	ath_cancel_work(sc);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
9168c2ecf20Sopenharmony_ci		ath_dbg(common, ANY, "Device not present\n");
9178c2ecf20Sopenharmony_ci		mutex_unlock(&sc->mutex);
9188c2ecf20Sopenharmony_ci		return;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	/* Ensure HW is awake when we try to shut it down. */
9228c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->sc_pcu_lock);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	/* prevent tasklets to enable interrupts once we disable them */
9278c2ecf20Sopenharmony_ci	ah->imask &= ~ATH9K_INT_GLOBAL;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	/* make sure h/w will not generate any interrupt
9308c2ecf20Sopenharmony_ci	 * before setting the invalid flag. */
9318c2ecf20Sopenharmony_ci	ath9k_hw_disable_interrupts(ah);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->sc_pcu_lock);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	/* we can now sync irq and kill any running tasklets, since we already
9368c2ecf20Sopenharmony_ci	 * disabled interrupts and not holding a spin lock */
9378c2ecf20Sopenharmony_ci	synchronize_irq(sc->irq);
9388c2ecf20Sopenharmony_ci	tasklet_kill(&sc->intr_tq);
9398c2ecf20Sopenharmony_ci	tasklet_kill(&sc->bcon_tasklet);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	prev_idle = sc->ps_idle;
9428c2ecf20Sopenharmony_ci	sc->ps_idle = true;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->sc_pcu_lock);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	if (ah->led_pin >= 0) {
9478c2ecf20Sopenharmony_ci		ath9k_hw_set_gpio(ah, ah->led_pin,
9488c2ecf20Sopenharmony_ci				  (ah->config.led_active_high) ? 0 : 1);
9498c2ecf20Sopenharmony_ci		ath9k_hw_gpio_request_in(ah, ah->led_pin, NULL);
9508c2ecf20Sopenharmony_ci	}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	ath_prepare_reset(sc);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	if (sc->rx.frag) {
9558c2ecf20Sopenharmony_ci		dev_kfree_skb_any(sc->rx.frag);
9568c2ecf20Sopenharmony_ci		sc->rx.frag = NULL;
9578c2ecf20Sopenharmony_ci	}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	if (!ah->curchan)
9608c2ecf20Sopenharmony_ci		ah->curchan = ath9k_cmn_get_channel(hw, ah,
9618c2ecf20Sopenharmony_ci						    &sc->cur_chan->chandef);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	set_bit(ATH_OP_INVALID, &common->op_flags);
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	ath9k_hw_phy_disable(ah);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	ath9k_hw_configpcipowersave(ah, true);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->sc_pcu_lock);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	for (i = 0; i < ATH_KEYMAX; i++)
9748c2ecf20Sopenharmony_ci		ath9k_pending_key_del(sc, i);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	/* Clear key cache entries explicitly to get rid of any potentially
9778c2ecf20Sopenharmony_ci	 * remaining keys.
9788c2ecf20Sopenharmony_ci	 */
9798c2ecf20Sopenharmony_ci	ath9k_cmn_init_crypto(sc->sc_ah);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	sc->ps_idle = prev_idle;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG, "Driver halt\n");
9888c2ecf20Sopenharmony_ci}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_cistatic bool ath9k_uses_beacons(int type)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	switch (type) {
9938c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_AP:
9948c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_ADHOC:
9958c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_MESH_POINT:
9968c2ecf20Sopenharmony_ci		return true;
9978c2ecf20Sopenharmony_ci	default:
9988c2ecf20Sopenharmony_ci		return false;
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_cistatic void ath9k_vif_iter_set_beacon(struct ath9k_vif_iter_data *iter_data,
10038c2ecf20Sopenharmony_ci				      struct ieee80211_vif *vif)
10048c2ecf20Sopenharmony_ci{
10058c2ecf20Sopenharmony_ci	/* Use the first (configured) interface, but prefering AP interfaces. */
10068c2ecf20Sopenharmony_ci	if (!iter_data->primary_beacon_vif) {
10078c2ecf20Sopenharmony_ci		iter_data->primary_beacon_vif = vif;
10088c2ecf20Sopenharmony_ci	} else {
10098c2ecf20Sopenharmony_ci		if (iter_data->primary_beacon_vif->type != NL80211_IFTYPE_AP &&
10108c2ecf20Sopenharmony_ci		    vif->type == NL80211_IFTYPE_AP)
10118c2ecf20Sopenharmony_ci			iter_data->primary_beacon_vif = vif;
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	iter_data->beacons = true;
10158c2ecf20Sopenharmony_ci	iter_data->nbcnvifs += 1;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
10198c2ecf20Sopenharmony_ci			   u8 *mac, struct ieee80211_vif *vif)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
10228c2ecf20Sopenharmony_ci	int i;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (iter_data->has_hw_macaddr) {
10258c2ecf20Sopenharmony_ci		for (i = 0; i < ETH_ALEN; i++)
10268c2ecf20Sopenharmony_ci			iter_data->mask[i] &=
10278c2ecf20Sopenharmony_ci				~(iter_data->hw_macaddr[i] ^ mac[i]);
10288c2ecf20Sopenharmony_ci	} else {
10298c2ecf20Sopenharmony_ci		memcpy(iter_data->hw_macaddr, mac, ETH_ALEN);
10308c2ecf20Sopenharmony_ci		iter_data->has_hw_macaddr = true;
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	if (!vif->bss_conf.use_short_slot)
10348c2ecf20Sopenharmony_ci		iter_data->slottime = 20;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	switch (vif->type) {
10378c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_AP:
10388c2ecf20Sopenharmony_ci		iter_data->naps++;
10398c2ecf20Sopenharmony_ci		if (vif->bss_conf.enable_beacon)
10408c2ecf20Sopenharmony_ci			ath9k_vif_iter_set_beacon(iter_data, vif);
10418c2ecf20Sopenharmony_ci		break;
10428c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_STATION:
10438c2ecf20Sopenharmony_ci		iter_data->nstations++;
10448c2ecf20Sopenharmony_ci		if (avp->assoc && !iter_data->primary_sta)
10458c2ecf20Sopenharmony_ci			iter_data->primary_sta = vif;
10468c2ecf20Sopenharmony_ci		break;
10478c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_OCB:
10488c2ecf20Sopenharmony_ci		iter_data->nocbs++;
10498c2ecf20Sopenharmony_ci		break;
10508c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_ADHOC:
10518c2ecf20Sopenharmony_ci		iter_data->nadhocs++;
10528c2ecf20Sopenharmony_ci		if (vif->bss_conf.enable_beacon)
10538c2ecf20Sopenharmony_ci			ath9k_vif_iter_set_beacon(iter_data, vif);
10548c2ecf20Sopenharmony_ci		break;
10558c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_MESH_POINT:
10568c2ecf20Sopenharmony_ci		iter_data->nmeshes++;
10578c2ecf20Sopenharmony_ci		if (vif->bss_conf.enable_beacon)
10588c2ecf20Sopenharmony_ci			ath9k_vif_iter_set_beacon(iter_data, vif);
10598c2ecf20Sopenharmony_ci		break;
10608c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_WDS:
10618c2ecf20Sopenharmony_ci		iter_data->nwds++;
10628c2ecf20Sopenharmony_ci		break;
10638c2ecf20Sopenharmony_ci	default:
10648c2ecf20Sopenharmony_ci		break;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_cistatic void ath9k_update_bssid_mask(struct ath_softc *sc,
10698c2ecf20Sopenharmony_ci				    struct ath_chanctx *ctx,
10708c2ecf20Sopenharmony_ci				    struct ath9k_vif_iter_data *iter_data)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
10738c2ecf20Sopenharmony_ci	struct ath_vif *avp;
10748c2ecf20Sopenharmony_ci	int i;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	if (!ath9k_is_chanctx_enabled())
10778c2ecf20Sopenharmony_ci		return;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	list_for_each_entry(avp, &ctx->vifs, list) {
10808c2ecf20Sopenharmony_ci		if (ctx->nvifs_assigned != 1)
10818c2ecf20Sopenharmony_ci			continue;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci		if (!iter_data->has_hw_macaddr)
10848c2ecf20Sopenharmony_ci			continue;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci		ether_addr_copy(common->curbssid, avp->bssid);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci		/* perm_addr will be used as the p2p device address. */
10898c2ecf20Sopenharmony_ci		for (i = 0; i < ETH_ALEN; i++)
10908c2ecf20Sopenharmony_ci			iter_data->mask[i] &=
10918c2ecf20Sopenharmony_ci				~(iter_data->hw_macaddr[i] ^
10928c2ecf20Sopenharmony_ci				  sc->hw->wiphy->perm_addr[i]);
10938c2ecf20Sopenharmony_ci	}
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci/* Called with sc->mutex held. */
10978c2ecf20Sopenharmony_civoid ath9k_calculate_iter_data(struct ath_softc *sc,
10988c2ecf20Sopenharmony_ci			       struct ath_chanctx *ctx,
10998c2ecf20Sopenharmony_ci			       struct ath9k_vif_iter_data *iter_data)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	struct ath_vif *avp;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	/*
11048c2ecf20Sopenharmony_ci	 * The hardware will use primary station addr together with the
11058c2ecf20Sopenharmony_ci	 * BSSID mask when matching addresses.
11068c2ecf20Sopenharmony_ci	 */
11078c2ecf20Sopenharmony_ci	memset(iter_data, 0, sizeof(*iter_data));
11088c2ecf20Sopenharmony_ci	eth_broadcast_addr(iter_data->mask);
11098c2ecf20Sopenharmony_ci	iter_data->slottime = 9;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	list_for_each_entry(avp, &ctx->vifs, list)
11128c2ecf20Sopenharmony_ci		ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	ath9k_update_bssid_mask(sc, ctx, iter_data);
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_cistatic void ath9k_set_assoc_state(struct ath_softc *sc,
11188c2ecf20Sopenharmony_ci				  struct ieee80211_vif *vif, bool changed)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
11218c2ecf20Sopenharmony_ci	struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
11228c2ecf20Sopenharmony_ci	unsigned long flags;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	ether_addr_copy(common->curbssid, avp->bssid);
11278c2ecf20Sopenharmony_ci	common->curaid = avp->aid;
11288c2ecf20Sopenharmony_ci	ath9k_hw_write_associd(sc->sc_ah);
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	if (changed) {
11318c2ecf20Sopenharmony_ci		common->last_rssi = ATH_RSSI_DUMMY_MARKER;
11328c2ecf20Sopenharmony_ci		sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci		spin_lock_irqsave(&sc->sc_pm_lock, flags);
11358c2ecf20Sopenharmony_ci		sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
11368c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
11378c2ecf20Sopenharmony_ci	}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	if (ath9k_hw_mci_is_enabled(sc->sc_ah))
11408c2ecf20Sopenharmony_ci		ath9k_mci_update_wlan_channels(sc, false);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG,
11438c2ecf20Sopenharmony_ci		"Primary Station interface: %pM, BSSID: %pM\n",
11448c2ecf20Sopenharmony_ci		vif->addr, common->curbssid);
11458c2ecf20Sopenharmony_ci}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
11488c2ecf20Sopenharmony_cistatic void ath9k_set_offchannel_state(struct ath_softc *sc)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
11518c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
11528c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = NULL;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START)
11578c2ecf20Sopenharmony_ci		vif = sc->offchannel.scan_vif;
11588c2ecf20Sopenharmony_ci	else
11598c2ecf20Sopenharmony_ci		vif = sc->offchannel.roc_vif;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	if (WARN_ON(!vif))
11628c2ecf20Sopenharmony_ci		goto exit;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	eth_zero_addr(common->curbssid);
11658c2ecf20Sopenharmony_ci	eth_broadcast_addr(common->bssidmask);
11668c2ecf20Sopenharmony_ci	memcpy(common->macaddr, vif->addr, ETH_ALEN);
11678c2ecf20Sopenharmony_ci	common->curaid = 0;
11688c2ecf20Sopenharmony_ci	ah->opmode = vif->type;
11698c2ecf20Sopenharmony_ci	ah->imask &= ~ATH9K_INT_SWBA;
11708c2ecf20Sopenharmony_ci	ah->imask &= ~ATH9K_INT_TSFOOR;
11718c2ecf20Sopenharmony_ci	ah->slottime = 9;
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	ath_hw_setbssidmask(common);
11748c2ecf20Sopenharmony_ci	ath9k_hw_setopmode(ah);
11758c2ecf20Sopenharmony_ci	ath9k_hw_write_associd(sc->sc_ah);
11768c2ecf20Sopenharmony_ci	ath9k_hw_set_interrupts(ah);
11778c2ecf20Sopenharmony_ci	ath9k_hw_init_global_settings(ah);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ciexit:
11808c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
11818c2ecf20Sopenharmony_ci}
11828c2ecf20Sopenharmony_ci#endif
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci/* Called with sc->mutex held. */
11858c2ecf20Sopenharmony_civoid ath9k_calculate_summary_state(struct ath_softc *sc,
11868c2ecf20Sopenharmony_ci				   struct ath_chanctx *ctx)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
11898c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
11908c2ecf20Sopenharmony_ci	struct ath9k_vif_iter_data iter_data;
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	ath_chanctx_check_active(sc, ctx);
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	if (ctx != sc->cur_chan)
11958c2ecf20Sopenharmony_ci		return;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
11988c2ecf20Sopenharmony_ci	if (ctx == &sc->offchannel.chan)
11998c2ecf20Sopenharmony_ci		return ath9k_set_offchannel_state(sc);
12008c2ecf20Sopenharmony_ci#endif
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
12038c2ecf20Sopenharmony_ci	ath9k_calculate_iter_data(sc, ctx, &iter_data);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	if (iter_data.has_hw_macaddr)
12068c2ecf20Sopenharmony_ci		memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
12098c2ecf20Sopenharmony_ci	ath_hw_setbssidmask(common);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	if (iter_data.naps > 0) {
12128c2ecf20Sopenharmony_ci		ath9k_hw_set_tsfadjust(ah, true);
12138c2ecf20Sopenharmony_ci		ah->opmode = NL80211_IFTYPE_AP;
12148c2ecf20Sopenharmony_ci	} else {
12158c2ecf20Sopenharmony_ci		ath9k_hw_set_tsfadjust(ah, false);
12168c2ecf20Sopenharmony_ci		if (iter_data.beacons)
12178c2ecf20Sopenharmony_ci			ath9k_beacon_ensure_primary_slot(sc);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci		if (iter_data.nmeshes)
12208c2ecf20Sopenharmony_ci			ah->opmode = NL80211_IFTYPE_MESH_POINT;
12218c2ecf20Sopenharmony_ci		else if (iter_data.nocbs)
12228c2ecf20Sopenharmony_ci			ah->opmode = NL80211_IFTYPE_OCB;
12238c2ecf20Sopenharmony_ci		else if (iter_data.nwds)
12248c2ecf20Sopenharmony_ci			ah->opmode = NL80211_IFTYPE_AP;
12258c2ecf20Sopenharmony_ci		else if (iter_data.nadhocs)
12268c2ecf20Sopenharmony_ci			ah->opmode = NL80211_IFTYPE_ADHOC;
12278c2ecf20Sopenharmony_ci		else
12288c2ecf20Sopenharmony_ci			ah->opmode = NL80211_IFTYPE_STATION;
12298c2ecf20Sopenharmony_ci	}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	ath9k_hw_setopmode(ah);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	ctx->switch_after_beacon = false;
12348c2ecf20Sopenharmony_ci	if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0)
12358c2ecf20Sopenharmony_ci		ah->imask |= ATH9K_INT_TSFOOR;
12368c2ecf20Sopenharmony_ci	else {
12378c2ecf20Sopenharmony_ci		ah->imask &= ~ATH9K_INT_TSFOOR;
12388c2ecf20Sopenharmony_ci		if (iter_data.naps == 1 && iter_data.beacons)
12398c2ecf20Sopenharmony_ci			ctx->switch_after_beacon = true;
12408c2ecf20Sopenharmony_ci	}
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	if (ah->opmode == NL80211_IFTYPE_STATION) {
12438c2ecf20Sopenharmony_ci		bool changed = (iter_data.primary_sta != ctx->primary_sta);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci		if (iter_data.primary_sta) {
12468c2ecf20Sopenharmony_ci			iter_data.primary_beacon_vif = iter_data.primary_sta;
12478c2ecf20Sopenharmony_ci			iter_data.beacons = true;
12488c2ecf20Sopenharmony_ci			ath9k_set_assoc_state(sc, iter_data.primary_sta,
12498c2ecf20Sopenharmony_ci					      changed);
12508c2ecf20Sopenharmony_ci			ctx->primary_sta = iter_data.primary_sta;
12518c2ecf20Sopenharmony_ci		} else {
12528c2ecf20Sopenharmony_ci			ctx->primary_sta = NULL;
12538c2ecf20Sopenharmony_ci			eth_zero_addr(common->curbssid);
12548c2ecf20Sopenharmony_ci			common->curaid = 0;
12558c2ecf20Sopenharmony_ci			ath9k_hw_write_associd(sc->sc_ah);
12568c2ecf20Sopenharmony_ci			if (ath9k_hw_mci_is_enabled(sc->sc_ah))
12578c2ecf20Sopenharmony_ci				ath9k_mci_update_wlan_channels(sc, true);
12588c2ecf20Sopenharmony_ci		}
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci	sc->nbcnvifs = iter_data.nbcnvifs;
12618c2ecf20Sopenharmony_ci	ath9k_beacon_config(sc, iter_data.primary_beacon_vif,
12628c2ecf20Sopenharmony_ci			    iter_data.beacons);
12638c2ecf20Sopenharmony_ci	ath9k_hw_set_interrupts(ah);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	if (ah->slottime != iter_data.slottime) {
12668c2ecf20Sopenharmony_ci		ah->slottime = iter_data.slottime;
12678c2ecf20Sopenharmony_ci		ath9k_hw_init_global_settings(ah);
12688c2ecf20Sopenharmony_ci	}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	if (iter_data.primary_sta)
12718c2ecf20Sopenharmony_ci		set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
12728c2ecf20Sopenharmony_ci	else
12738c2ecf20Sopenharmony_ci		clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags);
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG,
12768c2ecf20Sopenharmony_ci		"macaddr: %pM, bssid: %pM, bssidmask: %pM\n",
12778c2ecf20Sopenharmony_ci		common->macaddr, common->curbssid, common->bssidmask);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
12808c2ecf20Sopenharmony_ci}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_cistatic void ath9k_tpc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
12838c2ecf20Sopenharmony_ci{
12848c2ecf20Sopenharmony_ci	int *power = data;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	if (vif->bss_conf.txpower == INT_MIN)
12878c2ecf20Sopenharmony_ci		return;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	if (*power < vif->bss_conf.txpower)
12908c2ecf20Sopenharmony_ci		*power = vif->bss_conf.txpower;
12918c2ecf20Sopenharmony_ci}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci/* Called with sc->mutex held. */
12948c2ecf20Sopenharmony_civoid ath9k_set_txpower(struct ath_softc *sc, struct ieee80211_vif *vif)
12958c2ecf20Sopenharmony_ci{
12968c2ecf20Sopenharmony_ci	int power;
12978c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
12988c2ecf20Sopenharmony_ci	struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
13018c2ecf20Sopenharmony_ci	if (ah->tpc_enabled) {
13028c2ecf20Sopenharmony_ci		power = (vif) ? vif->bss_conf.txpower : -1;
13038c2ecf20Sopenharmony_ci		ieee80211_iterate_active_interfaces_atomic(
13048c2ecf20Sopenharmony_ci				sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
13058c2ecf20Sopenharmony_ci				ath9k_tpc_vif_iter, &power);
13068c2ecf20Sopenharmony_ci		if (power == -1)
13078c2ecf20Sopenharmony_ci			power = sc->hw->conf.power_level;
13088c2ecf20Sopenharmony_ci	} else {
13098c2ecf20Sopenharmony_ci		power = sc->hw->conf.power_level;
13108c2ecf20Sopenharmony_ci	}
13118c2ecf20Sopenharmony_ci	sc->cur_chan->txpower = 2 * power;
13128c2ecf20Sopenharmony_ci	ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
13138c2ecf20Sopenharmony_ci	sc->cur_chan->cur_txpower = reg->max_power_level;
13148c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
13158c2ecf20Sopenharmony_ci}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_cistatic void ath9k_assign_hw_queues(struct ieee80211_hw *hw,
13188c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif)
13198c2ecf20Sopenharmony_ci{
13208c2ecf20Sopenharmony_ci	int i;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	if (!ath9k_is_chanctx_enabled())
13238c2ecf20Sopenharmony_ci		return;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE80211_NUM_ACS; i++)
13268c2ecf20Sopenharmony_ci		vif->hw_queue[i] = i;
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_AP ||
13298c2ecf20Sopenharmony_ci	    vif->type == NL80211_IFTYPE_MESH_POINT)
13308c2ecf20Sopenharmony_ci		vif->cab_queue = hw->queues - 2;
13318c2ecf20Sopenharmony_ci	else
13328c2ecf20Sopenharmony_ci		vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
13338c2ecf20Sopenharmony_ci}
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_cistatic int ath9k_add_interface(struct ieee80211_hw *hw,
13368c2ecf20Sopenharmony_ci			       struct ieee80211_vif *vif)
13378c2ecf20Sopenharmony_ci{
13388c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
13398c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
13408c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
13418c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
13428c2ecf20Sopenharmony_ci	struct ath_node *an = &avp->mcast_node;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
13458c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_ATH9K_TX99)) {
13468c2ecf20Sopenharmony_ci		if (sc->cur_chan->nvifs >= 1) {
13478c2ecf20Sopenharmony_ci			mutex_unlock(&sc->mutex);
13488c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
13498c2ecf20Sopenharmony_ci		}
13508c2ecf20Sopenharmony_ci		sc->tx99_vif = vif;
13518c2ecf20Sopenharmony_ci	}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
13548c2ecf20Sopenharmony_ci	sc->cur_chan->nvifs++;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_STATION && ath9k_is_chanctx_enabled())
13578c2ecf20Sopenharmony_ci		vif->driver_flags |= IEEE80211_VIF_GET_NOA_UPDATE;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	if (ath9k_uses_beacons(vif->type))
13608c2ecf20Sopenharmony_ci		ath9k_beacon_assign_slot(sc, vif);
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	avp->vif = vif;
13638c2ecf20Sopenharmony_ci	if (!ath9k_is_chanctx_enabled()) {
13648c2ecf20Sopenharmony_ci		avp->chanctx = sc->cur_chan;
13658c2ecf20Sopenharmony_ci		list_add_tail(&avp->list, &avp->chanctx->vifs);
13668c2ecf20Sopenharmony_ci	}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	ath9k_calculate_summary_state(sc, avp->chanctx);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	ath9k_assign_hw_queues(hw, vif);
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	ath9k_set_txpower(sc, vif);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	an->sc = sc;
13758c2ecf20Sopenharmony_ci	an->sta = NULL;
13768c2ecf20Sopenharmony_ci	an->vif = vif;
13778c2ecf20Sopenharmony_ci	an->no_ps_filter = true;
13788c2ecf20Sopenharmony_ci	ath_tx_node_init(sc, an);
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
13818c2ecf20Sopenharmony_ci	return 0;
13828c2ecf20Sopenharmony_ci}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_cistatic int ath9k_change_interface(struct ieee80211_hw *hw,
13858c2ecf20Sopenharmony_ci				  struct ieee80211_vif *vif,
13868c2ecf20Sopenharmony_ci				  enum nl80211_iftype new_type,
13878c2ecf20Sopenharmony_ci				  bool p2p)
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
13908c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
13918c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_ATH9K_TX99)) {
13968c2ecf20Sopenharmony_ci		mutex_unlock(&sc->mutex);
13978c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13988c2ecf20Sopenharmony_ci	}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG, "Change Interface\n");
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	if (ath9k_uses_beacons(vif->type))
14038c2ecf20Sopenharmony_ci		ath9k_beacon_remove_slot(sc, vif);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	vif->type = new_type;
14068c2ecf20Sopenharmony_ci	vif->p2p = p2p;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	if (ath9k_uses_beacons(vif->type))
14098c2ecf20Sopenharmony_ci		ath9k_beacon_assign_slot(sc, vif);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	ath9k_assign_hw_queues(hw, vif);
14128c2ecf20Sopenharmony_ci	ath9k_calculate_summary_state(sc, avp->chanctx);
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	ath9k_set_txpower(sc, vif);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
14178c2ecf20Sopenharmony_ci	return 0;
14188c2ecf20Sopenharmony_ci}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_cistatic void ath9k_remove_interface(struct ieee80211_hw *hw,
14218c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif)
14228c2ecf20Sopenharmony_ci{
14238c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
14248c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
14258c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG, "Detach Interface\n");
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	ath9k_p2p_remove_vif(sc, vif);
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	sc->cur_chan->nvifs--;
14348c2ecf20Sopenharmony_ci	sc->tx99_vif = NULL;
14358c2ecf20Sopenharmony_ci	if (!ath9k_is_chanctx_enabled())
14368c2ecf20Sopenharmony_ci		list_del(&avp->list);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	if (ath9k_uses_beacons(vif->type))
14398c2ecf20Sopenharmony_ci		ath9k_beacon_remove_slot(sc, vif);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	ath_tx_node_cleanup(sc, &avp->mcast_node);
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	ath9k_calculate_summary_state(sc, avp->chanctx);
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	ath9k_set_txpower(sc, NULL);
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic void ath9k_enable_ps(struct ath_softc *sc)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
14538c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_ATH9K_TX99))
14568c2ecf20Sopenharmony_ci		return;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	sc->ps_enabled = true;
14598c2ecf20Sopenharmony_ci	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
14608c2ecf20Sopenharmony_ci		if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
14618c2ecf20Sopenharmony_ci			ah->imask |= ATH9K_INT_TIM_TIMER;
14628c2ecf20Sopenharmony_ci			ath9k_hw_set_interrupts(ah);
14638c2ecf20Sopenharmony_ci		}
14648c2ecf20Sopenharmony_ci		ath9k_hw_setrxabort(ah, 1);
14658c2ecf20Sopenharmony_ci	}
14668c2ecf20Sopenharmony_ci	ath_dbg(common, PS, "PowerSave enabled\n");
14678c2ecf20Sopenharmony_ci}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_cistatic void ath9k_disable_ps(struct ath_softc *sc)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
14728c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_ATH9K_TX99))
14758c2ecf20Sopenharmony_ci		return;
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	sc->ps_enabled = false;
14788c2ecf20Sopenharmony_ci	ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
14798c2ecf20Sopenharmony_ci	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
14808c2ecf20Sopenharmony_ci		ath9k_hw_setrxabort(ah, 0);
14818c2ecf20Sopenharmony_ci		sc->ps_flags &= ~(PS_WAIT_FOR_BEACON |
14828c2ecf20Sopenharmony_ci				  PS_WAIT_FOR_CAB |
14838c2ecf20Sopenharmony_ci				  PS_WAIT_FOR_PSPOLL_DATA |
14848c2ecf20Sopenharmony_ci				  PS_WAIT_FOR_TX_ACK);
14858c2ecf20Sopenharmony_ci		if (ah->imask & ATH9K_INT_TIM_TIMER) {
14868c2ecf20Sopenharmony_ci			ah->imask &= ~ATH9K_INT_TIM_TIMER;
14878c2ecf20Sopenharmony_ci			ath9k_hw_set_interrupts(ah);
14888c2ecf20Sopenharmony_ci		}
14898c2ecf20Sopenharmony_ci	}
14908c2ecf20Sopenharmony_ci	ath_dbg(common, PS, "PowerSave disabled\n");
14918c2ecf20Sopenharmony_ci}
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_cistatic int ath9k_config(struct ieee80211_hw *hw, u32 changed)
14948c2ecf20Sopenharmony_ci{
14958c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
14968c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
14978c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
14988c2ecf20Sopenharmony_ci	struct ieee80211_conf *conf = &hw->conf;
14998c2ecf20Sopenharmony_ci	struct ath_chanctx *ctx = sc->cur_chan;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
15028c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
15058c2ecf20Sopenharmony_ci		sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
15068c2ecf20Sopenharmony_ci		if (sc->ps_idle) {
15078c2ecf20Sopenharmony_ci			ath_cancel_work(sc);
15088c2ecf20Sopenharmony_ci			ath9k_stop_btcoex(sc);
15098c2ecf20Sopenharmony_ci		} else {
15108c2ecf20Sopenharmony_ci			ath9k_start_btcoex(sc);
15118c2ecf20Sopenharmony_ci			/*
15128c2ecf20Sopenharmony_ci			 * The chip needs a reset to properly wake up from
15138c2ecf20Sopenharmony_ci			 * full sleep
15148c2ecf20Sopenharmony_ci			 */
15158c2ecf20Sopenharmony_ci			ath_chanctx_set_channel(sc, ctx, &ctx->chandef);
15168c2ecf20Sopenharmony_ci		}
15178c2ecf20Sopenharmony_ci	}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	/*
15208c2ecf20Sopenharmony_ci	 * We just prepare to enable PS. We have to wait until our AP has
15218c2ecf20Sopenharmony_ci	 * ACK'd our null data frame to disable RX otherwise we'll ignore
15228c2ecf20Sopenharmony_ci	 * those ACKs and end up retransmitting the same null data frames.
15238c2ecf20Sopenharmony_ci	 * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
15248c2ecf20Sopenharmony_ci	 */
15258c2ecf20Sopenharmony_ci	if (changed & IEEE80211_CONF_CHANGE_PS) {
15268c2ecf20Sopenharmony_ci		unsigned long flags;
15278c2ecf20Sopenharmony_ci		spin_lock_irqsave(&sc->sc_pm_lock, flags);
15288c2ecf20Sopenharmony_ci		if (conf->flags & IEEE80211_CONF_PS)
15298c2ecf20Sopenharmony_ci			ath9k_enable_ps(sc);
15308c2ecf20Sopenharmony_ci		else
15318c2ecf20Sopenharmony_ci			ath9k_disable_ps(sc);
15328c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
15338c2ecf20Sopenharmony_ci	}
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
15368c2ecf20Sopenharmony_ci		if (conf->flags & IEEE80211_CONF_MONITOR) {
15378c2ecf20Sopenharmony_ci			ath_dbg(common, CONFIG, "Monitor mode is enabled\n");
15388c2ecf20Sopenharmony_ci			sc->sc_ah->is_monitoring = true;
15398c2ecf20Sopenharmony_ci		} else {
15408c2ecf20Sopenharmony_ci			ath_dbg(common, CONFIG, "Monitor mode is disabled\n");
15418c2ecf20Sopenharmony_ci			sc->sc_ah->is_monitoring = false;
15428c2ecf20Sopenharmony_ci		}
15438c2ecf20Sopenharmony_ci	}
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
15468c2ecf20Sopenharmony_ci		ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL);
15478c2ecf20Sopenharmony_ci		ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef);
15488c2ecf20Sopenharmony_ci	}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	if (changed & IEEE80211_CONF_CHANGE_POWER)
15518c2ecf20Sopenharmony_ci		ath9k_set_txpower(sc, NULL);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
15548c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	return 0;
15578c2ecf20Sopenharmony_ci}
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci#define SUPPORTED_FILTERS			\
15608c2ecf20Sopenharmony_ci	(FIF_ALLMULTI |				\
15618c2ecf20Sopenharmony_ci	FIF_CONTROL |				\
15628c2ecf20Sopenharmony_ci	FIF_PSPOLL |				\
15638c2ecf20Sopenharmony_ci	FIF_OTHER_BSS |				\
15648c2ecf20Sopenharmony_ci	FIF_BCN_PRBRESP_PROMISC |		\
15658c2ecf20Sopenharmony_ci	FIF_PROBE_REQ |				\
15668c2ecf20Sopenharmony_ci	FIF_MCAST_ACTION |			\
15678c2ecf20Sopenharmony_ci	FIF_FCSFAIL)
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci/* FIXME: sc->sc_full_reset ? */
15708c2ecf20Sopenharmony_cistatic void ath9k_configure_filter(struct ieee80211_hw *hw,
15718c2ecf20Sopenharmony_ci				   unsigned int changed_flags,
15728c2ecf20Sopenharmony_ci				   unsigned int *total_flags,
15738c2ecf20Sopenharmony_ci				   u64 multicast)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
15768c2ecf20Sopenharmony_ci	struct ath_chanctx *ctx;
15778c2ecf20Sopenharmony_ci	u32 rfilt;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	changed_flags &= SUPPORTED_FILTERS;
15808c2ecf20Sopenharmony_ci	*total_flags &= SUPPORTED_FILTERS;
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->chan_lock);
15838c2ecf20Sopenharmony_ci	ath_for_each_chanctx(sc, ctx)
15848c2ecf20Sopenharmony_ci		ctx->rxfilter = *total_flags;
15858c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
15868c2ecf20Sopenharmony_ci	sc->offchannel.chan.rxfilter = *total_flags;
15878c2ecf20Sopenharmony_ci#endif
15888c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->chan_lock);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
15918c2ecf20Sopenharmony_ci	rfilt = ath_calcrxfilter(sc);
15928c2ecf20Sopenharmony_ci	ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
15938c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, "Set HW RX filter: 0x%x\n",
15968c2ecf20Sopenharmony_ci		rfilt);
15978c2ecf20Sopenharmony_ci}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_cistatic int ath9k_sta_add(struct ieee80211_hw *hw,
16008c2ecf20Sopenharmony_ci			 struct ieee80211_vif *vif,
16018c2ecf20Sopenharmony_ci			 struct ieee80211_sta *sta)
16028c2ecf20Sopenharmony_ci{
16038c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
16048c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
16058c2ecf20Sopenharmony_ci	struct ath_node *an = (struct ath_node *) sta->drv_priv;
16068c2ecf20Sopenharmony_ci	struct ieee80211_key_conf ps_key = { };
16078c2ecf20Sopenharmony_ci	int key;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	ath_node_attach(sc, sta, vif);
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_AP &&
16128c2ecf20Sopenharmony_ci	    vif->type != NL80211_IFTYPE_AP_VLAN)
16138c2ecf20Sopenharmony_ci		return 0;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	key = ath_key_config(common, vif, sta, &ps_key);
16168c2ecf20Sopenharmony_ci	if (key > 0) {
16178c2ecf20Sopenharmony_ci		an->ps_key = key;
16188c2ecf20Sopenharmony_ci		an->key_idx[0] = key;
16198c2ecf20Sopenharmony_ci	}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	return 0;
16228c2ecf20Sopenharmony_ci}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_cistatic void ath9k_del_ps_key(struct ath_softc *sc,
16258c2ecf20Sopenharmony_ci			     struct ieee80211_vif *vif,
16268c2ecf20Sopenharmony_ci			     struct ieee80211_sta *sta)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
16298c2ecf20Sopenharmony_ci	struct ath_node *an = (struct ath_node *) sta->drv_priv;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	if (!an->ps_key)
16328c2ecf20Sopenharmony_ci	    return;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	ath_key_delete(common, an->ps_key);
16358c2ecf20Sopenharmony_ci	an->ps_key = 0;
16368c2ecf20Sopenharmony_ci	an->key_idx[0] = 0;
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_cistatic int ath9k_sta_remove(struct ieee80211_hw *hw,
16408c2ecf20Sopenharmony_ci			    struct ieee80211_vif *vif,
16418c2ecf20Sopenharmony_ci			    struct ieee80211_sta *sta)
16428c2ecf20Sopenharmony_ci{
16438c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	ath9k_del_ps_key(sc, vif, sta);
16468c2ecf20Sopenharmony_ci	ath_node_detach(sc, sta);
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	return 0;
16498c2ecf20Sopenharmony_ci}
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_cistatic int ath9k_sta_state(struct ieee80211_hw *hw,
16528c2ecf20Sopenharmony_ci			   struct ieee80211_vif *vif,
16538c2ecf20Sopenharmony_ci			   struct ieee80211_sta *sta,
16548c2ecf20Sopenharmony_ci			   enum ieee80211_sta_state old_state,
16558c2ecf20Sopenharmony_ci			   enum ieee80211_sta_state new_state)
16568c2ecf20Sopenharmony_ci{
16578c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
16588c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
16598c2ecf20Sopenharmony_ci	int ret = 0;
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	if (old_state == IEEE80211_STA_NOTEXIST &&
16628c2ecf20Sopenharmony_ci	    new_state == IEEE80211_STA_NONE) {
16638c2ecf20Sopenharmony_ci		ret = ath9k_sta_add(hw, vif, sta);
16648c2ecf20Sopenharmony_ci		ath_dbg(common, CONFIG,
16658c2ecf20Sopenharmony_ci			"Add station: %pM\n", sta->addr);
16668c2ecf20Sopenharmony_ci	} else if (old_state == IEEE80211_STA_NONE &&
16678c2ecf20Sopenharmony_ci		   new_state == IEEE80211_STA_NOTEXIST) {
16688c2ecf20Sopenharmony_ci		ret = ath9k_sta_remove(hw, vif, sta);
16698c2ecf20Sopenharmony_ci		ath_dbg(common, CONFIG,
16708c2ecf20Sopenharmony_ci			"Remove station: %pM\n", sta->addr);
16718c2ecf20Sopenharmony_ci	}
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	if (ath9k_is_chanctx_enabled()) {
16748c2ecf20Sopenharmony_ci		if (vif->type == NL80211_IFTYPE_STATION) {
16758c2ecf20Sopenharmony_ci			if (old_state == IEEE80211_STA_ASSOC &&
16768c2ecf20Sopenharmony_ci			    new_state == IEEE80211_STA_AUTHORIZED)
16778c2ecf20Sopenharmony_ci				ath_chanctx_event(sc, vif,
16788c2ecf20Sopenharmony_ci						  ATH_CHANCTX_EVENT_AUTHORIZED);
16798c2ecf20Sopenharmony_ci		}
16808c2ecf20Sopenharmony_ci	}
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	return ret;
16838c2ecf20Sopenharmony_ci}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_cistatic void ath9k_sta_set_tx_filter(struct ath_hw *ah,
16868c2ecf20Sopenharmony_ci				    struct ath_node *an,
16878c2ecf20Sopenharmony_ci				    bool set)
16888c2ecf20Sopenharmony_ci{
16898c2ecf20Sopenharmony_ci	int i;
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
16928c2ecf20Sopenharmony_ci		if (!an->key_idx[i])
16938c2ecf20Sopenharmony_ci			continue;
16948c2ecf20Sopenharmony_ci		ath9k_hw_set_tx_filter(ah, an->key_idx[i], set);
16958c2ecf20Sopenharmony_ci	}
16968c2ecf20Sopenharmony_ci}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_cistatic void ath9k_sta_notify(struct ieee80211_hw *hw,
16998c2ecf20Sopenharmony_ci			 struct ieee80211_vif *vif,
17008c2ecf20Sopenharmony_ci			 enum sta_notify_cmd cmd,
17018c2ecf20Sopenharmony_ci			 struct ieee80211_sta *sta)
17028c2ecf20Sopenharmony_ci{
17038c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
17048c2ecf20Sopenharmony_ci	struct ath_node *an = (struct ath_node *) sta->drv_priv;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	switch (cmd) {
17078c2ecf20Sopenharmony_ci	case STA_NOTIFY_SLEEP:
17088c2ecf20Sopenharmony_ci		an->sleeping = true;
17098c2ecf20Sopenharmony_ci		ath_tx_aggr_sleep(sta, sc, an);
17108c2ecf20Sopenharmony_ci		ath9k_sta_set_tx_filter(sc->sc_ah, an, true);
17118c2ecf20Sopenharmony_ci		break;
17128c2ecf20Sopenharmony_ci	case STA_NOTIFY_AWAKE:
17138c2ecf20Sopenharmony_ci		ath9k_sta_set_tx_filter(sc->sc_ah, an, false);
17148c2ecf20Sopenharmony_ci		an->sleeping = false;
17158c2ecf20Sopenharmony_ci		ath_tx_aggr_wakeup(sc, an);
17168c2ecf20Sopenharmony_ci		break;
17178c2ecf20Sopenharmony_ci	}
17188c2ecf20Sopenharmony_ci}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_cistatic int ath9k_conf_tx(struct ieee80211_hw *hw,
17218c2ecf20Sopenharmony_ci			 struct ieee80211_vif *vif, u16 queue,
17228c2ecf20Sopenharmony_ci			 const struct ieee80211_tx_queue_params *params)
17238c2ecf20Sopenharmony_ci{
17248c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
17258c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
17268c2ecf20Sopenharmony_ci	struct ath_txq *txq;
17278c2ecf20Sopenharmony_ci	struct ath9k_tx_queue_info qi;
17288c2ecf20Sopenharmony_ci	int ret = 0;
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	if (queue >= IEEE80211_NUM_ACS)
17318c2ecf20Sopenharmony_ci		return 0;
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	txq = sc->tx.txq_map[queue];
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
17368c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	qi.tqi_aifs = params->aifs;
17418c2ecf20Sopenharmony_ci	qi.tqi_cwmin = params->cw_min;
17428c2ecf20Sopenharmony_ci	qi.tqi_cwmax = params->cw_max;
17438c2ecf20Sopenharmony_ci	qi.tqi_burstTime = params->txop * 32;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG,
17468c2ecf20Sopenharmony_ci		"Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
17478c2ecf20Sopenharmony_ci		queue, txq->axq_qnum, params->aifs, params->cw_min,
17488c2ecf20Sopenharmony_ci		params->cw_max, params->txop);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	ath_update_max_aggr_framelen(sc, queue, qi.tqi_burstTime);
17518c2ecf20Sopenharmony_ci	ret = ath_txq_update(sc, txq->axq_qnum, &qi);
17528c2ecf20Sopenharmony_ci	if (ret)
17538c2ecf20Sopenharmony_ci		ath_err(common, "TXQ Update failed\n");
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
17568c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	return ret;
17598c2ecf20Sopenharmony_ci}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_cistatic int ath9k_set_key(struct ieee80211_hw *hw,
17628c2ecf20Sopenharmony_ci			 enum set_key_cmd cmd,
17638c2ecf20Sopenharmony_ci			 struct ieee80211_vif *vif,
17648c2ecf20Sopenharmony_ci			 struct ieee80211_sta *sta,
17658c2ecf20Sopenharmony_ci			 struct ieee80211_key_conf *key)
17668c2ecf20Sopenharmony_ci{
17678c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
17688c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
17698c2ecf20Sopenharmony_ci	struct ath_node *an = NULL;
17708c2ecf20Sopenharmony_ci	int ret = 0, i;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	if (ath9k_modparam_nohwcrypt)
17738c2ecf20Sopenharmony_ci		return -ENOSPC;
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	if ((vif->type == NL80211_IFTYPE_ADHOC ||
17768c2ecf20Sopenharmony_ci	     vif->type == NL80211_IFTYPE_MESH_POINT) &&
17778c2ecf20Sopenharmony_ci	    (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
17788c2ecf20Sopenharmony_ci	     key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
17798c2ecf20Sopenharmony_ci	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
17808c2ecf20Sopenharmony_ci		/*
17818c2ecf20Sopenharmony_ci		 * For now, disable hw crypto for the RSN IBSS group keys. This
17828c2ecf20Sopenharmony_ci		 * could be optimized in the future to use a modified key cache
17838c2ecf20Sopenharmony_ci		 * design to support per-STA RX GTK, but until that gets
17848c2ecf20Sopenharmony_ci		 * implemented, use of software crypto for group addressed
17858c2ecf20Sopenharmony_ci		 * frames is a acceptable to allow RSN IBSS to be used.
17868c2ecf20Sopenharmony_ci		 */
17878c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17888c2ecf20Sopenharmony_ci	}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	/* There may be MPDUs queued for the outgoing PTK key. Flush queues to
17918c2ecf20Sopenharmony_ci	 * make sure these are not send unencrypted or with a wrong (new) key
17928c2ecf20Sopenharmony_ci	 */
17938c2ecf20Sopenharmony_ci	if (cmd == DISABLE_KEY && key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
17948c2ecf20Sopenharmony_ci		ieee80211_stop_queues(hw);
17958c2ecf20Sopenharmony_ci		ath9k_flush(hw, vif, 0, true);
17968c2ecf20Sopenharmony_ci		ieee80211_wake_queues(hw);
17978c2ecf20Sopenharmony_ci	}
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
18008c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
18018c2ecf20Sopenharmony_ci	ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd);
18028c2ecf20Sopenharmony_ci	if (sta)
18038c2ecf20Sopenharmony_ci		an = (struct ath_node *)sta->drv_priv;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	/* Delete pending key cache entries if no more frames are pointing to
18068c2ecf20Sopenharmony_ci	 * them in TXQs.
18078c2ecf20Sopenharmony_ci	 */
18088c2ecf20Sopenharmony_ci	for (i = 0; i < ATH_KEYMAX; i++)
18098c2ecf20Sopenharmony_ci		ath9k_pending_key_del(sc, i);
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	switch (cmd) {
18128c2ecf20Sopenharmony_ci	case SET_KEY:
18138c2ecf20Sopenharmony_ci		if (sta)
18148c2ecf20Sopenharmony_ci			ath9k_del_ps_key(sc, vif, sta);
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci		key->hw_key_idx = 0;
18178c2ecf20Sopenharmony_ci		ret = ath_key_config(common, vif, sta, key);
18188c2ecf20Sopenharmony_ci		if (ret >= 0) {
18198c2ecf20Sopenharmony_ci			key->hw_key_idx = ret;
18208c2ecf20Sopenharmony_ci			/* push IV and Michael MIC generation to stack */
18218c2ecf20Sopenharmony_ci			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
18228c2ecf20Sopenharmony_ci			if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
18238c2ecf20Sopenharmony_ci				key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
18248c2ecf20Sopenharmony_ci			if (sc->sc_ah->sw_mgmt_crypto_tx &&
18258c2ecf20Sopenharmony_ci			    key->cipher == WLAN_CIPHER_SUITE_CCMP)
18268c2ecf20Sopenharmony_ci				key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
18278c2ecf20Sopenharmony_ci			ret = 0;
18288c2ecf20Sopenharmony_ci		}
18298c2ecf20Sopenharmony_ci		if (an && key->hw_key_idx) {
18308c2ecf20Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
18318c2ecf20Sopenharmony_ci				if (an->key_idx[i])
18328c2ecf20Sopenharmony_ci					continue;
18338c2ecf20Sopenharmony_ci				an->key_idx[i] = key->hw_key_idx;
18348c2ecf20Sopenharmony_ci				break;
18358c2ecf20Sopenharmony_ci			}
18368c2ecf20Sopenharmony_ci			WARN_ON(i == ARRAY_SIZE(an->key_idx));
18378c2ecf20Sopenharmony_ci		}
18388c2ecf20Sopenharmony_ci		break;
18398c2ecf20Sopenharmony_ci	case DISABLE_KEY:
18408c2ecf20Sopenharmony_ci		if (ath9k_txq_has_key(sc, key->hw_key_idx)) {
18418c2ecf20Sopenharmony_ci			/* Delay key cache entry deletion until there are no
18428c2ecf20Sopenharmony_ci			 * remaining TXQ frames pointing to this entry.
18438c2ecf20Sopenharmony_ci			 */
18448c2ecf20Sopenharmony_ci			set_bit(key->hw_key_idx, sc->sc_ah->pending_del_keymap);
18458c2ecf20Sopenharmony_ci			ath_hw_keysetmac(common, key->hw_key_idx, NULL);
18468c2ecf20Sopenharmony_ci		} else {
18478c2ecf20Sopenharmony_ci			ath_key_delete(common, key->hw_key_idx);
18488c2ecf20Sopenharmony_ci		}
18498c2ecf20Sopenharmony_ci		if (an) {
18508c2ecf20Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
18518c2ecf20Sopenharmony_ci				if (an->key_idx[i] != key->hw_key_idx)
18528c2ecf20Sopenharmony_ci					continue;
18538c2ecf20Sopenharmony_ci				an->key_idx[i] = 0;
18548c2ecf20Sopenharmony_ci				break;
18558c2ecf20Sopenharmony_ci			}
18568c2ecf20Sopenharmony_ci		}
18578c2ecf20Sopenharmony_ci		key->hw_key_idx = 0;
18588c2ecf20Sopenharmony_ci		break;
18598c2ecf20Sopenharmony_ci	default:
18608c2ecf20Sopenharmony_ci		ret = -EINVAL;
18618c2ecf20Sopenharmony_ci	}
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
18648c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	return ret;
18678c2ecf20Sopenharmony_ci}
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_cistatic void ath9k_bss_info_changed(struct ieee80211_hw *hw,
18708c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif,
18718c2ecf20Sopenharmony_ci				   struct ieee80211_bss_conf *bss_conf,
18728c2ecf20Sopenharmony_ci				   u32 changed)
18738c2ecf20Sopenharmony_ci{
18748c2ecf20Sopenharmony_ci#define CHECK_ANI				\
18758c2ecf20Sopenharmony_ci	(BSS_CHANGED_ASSOC |			\
18768c2ecf20Sopenharmony_ci	 BSS_CHANGED_IBSS |			\
18778c2ecf20Sopenharmony_ci	 BSS_CHANGED_BEACON_ENABLED)
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
18808c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
18818c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
18828c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
18838c2ecf20Sopenharmony_ci	int slottime;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
18868c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_ASSOC) {
18898c2ecf20Sopenharmony_ci		ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
18908c2ecf20Sopenharmony_ci			bss_conf->bssid, bss_conf->assoc);
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci		memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
18938c2ecf20Sopenharmony_ci		avp->aid = bss_conf->aid;
18948c2ecf20Sopenharmony_ci		avp->assoc = bss_conf->assoc;
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci		ath9k_calculate_summary_state(sc, avp->chanctx);
18978c2ecf20Sopenharmony_ci	}
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	if ((changed & BSS_CHANGED_IBSS) ||
19008c2ecf20Sopenharmony_ci	      (changed & BSS_CHANGED_OCB)) {
19018c2ecf20Sopenharmony_ci		memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
19028c2ecf20Sopenharmony_ci		common->curaid = bss_conf->aid;
19038c2ecf20Sopenharmony_ci		ath9k_hw_write_associd(sc->sc_ah);
19048c2ecf20Sopenharmony_ci	}
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
19078c2ecf20Sopenharmony_ci	    (changed & BSS_CHANGED_BEACON_INT) ||
19088c2ecf20Sopenharmony_ci	    (changed & BSS_CHANGED_BEACON_INFO)) {
19098c2ecf20Sopenharmony_ci		ath9k_calculate_summary_state(sc, avp->chanctx);
19108c2ecf20Sopenharmony_ci	}
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	if ((avp->chanctx == sc->cur_chan) &&
19138c2ecf20Sopenharmony_ci	    (changed & BSS_CHANGED_ERP_SLOT)) {
19148c2ecf20Sopenharmony_ci		if (bss_conf->use_short_slot)
19158c2ecf20Sopenharmony_ci			slottime = 9;
19168c2ecf20Sopenharmony_ci		else
19178c2ecf20Sopenharmony_ci			slottime = 20;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci		if (vif->type == NL80211_IFTYPE_AP) {
19208c2ecf20Sopenharmony_ci			/*
19218c2ecf20Sopenharmony_ci			 * Defer update, so that connected stations can adjust
19228c2ecf20Sopenharmony_ci			 * their settings at the same time.
19238c2ecf20Sopenharmony_ci			 * See beacon.c for more details
19248c2ecf20Sopenharmony_ci			 */
19258c2ecf20Sopenharmony_ci			sc->beacon.slottime = slottime;
19268c2ecf20Sopenharmony_ci			sc->beacon.updateslot = UPDATE;
19278c2ecf20Sopenharmony_ci		} else {
19288c2ecf20Sopenharmony_ci			ah->slottime = slottime;
19298c2ecf20Sopenharmony_ci			ath9k_hw_init_global_settings(ah);
19308c2ecf20Sopenharmony_ci		}
19318c2ecf20Sopenharmony_ci	}
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_P2P_PS)
19348c2ecf20Sopenharmony_ci		ath9k_p2p_bss_info_changed(sc, vif);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	if (changed & CHECK_ANI)
19378c2ecf20Sopenharmony_ci		ath_check_ani(sc);
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_TXPOWER) {
19408c2ecf20Sopenharmony_ci		ath_dbg(common, CONFIG, "vif %pM power %d dbm power_type %d\n",
19418c2ecf20Sopenharmony_ci			vif->addr, bss_conf->txpower, bss_conf->txpower_type);
19428c2ecf20Sopenharmony_ci		ath9k_set_txpower(sc, vif);
19438c2ecf20Sopenharmony_ci	}
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
19468c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci#undef CHECK_ANI
19498c2ecf20Sopenharmony_ci}
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_cistatic u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
19528c2ecf20Sopenharmony_ci{
19538c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
19548c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
19558c2ecf20Sopenharmony_ci	u64 tsf;
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
19588c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
19598c2ecf20Sopenharmony_ci	/* Get current TSF either from HW or kernel time. */
19608c2ecf20Sopenharmony_ci	if (sc->cur_chan == avp->chanctx) {
19618c2ecf20Sopenharmony_ci		tsf = ath9k_hw_gettsf64(sc->sc_ah);
19628c2ecf20Sopenharmony_ci	} else {
19638c2ecf20Sopenharmony_ci		tsf = sc->cur_chan->tsf_val +
19648c2ecf20Sopenharmony_ci		      ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
19658c2ecf20Sopenharmony_ci	}
19668c2ecf20Sopenharmony_ci	tsf += le64_to_cpu(avp->tsf_adjust);
19678c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
19688c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	return tsf;
19718c2ecf20Sopenharmony_ci}
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_cistatic void ath9k_set_tsf(struct ieee80211_hw *hw,
19748c2ecf20Sopenharmony_ci			  struct ieee80211_vif *vif,
19758c2ecf20Sopenharmony_ci			  u64 tsf)
19768c2ecf20Sopenharmony_ci{
19778c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
19788c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
19818c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
19828c2ecf20Sopenharmony_ci	tsf -= le64_to_cpu(avp->tsf_adjust);
19838c2ecf20Sopenharmony_ci	ktime_get_raw_ts64(&avp->chanctx->tsf_ts);
19848c2ecf20Sopenharmony_ci	if (sc->cur_chan == avp->chanctx)
19858c2ecf20Sopenharmony_ci		ath9k_hw_settsf64(sc->sc_ah, tsf);
19868c2ecf20Sopenharmony_ci	avp->chanctx->tsf_val = tsf;
19878c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
19888c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
19898c2ecf20Sopenharmony_ci}
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_cistatic void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
19928c2ecf20Sopenharmony_ci{
19938c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
19948c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
19998c2ecf20Sopenharmony_ci	ktime_get_raw_ts64(&avp->chanctx->tsf_ts);
20008c2ecf20Sopenharmony_ci	if (sc->cur_chan == avp->chanctx)
20018c2ecf20Sopenharmony_ci		ath9k_hw_reset_tsf(sc->sc_ah);
20028c2ecf20Sopenharmony_ci	avp->chanctx->tsf_val = 0;
20038c2ecf20Sopenharmony_ci	ath9k_ps_restore(sc);
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
20068c2ecf20Sopenharmony_ci}
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_cistatic int ath9k_ampdu_action(struct ieee80211_hw *hw,
20098c2ecf20Sopenharmony_ci			      struct ieee80211_vif *vif,
20108c2ecf20Sopenharmony_ci			      struct ieee80211_ampdu_params *params)
20118c2ecf20Sopenharmony_ci{
20128c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
20138c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
20148c2ecf20Sopenharmony_ci	bool flush = false;
20158c2ecf20Sopenharmony_ci	int ret = 0;
20168c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta = params->sta;
20178c2ecf20Sopenharmony_ci	struct ath_node *an = (struct ath_node *)sta->drv_priv;
20188c2ecf20Sopenharmony_ci	enum ieee80211_ampdu_mlme_action action = params->action;
20198c2ecf20Sopenharmony_ci	u16 tid = params->tid;
20208c2ecf20Sopenharmony_ci	u16 *ssn = &params->ssn;
20218c2ecf20Sopenharmony_ci	struct ath_atx_tid *atid;
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	switch (action) {
20268c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_RX_START:
20278c2ecf20Sopenharmony_ci		break;
20288c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_RX_STOP:
20298c2ecf20Sopenharmony_ci		break;
20308c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_START:
20318c2ecf20Sopenharmony_ci		if (ath9k_is_chanctx_enabled()) {
20328c2ecf20Sopenharmony_ci			if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
20338c2ecf20Sopenharmony_ci				ret = -EBUSY;
20348c2ecf20Sopenharmony_ci				break;
20358c2ecf20Sopenharmony_ci			}
20368c2ecf20Sopenharmony_ci		}
20378c2ecf20Sopenharmony_ci		ath9k_ps_wakeup(sc);
20388c2ecf20Sopenharmony_ci		ret = ath_tx_aggr_start(sc, sta, tid, ssn);
20398c2ecf20Sopenharmony_ci		if (!ret)
20408c2ecf20Sopenharmony_ci			ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
20418c2ecf20Sopenharmony_ci		ath9k_ps_restore(sc);
20428c2ecf20Sopenharmony_ci		break;
20438c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_STOP_FLUSH:
20448c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
20458c2ecf20Sopenharmony_ci		flush = true;
20468c2ecf20Sopenharmony_ci		fallthrough;
20478c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_STOP_CONT:
20488c2ecf20Sopenharmony_ci		ath9k_ps_wakeup(sc);
20498c2ecf20Sopenharmony_ci		ath_tx_aggr_stop(sc, sta, tid);
20508c2ecf20Sopenharmony_ci		if (!flush)
20518c2ecf20Sopenharmony_ci			ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
20528c2ecf20Sopenharmony_ci		ath9k_ps_restore(sc);
20538c2ecf20Sopenharmony_ci		break;
20548c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_OPERATIONAL:
20558c2ecf20Sopenharmony_ci		atid = ath_node_to_tid(an, tid);
20568c2ecf20Sopenharmony_ci		atid->baw_size = IEEE80211_MIN_AMPDU_BUF <<
20578c2ecf20Sopenharmony_ci			        sta->ht_cap.ampdu_factor;
20588c2ecf20Sopenharmony_ci		break;
20598c2ecf20Sopenharmony_ci	default:
20608c2ecf20Sopenharmony_ci		ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
20618c2ecf20Sopenharmony_ci	}
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	return ret;
20668c2ecf20Sopenharmony_ci}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_cistatic int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
20698c2ecf20Sopenharmony_ci			     struct survey_info *survey)
20708c2ecf20Sopenharmony_ci{
20718c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
20728c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
20738c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
20748c2ecf20Sopenharmony_ci	struct ieee80211_channel *chan;
20758c2ecf20Sopenharmony_ci	unsigned long flags;
20768c2ecf20Sopenharmony_ci	int pos;
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_ATH9K_TX99))
20798c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci	spin_lock_irqsave(&common->cc_lock, flags);
20828c2ecf20Sopenharmony_ci	if (idx == 0)
20838c2ecf20Sopenharmony_ci		ath_update_survey_stats(sc);
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	sband = hw->wiphy->bands[NL80211_BAND_2GHZ];
20868c2ecf20Sopenharmony_ci	if (sband && idx >= sband->n_channels) {
20878c2ecf20Sopenharmony_ci		idx -= sband->n_channels;
20888c2ecf20Sopenharmony_ci		sband = NULL;
20898c2ecf20Sopenharmony_ci	}
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci	if (!sband)
20928c2ecf20Sopenharmony_ci		sband = hw->wiphy->bands[NL80211_BAND_5GHZ];
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	if (!sband || idx >= sband->n_channels) {
20958c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&common->cc_lock, flags);
20968c2ecf20Sopenharmony_ci		return -ENOENT;
20978c2ecf20Sopenharmony_ci	}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci	chan = &sband->channels[idx];
21008c2ecf20Sopenharmony_ci	pos = chan->hw_value;
21018c2ecf20Sopenharmony_ci	memcpy(survey, &sc->survey[pos], sizeof(*survey));
21028c2ecf20Sopenharmony_ci	survey->channel = chan;
21038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&common->cc_lock, flags);
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	return 0;
21068c2ecf20Sopenharmony_ci}
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_cistatic void ath9k_enable_dynack(struct ath_softc *sc)
21098c2ecf20Sopenharmony_ci{
21108c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_DYNACK
21118c2ecf20Sopenharmony_ci	u32 rfilt;
21128c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	ath_dynack_reset(ah);
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	ah->dynack.enabled = true;
21178c2ecf20Sopenharmony_ci	rfilt = ath_calcrxfilter(sc);
21188c2ecf20Sopenharmony_ci	ath9k_hw_setrxfilter(ah, rfilt);
21198c2ecf20Sopenharmony_ci#endif
21208c2ecf20Sopenharmony_ci}
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_cistatic void ath9k_set_coverage_class(struct ieee80211_hw *hw,
21238c2ecf20Sopenharmony_ci				     s16 coverage_class)
21248c2ecf20Sopenharmony_ci{
21258c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
21268c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_ATH9K_TX99))
21298c2ecf20Sopenharmony_ci		return;
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	if (coverage_class >= 0) {
21348c2ecf20Sopenharmony_ci		ah->coverage_class = coverage_class;
21358c2ecf20Sopenharmony_ci		if (ah->dynack.enabled) {
21368c2ecf20Sopenharmony_ci			u32 rfilt;
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci			ah->dynack.enabled = false;
21398c2ecf20Sopenharmony_ci			rfilt = ath_calcrxfilter(sc);
21408c2ecf20Sopenharmony_ci			ath9k_hw_setrxfilter(ah, rfilt);
21418c2ecf20Sopenharmony_ci		}
21428c2ecf20Sopenharmony_ci		ath9k_ps_wakeup(sc);
21438c2ecf20Sopenharmony_ci		ath9k_hw_init_global_settings(ah);
21448c2ecf20Sopenharmony_ci		ath9k_ps_restore(sc);
21458c2ecf20Sopenharmony_ci	} else if (!ah->dynack.enabled) {
21468c2ecf20Sopenharmony_ci		ath9k_enable_dynack(sc);
21478c2ecf20Sopenharmony_ci	}
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
21508c2ecf20Sopenharmony_ci}
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_cistatic bool ath9k_has_tx_pending(struct ath_softc *sc,
21538c2ecf20Sopenharmony_ci				 bool sw_pending)
21548c2ecf20Sopenharmony_ci{
21558c2ecf20Sopenharmony_ci	int i, npend = 0;
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
21588c2ecf20Sopenharmony_ci		if (!ATH_TXQ_SETUP(sc, i))
21598c2ecf20Sopenharmony_ci			continue;
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci		npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i],
21628c2ecf20Sopenharmony_ci						 sw_pending);
21638c2ecf20Sopenharmony_ci		if (npend)
21648c2ecf20Sopenharmony_ci			break;
21658c2ecf20Sopenharmony_ci	}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	return !!npend;
21688c2ecf20Sopenharmony_ci}
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_cistatic void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
21718c2ecf20Sopenharmony_ci			u32 queues, bool drop)
21728c2ecf20Sopenharmony_ci{
21738c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
21748c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	if (ath9k_is_chanctx_enabled()) {
21778c2ecf20Sopenharmony_ci		if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
21788c2ecf20Sopenharmony_ci			goto flush;
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci		/*
21818c2ecf20Sopenharmony_ci		 * If MCC is active, extend the flush timeout
21828c2ecf20Sopenharmony_ci		 * and wait for the HW/SW queues to become
21838c2ecf20Sopenharmony_ci		 * empty. This needs to be done outside the
21848c2ecf20Sopenharmony_ci		 * sc->mutex lock to allow the channel scheduler
21858c2ecf20Sopenharmony_ci		 * to switch channel contexts.
21868c2ecf20Sopenharmony_ci		 *
21878c2ecf20Sopenharmony_ci		 * The vif queues have been stopped in mac80211,
21888c2ecf20Sopenharmony_ci		 * so there won't be any incoming frames.
21898c2ecf20Sopenharmony_ci		 */
21908c2ecf20Sopenharmony_ci		__ath9k_flush(hw, queues, drop, true, true);
21918c2ecf20Sopenharmony_ci		return;
21928c2ecf20Sopenharmony_ci	}
21938c2ecf20Sopenharmony_ciflush:
21948c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
21958c2ecf20Sopenharmony_ci	__ath9k_flush(hw, queues, drop, true, false);
21968c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
21978c2ecf20Sopenharmony_ci}
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_civoid __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
22008c2ecf20Sopenharmony_ci		   bool sw_pending, bool timeout_override)
22018c2ecf20Sopenharmony_ci{
22028c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
22038c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
22048c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
22058c2ecf20Sopenharmony_ci	int timeout;
22068c2ecf20Sopenharmony_ci	bool drain_txq;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&sc->hw_check_work);
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	if (ah->ah_flags & AH_UNPLUGGED) {
22118c2ecf20Sopenharmony_ci		ath_dbg(common, ANY, "Device has been unplugged!\n");
22128c2ecf20Sopenharmony_ci		return;
22138c2ecf20Sopenharmony_ci	}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
22168c2ecf20Sopenharmony_ci		ath_dbg(common, ANY, "Device not present\n");
22178c2ecf20Sopenharmony_ci		return;
22188c2ecf20Sopenharmony_ci	}
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->chan_lock);
22218c2ecf20Sopenharmony_ci	if (timeout_override)
22228c2ecf20Sopenharmony_ci		timeout = HZ / 5;
22238c2ecf20Sopenharmony_ci	else
22248c2ecf20Sopenharmony_ci		timeout = sc->cur_chan->flush_timeout;
22258c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->chan_lock);
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX,
22288c2ecf20Sopenharmony_ci		"Flush timeout: %d\n", jiffies_to_msecs(timeout));
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc, sw_pending),
22318c2ecf20Sopenharmony_ci			       timeout) > 0)
22328c2ecf20Sopenharmony_ci		drop = false;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	if (drop) {
22358c2ecf20Sopenharmony_ci		ath9k_ps_wakeup(sc);
22368c2ecf20Sopenharmony_ci		spin_lock_bh(&sc->sc_pcu_lock);
22378c2ecf20Sopenharmony_ci		drain_txq = ath_drain_all_txq(sc);
22388c2ecf20Sopenharmony_ci		spin_unlock_bh(&sc->sc_pcu_lock);
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci		if (!drain_txq)
22418c2ecf20Sopenharmony_ci			ath_reset(sc, NULL);
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci		ath9k_ps_restore(sc);
22448c2ecf20Sopenharmony_ci	}
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	ieee80211_queue_delayed_work(hw, &sc->hw_check_work,
22478c2ecf20Sopenharmony_ci				     msecs_to_jiffies(ATH_HW_CHECK_POLL_INT));
22488c2ecf20Sopenharmony_ci}
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_cistatic bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
22518c2ecf20Sopenharmony_ci{
22528c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	return ath9k_has_tx_pending(sc, true);
22558c2ecf20Sopenharmony_ci}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_cistatic int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
22588c2ecf20Sopenharmony_ci{
22598c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
22608c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
22618c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif;
22628c2ecf20Sopenharmony_ci	struct ath_vif *avp;
22638c2ecf20Sopenharmony_ci	struct ath_buf *bf;
22648c2ecf20Sopenharmony_ci	struct ath_tx_status ts;
22658c2ecf20Sopenharmony_ci	bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
22668c2ecf20Sopenharmony_ci	int status;
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	vif = sc->beacon.bslot[0];
22698c2ecf20Sopenharmony_ci	if (!vif)
22708c2ecf20Sopenharmony_ci		return 0;
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci	if (!vif->bss_conf.enable_beacon)
22738c2ecf20Sopenharmony_ci		return 0;
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_ci	avp = (void *)vif->drv_priv;
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	if (!sc->beacon.tx_processed && !edma) {
22788c2ecf20Sopenharmony_ci		tasklet_disable(&sc->bcon_tasklet);
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci		bf = avp->av_bcbuf;
22818c2ecf20Sopenharmony_ci		if (!bf || !bf->bf_mpdu)
22828c2ecf20Sopenharmony_ci			goto skip;
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci		status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts);
22858c2ecf20Sopenharmony_ci		if (status == -EINPROGRESS)
22868c2ecf20Sopenharmony_ci			goto skip;
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci		sc->beacon.tx_processed = true;
22898c2ecf20Sopenharmony_ci		sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ciskip:
22928c2ecf20Sopenharmony_ci		tasklet_enable(&sc->bcon_tasklet);
22938c2ecf20Sopenharmony_ci	}
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	return sc->beacon.tx_last;
22968c2ecf20Sopenharmony_ci}
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_cistatic int ath9k_get_stats(struct ieee80211_hw *hw,
22998c2ecf20Sopenharmony_ci			   struct ieee80211_low_level_stats *stats)
23008c2ecf20Sopenharmony_ci{
23018c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
23028c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
23038c2ecf20Sopenharmony_ci	struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats;
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci	stats->dot11ACKFailureCount = mib_stats->ackrcv_bad;
23068c2ecf20Sopenharmony_ci	stats->dot11RTSFailureCount = mib_stats->rts_bad;
23078c2ecf20Sopenharmony_ci	stats->dot11FCSErrorCount = mib_stats->fcs_bad;
23088c2ecf20Sopenharmony_ci	stats->dot11RTSSuccessCount = mib_stats->rts_good;
23098c2ecf20Sopenharmony_ci	return 0;
23108c2ecf20Sopenharmony_ci}
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_cistatic u32 fill_chainmask(u32 cap, u32 new)
23138c2ecf20Sopenharmony_ci{
23148c2ecf20Sopenharmony_ci	u32 filled = 0;
23158c2ecf20Sopenharmony_ci	int i;
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci	for (i = 0; cap && new; i++, cap >>= 1) {
23188c2ecf20Sopenharmony_ci		if (!(cap & BIT(0)))
23198c2ecf20Sopenharmony_ci			continue;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci		if (new & BIT(0))
23228c2ecf20Sopenharmony_ci			filled |= BIT(i);
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci		new >>= 1;
23258c2ecf20Sopenharmony_ci	}
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci	return filled;
23288c2ecf20Sopenharmony_ci}
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_cistatic bool validate_antenna_mask(struct ath_hw *ah, u32 val)
23318c2ecf20Sopenharmony_ci{
23328c2ecf20Sopenharmony_ci	if (AR_SREV_9300_20_OR_LATER(ah))
23338c2ecf20Sopenharmony_ci		return true;
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	switch (val & 0x7) {
23368c2ecf20Sopenharmony_ci	case 0x1:
23378c2ecf20Sopenharmony_ci	case 0x3:
23388c2ecf20Sopenharmony_ci	case 0x7:
23398c2ecf20Sopenharmony_ci		return true;
23408c2ecf20Sopenharmony_ci	case 0x2:
23418c2ecf20Sopenharmony_ci		return (ah->caps.rx_chainmask == 1);
23428c2ecf20Sopenharmony_ci	default:
23438c2ecf20Sopenharmony_ci		return false;
23448c2ecf20Sopenharmony_ci	}
23458c2ecf20Sopenharmony_ci}
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_cistatic int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
23488c2ecf20Sopenharmony_ci{
23498c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
23508c2ecf20Sopenharmony_ci	struct ath_hw *ah = sc->sc_ah;
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci	if (ah->caps.rx_chainmask != 1)
23538c2ecf20Sopenharmony_ci		rx_ant |= tx_ant;
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	if (!validate_antenna_mask(ah, rx_ant) || !tx_ant)
23568c2ecf20Sopenharmony_ci		return -EINVAL;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	sc->ant_rx = rx_ant;
23598c2ecf20Sopenharmony_ci	sc->ant_tx = tx_ant;
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	if (ah->caps.rx_chainmask == 1)
23628c2ecf20Sopenharmony_ci		return 0;
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci	/* AR9100 runs into calibration issues if not all rx chains are enabled */
23658c2ecf20Sopenharmony_ci	if (AR_SREV_9100(ah))
23668c2ecf20Sopenharmony_ci		ah->rxchainmask = 0x7;
23678c2ecf20Sopenharmony_ci	else
23688c2ecf20Sopenharmony_ci		ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci	ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
23718c2ecf20Sopenharmony_ci	ath9k_cmn_reload_chainmask(ah);
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	return 0;
23748c2ecf20Sopenharmony_ci}
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_cistatic int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
23778c2ecf20Sopenharmony_ci{
23788c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci	*tx_ant = sc->ant_tx;
23818c2ecf20Sopenharmony_ci	*rx_ant = sc->ant_rx;
23828c2ecf20Sopenharmony_ci	return 0;
23838c2ecf20Sopenharmony_ci}
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_cistatic void ath9k_sw_scan_start(struct ieee80211_hw *hw,
23868c2ecf20Sopenharmony_ci				struct ieee80211_vif *vif,
23878c2ecf20Sopenharmony_ci				const u8 *mac_addr)
23888c2ecf20Sopenharmony_ci{
23898c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
23908c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
23918c2ecf20Sopenharmony_ci	set_bit(ATH_OP_SCANNING, &common->op_flags);
23928c2ecf20Sopenharmony_ci}
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_cistatic void ath9k_sw_scan_complete(struct ieee80211_hw *hw,
23958c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif)
23968c2ecf20Sopenharmony_ci{
23978c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
23988c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
23998c2ecf20Sopenharmony_ci	clear_bit(ATH_OP_SCANNING, &common->op_flags);
24008c2ecf20Sopenharmony_ci}
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_cistatic void ath9k_cancel_pending_offchannel(struct ath_softc *sc)
24058c2ecf20Sopenharmony_ci{
24068c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	if (sc->offchannel.roc_vif) {
24098c2ecf20Sopenharmony_ci		ath_dbg(common, CHAN_CTX,
24108c2ecf20Sopenharmony_ci			"%s: Aborting RoC\n", __func__);
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci		del_timer_sync(&sc->offchannel.timer);
24138c2ecf20Sopenharmony_ci		if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START)
24148c2ecf20Sopenharmony_ci			ath_roc_complete(sc, ATH_ROC_COMPLETE_ABORT);
24158c2ecf20Sopenharmony_ci	}
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
24188c2ecf20Sopenharmony_ci		ath_dbg(common, CHAN_CTX,
24198c2ecf20Sopenharmony_ci			"%s: Aborting HW scan\n", __func__);
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci		del_timer_sync(&sc->offchannel.timer);
24228c2ecf20Sopenharmony_ci		ath_scan_complete(sc, true);
24238c2ecf20Sopenharmony_ci	}
24248c2ecf20Sopenharmony_ci}
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_cistatic int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
24278c2ecf20Sopenharmony_ci			 struct ieee80211_scan_request *hw_req)
24288c2ecf20Sopenharmony_ci{
24298c2ecf20Sopenharmony_ci	struct cfg80211_scan_request *req = &hw_req->req;
24308c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
24318c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
24328c2ecf20Sopenharmony_ci	int ret = 0;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	if (WARN_ON(sc->offchannel.scan_req)) {
24378c2ecf20Sopenharmony_ci		ret = -EBUSY;
24388c2ecf20Sopenharmony_ci		goto out;
24398c2ecf20Sopenharmony_ci	}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
24428c2ecf20Sopenharmony_ci	set_bit(ATH_OP_SCANNING, &common->op_flags);
24438c2ecf20Sopenharmony_ci	sc->offchannel.scan_vif = vif;
24448c2ecf20Sopenharmony_ci	sc->offchannel.scan_req = req;
24458c2ecf20Sopenharmony_ci	sc->offchannel.scan_idx = 0;
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n",
24488c2ecf20Sopenharmony_ci		vif->addr);
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci	if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
24518c2ecf20Sopenharmony_ci		ath_dbg(common, CHAN_CTX, "Starting HW scan\n");
24528c2ecf20Sopenharmony_ci		ath_offchannel_next(sc);
24538c2ecf20Sopenharmony_ci	}
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ciout:
24568c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	return ret;
24598c2ecf20Sopenharmony_ci}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_cistatic void ath9k_cancel_hw_scan(struct ieee80211_hw *hw,
24628c2ecf20Sopenharmony_ci				 struct ieee80211_vif *vif)
24638c2ecf20Sopenharmony_ci{
24648c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
24658c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
24708c2ecf20Sopenharmony_ci	del_timer_sync(&sc->offchannel.timer);
24718c2ecf20Sopenharmony_ci	ath_scan_complete(sc, true);
24728c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
24738c2ecf20Sopenharmony_ci}
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_cistatic int ath9k_remain_on_channel(struct ieee80211_hw *hw,
24768c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif,
24778c2ecf20Sopenharmony_ci				   struct ieee80211_channel *chan, int duration,
24788c2ecf20Sopenharmony_ci				   enum ieee80211_roc_type type)
24798c2ecf20Sopenharmony_ci{
24808c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
24818c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
24828c2ecf20Sopenharmony_ci	int ret = 0;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	if (WARN_ON(sc->offchannel.roc_vif)) {
24878c2ecf20Sopenharmony_ci		ret = -EBUSY;
24888c2ecf20Sopenharmony_ci		goto out;
24898c2ecf20Sopenharmony_ci	}
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	ath9k_ps_wakeup(sc);
24928c2ecf20Sopenharmony_ci	sc->offchannel.roc_vif = vif;
24938c2ecf20Sopenharmony_ci	sc->offchannel.roc_chan = chan;
24948c2ecf20Sopenharmony_ci	sc->offchannel.roc_duration = duration;
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX,
24978c2ecf20Sopenharmony_ci		"RoC request on vif: %pM, type: %d duration: %d\n",
24988c2ecf20Sopenharmony_ci		vif->addr, type, duration);
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
25018c2ecf20Sopenharmony_ci		ath_dbg(common, CHAN_CTX, "Starting RoC period\n");
25028c2ecf20Sopenharmony_ci		ath_offchannel_next(sc);
25038c2ecf20Sopenharmony_ci	}
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ciout:
25068c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	return ret;
25098c2ecf20Sopenharmony_ci}
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_cistatic int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw,
25128c2ecf20Sopenharmony_ci					  struct ieee80211_vif *vif)
25138c2ecf20Sopenharmony_ci{
25148c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
25158c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX, "Cancel RoC\n");
25208c2ecf20Sopenharmony_ci	del_timer_sync(&sc->offchannel.timer);
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	if (sc->offchannel.roc_vif) {
25238c2ecf20Sopenharmony_ci		if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START)
25248c2ecf20Sopenharmony_ci			ath_roc_complete(sc, ATH_ROC_COMPLETE_CANCEL);
25258c2ecf20Sopenharmony_ci	}
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	return 0;
25308c2ecf20Sopenharmony_ci}
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_cistatic int ath9k_add_chanctx(struct ieee80211_hw *hw,
25338c2ecf20Sopenharmony_ci			     struct ieee80211_chanctx_conf *conf)
25348c2ecf20Sopenharmony_ci{
25358c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
25368c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
25378c2ecf20Sopenharmony_ci	struct ath_chanctx *ctx, **ptr;
25388c2ecf20Sopenharmony_ci	int pos;
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	ath_for_each_chanctx(sc, ctx) {
25438c2ecf20Sopenharmony_ci		if (ctx->assigned)
25448c2ecf20Sopenharmony_ci			continue;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci		ptr = (void *) conf->drv_priv;
25478c2ecf20Sopenharmony_ci		*ptr = ctx;
25488c2ecf20Sopenharmony_ci		ctx->assigned = true;
25498c2ecf20Sopenharmony_ci		pos = ctx - &sc->chanctx[0];
25508c2ecf20Sopenharmony_ci		ctx->hw_queue_base = pos * IEEE80211_NUM_ACS;
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci		ath_dbg(common, CHAN_CTX,
25538c2ecf20Sopenharmony_ci			"Add channel context: %d MHz\n",
25548c2ecf20Sopenharmony_ci			conf->def.chan->center_freq);
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci		ath_chanctx_set_channel(sc, ctx, &conf->def);
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci		mutex_unlock(&sc->mutex);
25598c2ecf20Sopenharmony_ci		return 0;
25608c2ecf20Sopenharmony_ci	}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
25638c2ecf20Sopenharmony_ci	return -ENOSPC;
25648c2ecf20Sopenharmony_ci}
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_cistatic void ath9k_remove_chanctx(struct ieee80211_hw *hw,
25688c2ecf20Sopenharmony_ci				 struct ieee80211_chanctx_conf *conf)
25698c2ecf20Sopenharmony_ci{
25708c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
25718c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
25728c2ecf20Sopenharmony_ci	struct ath_chanctx *ctx = ath_chanctx_get(conf);
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX,
25778c2ecf20Sopenharmony_ci		"Remove channel context: %d MHz\n",
25788c2ecf20Sopenharmony_ci		conf->def.chan->center_freq);
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	ctx->assigned = false;
25818c2ecf20Sopenharmony_ci	ctx->hw_queue_base = 0;
25828c2ecf20Sopenharmony_ci	ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN);
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
25858c2ecf20Sopenharmony_ci}
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_cistatic void ath9k_change_chanctx(struct ieee80211_hw *hw,
25888c2ecf20Sopenharmony_ci				 struct ieee80211_chanctx_conf *conf,
25898c2ecf20Sopenharmony_ci				 u32 changed)
25908c2ecf20Sopenharmony_ci{
25918c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
25928c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
25938c2ecf20Sopenharmony_ci	struct ath_chanctx *ctx = ath_chanctx_get(conf);
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
25968c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX,
25978c2ecf20Sopenharmony_ci		"Change channel context: %d MHz\n",
25988c2ecf20Sopenharmony_ci		conf->def.chan->center_freq);
25998c2ecf20Sopenharmony_ci	ath_chanctx_set_channel(sc, ctx, &conf->def);
26008c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
26018c2ecf20Sopenharmony_ci}
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_cistatic int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw,
26048c2ecf20Sopenharmony_ci				    struct ieee80211_vif *vif,
26058c2ecf20Sopenharmony_ci				    struct ieee80211_chanctx_conf *conf)
26068c2ecf20Sopenharmony_ci{
26078c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
26088c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
26098c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
26108c2ecf20Sopenharmony_ci	struct ath_chanctx *ctx = ath_chanctx_get(conf);
26118c2ecf20Sopenharmony_ci	int i;
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci	ath9k_cancel_pending_offchannel(sc);
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX,
26188c2ecf20Sopenharmony_ci		"Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n",
26198c2ecf20Sopenharmony_ci		vif->addr, vif->type, vif->p2p,
26208c2ecf20Sopenharmony_ci		conf->def.chan->center_freq);
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	avp->chanctx = ctx;
26238c2ecf20Sopenharmony_ci	ctx->nvifs_assigned++;
26248c2ecf20Sopenharmony_ci	list_add_tail(&avp->list, &ctx->vifs);
26258c2ecf20Sopenharmony_ci	ath9k_calculate_summary_state(sc, ctx);
26268c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE80211_NUM_ACS; i++)
26278c2ecf20Sopenharmony_ci		vif->hw_queue[i] = ctx->hw_queue_base + i;
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	return 0;
26328c2ecf20Sopenharmony_ci}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_cistatic void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw,
26358c2ecf20Sopenharmony_ci				       struct ieee80211_vif *vif,
26368c2ecf20Sopenharmony_ci				       struct ieee80211_chanctx_conf *conf)
26378c2ecf20Sopenharmony_ci{
26388c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
26398c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
26408c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
26418c2ecf20Sopenharmony_ci	struct ath_chanctx *ctx = ath_chanctx_get(conf);
26428c2ecf20Sopenharmony_ci	int ac;
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	ath9k_cancel_pending_offchannel(sc);
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX,
26498c2ecf20Sopenharmony_ci		"Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n",
26508c2ecf20Sopenharmony_ci		vif->addr, vif->type, vif->p2p,
26518c2ecf20Sopenharmony_ci		conf->def.chan->center_freq);
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	avp->chanctx = NULL;
26548c2ecf20Sopenharmony_ci	ctx->nvifs_assigned--;
26558c2ecf20Sopenharmony_ci	list_del(&avp->list);
26568c2ecf20Sopenharmony_ci	ath9k_calculate_summary_state(sc, ctx);
26578c2ecf20Sopenharmony_ci	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
26588c2ecf20Sopenharmony_ci		vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE;
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
26618c2ecf20Sopenharmony_ci}
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_cistatic void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
26648c2ecf20Sopenharmony_ci				 struct ieee80211_vif *vif,
26658c2ecf20Sopenharmony_ci				 u16 duration)
26668c2ecf20Sopenharmony_ci{
26678c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
26688c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
26698c2ecf20Sopenharmony_ci	struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
26708c2ecf20Sopenharmony_ci	struct ath_beacon_config *cur_conf;
26718c2ecf20Sopenharmony_ci	struct ath_chanctx *go_ctx;
26728c2ecf20Sopenharmony_ci	unsigned long timeout;
26738c2ecf20Sopenharmony_ci	bool changed = false;
26748c2ecf20Sopenharmony_ci	u32 beacon_int;
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
26778c2ecf20Sopenharmony_ci		return;
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	if (!avp->chanctx)
26808c2ecf20Sopenharmony_ci		return;
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->chan_lock);
26858c2ecf20Sopenharmony_ci	if (sc->next_chan || (sc->cur_chan != avp->chanctx))
26868c2ecf20Sopenharmony_ci		changed = true;
26878c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->chan_lock);
26888c2ecf20Sopenharmony_ci
26898c2ecf20Sopenharmony_ci	if (!changed)
26908c2ecf20Sopenharmony_ci		goto out;
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	ath9k_cancel_pending_offchannel(sc);
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	go_ctx = ath_is_go_chanctx_present(sc);
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	if (go_ctx) {
26978c2ecf20Sopenharmony_ci		/*
26988c2ecf20Sopenharmony_ci		 * Wait till the GO interface gets a chance
26998c2ecf20Sopenharmony_ci		 * to send out an NoA.
27008c2ecf20Sopenharmony_ci		 */
27018c2ecf20Sopenharmony_ci		spin_lock_bh(&sc->chan_lock);
27028c2ecf20Sopenharmony_ci		sc->sched.mgd_prepare_tx = true;
27038c2ecf20Sopenharmony_ci		cur_conf = &go_ctx->beacon;
27048c2ecf20Sopenharmony_ci		beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
27058c2ecf20Sopenharmony_ci		spin_unlock_bh(&sc->chan_lock);
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci		timeout = usecs_to_jiffies(beacon_int * 2);
27088c2ecf20Sopenharmony_ci		init_completion(&sc->go_beacon);
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci		mutex_unlock(&sc->mutex);
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci		if (wait_for_completion_timeout(&sc->go_beacon,
27138c2ecf20Sopenharmony_ci						timeout) == 0) {
27148c2ecf20Sopenharmony_ci			ath_dbg(common, CHAN_CTX,
27158c2ecf20Sopenharmony_ci				"Failed to send new NoA\n");
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_ci			spin_lock_bh(&sc->chan_lock);
27188c2ecf20Sopenharmony_ci			sc->sched.mgd_prepare_tx = false;
27198c2ecf20Sopenharmony_ci			spin_unlock_bh(&sc->chan_lock);
27208c2ecf20Sopenharmony_ci		}
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci		mutex_lock(&sc->mutex);
27238c2ecf20Sopenharmony_ci	}
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	ath_dbg(common, CHAN_CTX,
27268c2ecf20Sopenharmony_ci		"%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n",
27278c2ecf20Sopenharmony_ci		__func__, vif->addr);
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	spin_lock_bh(&sc->chan_lock);
27308c2ecf20Sopenharmony_ci	sc->next_chan = avp->chanctx;
27318c2ecf20Sopenharmony_ci	sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
27328c2ecf20Sopenharmony_ci	spin_unlock_bh(&sc->chan_lock);
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci	ath_chanctx_set_next(sc, true);
27358c2ecf20Sopenharmony_ciout:
27368c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
27378c2ecf20Sopenharmony_ci}
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_civoid ath9k_fill_chanctx_ops(void)
27408c2ecf20Sopenharmony_ci{
27418c2ecf20Sopenharmony_ci	if (!ath9k_is_chanctx_enabled())
27428c2ecf20Sopenharmony_ci		return;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	ath9k_ops.hw_scan                  = ath9k_hw_scan;
27458c2ecf20Sopenharmony_ci	ath9k_ops.cancel_hw_scan           = ath9k_cancel_hw_scan;
27468c2ecf20Sopenharmony_ci	ath9k_ops.remain_on_channel        = ath9k_remain_on_channel;
27478c2ecf20Sopenharmony_ci	ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel;
27488c2ecf20Sopenharmony_ci	ath9k_ops.add_chanctx              = ath9k_add_chanctx;
27498c2ecf20Sopenharmony_ci	ath9k_ops.remove_chanctx           = ath9k_remove_chanctx;
27508c2ecf20Sopenharmony_ci	ath9k_ops.change_chanctx           = ath9k_change_chanctx;
27518c2ecf20Sopenharmony_ci	ath9k_ops.assign_vif_chanctx       = ath9k_assign_vif_chanctx;
27528c2ecf20Sopenharmony_ci	ath9k_ops.unassign_vif_chanctx     = ath9k_unassign_vif_chanctx;
27538c2ecf20Sopenharmony_ci	ath9k_ops.mgd_prepare_tx           = ath9k_mgd_prepare_tx;
27548c2ecf20Sopenharmony_ci}
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci#endif
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_cistatic int ath9k_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
27598c2ecf20Sopenharmony_ci			     int *dbm)
27608c2ecf20Sopenharmony_ci{
27618c2ecf20Sopenharmony_ci	struct ath_softc *sc = hw->priv;
27628c2ecf20Sopenharmony_ci	struct ath_vif *avp = (void *)vif->drv_priv;
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_ci	mutex_lock(&sc->mutex);
27658c2ecf20Sopenharmony_ci	if (avp->chanctx)
27668c2ecf20Sopenharmony_ci		*dbm = avp->chanctx->cur_txpower;
27678c2ecf20Sopenharmony_ci	else
27688c2ecf20Sopenharmony_ci		*dbm = sc->cur_chan->cur_txpower;
27698c2ecf20Sopenharmony_ci	mutex_unlock(&sc->mutex);
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	*dbm /= 2;
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	return 0;
27748c2ecf20Sopenharmony_ci}
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_cistruct ieee80211_ops ath9k_ops = {
27778c2ecf20Sopenharmony_ci	.tx 		    = ath9k_tx,
27788c2ecf20Sopenharmony_ci	.start 		    = ath9k_start,
27798c2ecf20Sopenharmony_ci	.stop 		    = ath9k_stop,
27808c2ecf20Sopenharmony_ci	.add_interface 	    = ath9k_add_interface,
27818c2ecf20Sopenharmony_ci	.change_interface   = ath9k_change_interface,
27828c2ecf20Sopenharmony_ci	.remove_interface   = ath9k_remove_interface,
27838c2ecf20Sopenharmony_ci	.config 	    = ath9k_config,
27848c2ecf20Sopenharmony_ci	.configure_filter   = ath9k_configure_filter,
27858c2ecf20Sopenharmony_ci	.sta_state          = ath9k_sta_state,
27868c2ecf20Sopenharmony_ci	.sta_notify         = ath9k_sta_notify,
27878c2ecf20Sopenharmony_ci	.conf_tx 	    = ath9k_conf_tx,
27888c2ecf20Sopenharmony_ci	.bss_info_changed   = ath9k_bss_info_changed,
27898c2ecf20Sopenharmony_ci	.set_key            = ath9k_set_key,
27908c2ecf20Sopenharmony_ci	.get_tsf 	    = ath9k_get_tsf,
27918c2ecf20Sopenharmony_ci	.set_tsf 	    = ath9k_set_tsf,
27928c2ecf20Sopenharmony_ci	.reset_tsf 	    = ath9k_reset_tsf,
27938c2ecf20Sopenharmony_ci	.ampdu_action       = ath9k_ampdu_action,
27948c2ecf20Sopenharmony_ci	.get_survey	    = ath9k_get_survey,
27958c2ecf20Sopenharmony_ci	.rfkill_poll        = ath9k_rfkill_poll_state,
27968c2ecf20Sopenharmony_ci	.set_coverage_class = ath9k_set_coverage_class,
27978c2ecf20Sopenharmony_ci	.flush		    = ath9k_flush,
27988c2ecf20Sopenharmony_ci	.tx_frames_pending  = ath9k_tx_frames_pending,
27998c2ecf20Sopenharmony_ci	.tx_last_beacon     = ath9k_tx_last_beacon,
28008c2ecf20Sopenharmony_ci	.release_buffered_frames = ath9k_release_buffered_frames,
28018c2ecf20Sopenharmony_ci	.get_stats	    = ath9k_get_stats,
28028c2ecf20Sopenharmony_ci	.set_antenna	    = ath9k_set_antenna,
28038c2ecf20Sopenharmony_ci	.get_antenna	    = ath9k_get_antenna,
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_WOW
28068c2ecf20Sopenharmony_ci	.suspend	    = ath9k_suspend,
28078c2ecf20Sopenharmony_ci	.resume		    = ath9k_resume,
28088c2ecf20Sopenharmony_ci	.set_wakeup	    = ath9k_set_wakeup,
28098c2ecf20Sopenharmony_ci#endif
28108c2ecf20Sopenharmony_ci
28118c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_DEBUGFS
28128c2ecf20Sopenharmony_ci	.get_et_sset_count  = ath9k_get_et_sset_count,
28138c2ecf20Sopenharmony_ci	.get_et_stats       = ath9k_get_et_stats,
28148c2ecf20Sopenharmony_ci	.get_et_strings     = ath9k_get_et_strings,
28158c2ecf20Sopenharmony_ci#endif
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_STATION_STATISTICS)
28188c2ecf20Sopenharmony_ci	.sta_add_debugfs    = ath9k_sta_add_debugfs,
28198c2ecf20Sopenharmony_ci#endif
28208c2ecf20Sopenharmony_ci	.sw_scan_start	    = ath9k_sw_scan_start,
28218c2ecf20Sopenharmony_ci	.sw_scan_complete   = ath9k_sw_scan_complete,
28228c2ecf20Sopenharmony_ci	.get_txpower        = ath9k_get_txpower,
28238c2ecf20Sopenharmony_ci	.wake_tx_queue      = ath9k_wake_tx_queue,
28248c2ecf20Sopenharmony_ci};
2825