diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 43d2be9867fc..0c349cece951 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1538,14 +1538,19 @@ bad_no_ah: void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { + struct ath_hw *ah = sc->sc_ah; + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_PS_NULLFUNC_STACK | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SPECTRUM_MGMT; + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) + hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; + if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) hw->flags |= IEEE80211_HW_MFP_CAPABLE; @@ -1555,7 +1560,10 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->wiphy->ps_default = false; + if (AR_SREV_5416(ah)) + hw->wiphy->ps_default = false; + else + hw->wiphy->ps_default = true; hw->queues = 4; hw->max_rates = 4; @@ -2147,6 +2155,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) return; /* another wiphy still in use */ } + /* Ensure HW is awake when we try to shut it down. */ + ath9k_ps_wakeup(sc); + if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { ath9k_hw_btcoex_disable(sc->sc_ah); if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) @@ -2167,6 +2178,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); ath9k_hw_configpcipowersave(sc->sc_ah, 1, 1); + ath9k_ps_restore(sc); + + /* Finally, put the chip in FULL SLEEP mode */ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); sc->sc_flags |= SC_OP_INVALID; @@ -2277,10 +2291,12 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { + ath9k_ps_wakeup(sc); ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); - ath_beacon_return(sc, avp); + ath9k_ps_restore(sc); } + ath_beacon_return(sc, avp); sc->sc_flags &= ~SC_OP_BEACONS; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { @@ -2297,6 +2313,19 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&sc->mutex); } +void ath9k_enable_ps(struct ath_softc *sc) +{ + sc->ps_enabled = true; + if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { + sc->imask |= ATH9K_INT_TIM_TIMER; + ath9k_hw_set_interrupts(sc->sc_ah, + sc->imask); + } + } + ath9k_hw_setrxabort(sc->sc_ah, 1); +} + static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_wiphy *aphy = hw->priv; @@ -2327,18 +2356,15 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_PS) { if (conf->flags & IEEE80211_CONF_PS) { - if (!(ah->caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { - sc->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(sc->sc_ah, - sc->imask); - } - ath9k_hw_setrxabort(sc->sc_ah, 1); + sc->sc_flags |= SC_OP_PS_ENABLED; + if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) { + sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; + ath9k_enable_ps(sc); } - sc->ps_enabled = true; } else { sc->ps_enabled = false; + sc->sc_flags &= ~(SC_OP_PS_ENABLED | + SC_OP_NULLFUNC_COMPLETED); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { @@ -2717,15 +2743,21 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: + ath9k_ps_wakeup(sc); ath_tx_aggr_start(sc, sta, tid, ssn); ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_STOP: + ath9k_ps_wakeup(sc); ath_tx_aggr_stop(sc, sta, tid); ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); + ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + ath9k_ps_wakeup(sc); ath_tx_aggr_resume(sc, sta, tid); + ath9k_ps_restore(sc); break; default: DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); |