diff options
author | Vivek Natarajan <vivek.natraj@gmail.com> | 2009-01-20 00:47:08 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:01:03 -0500 |
commit | 3cbb5dd73697b3f1c677daffe29f00ace22b71e9 (patch) | |
tree | 39fcb371ef37b9a2a53a4cdf72a8e98c64d9e98e /drivers/net/wireless/ath9k/main.c | |
parent | c5d0569882b9c264be31dcb0758961bfc479deea (diff) |
ath9k: Enable dynamic power save in ath9k.
This patch implements dynamic power save feature for ath9k.
Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 8ad927a8870c..b494a0d7e8b5 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -237,6 +237,8 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) | |||
237 | if (sc->sc_flags & SC_OP_INVALID) | 237 | if (sc->sc_flags & SC_OP_INVALID) |
238 | return -EIO; | 238 | return -EIO; |
239 | 239 | ||
240 | ath9k_ps_wakeup(sc); | ||
241 | |||
240 | /* | 242 | /* |
241 | * This is only performed if the channel settings have | 243 | * This is only performed if the channel settings have |
242 | * actually changed. | 244 | * actually changed. |
@@ -287,6 +289,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) | |||
287 | ath_cache_conf_rate(sc, &hw->conf); | 289 | ath_cache_conf_rate(sc, &hw->conf); |
288 | ath_update_txpow(sc); | 290 | ath_update_txpow(sc); |
289 | ath9k_hw_set_interrupts(ah, sc->sc_imask); | 291 | ath9k_hw_set_interrupts(ah, sc->sc_imask); |
292 | ath9k_ps_restore(sc); | ||
290 | return 0; | 293 | return 0; |
291 | } | 294 | } |
292 | 295 | ||
@@ -559,8 +562,10 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
559 | ATH9K_HW_CAP_AUTOSLEEP)) { | 562 | ATH9K_HW_CAP_AUTOSLEEP)) { |
560 | /* Clear RxAbort bit so that we can | 563 | /* Clear RxAbort bit so that we can |
561 | * receive frames */ | 564 | * receive frames */ |
565 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); | ||
562 | ath9k_hw_setrxabort(ah, 0); | 566 | ath9k_hw_setrxabort(ah, 0); |
563 | sched = true; | 567 | sched = true; |
568 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; | ||
564 | } | 569 | } |
565 | } | 570 | } |
566 | } | 571 | } |
@@ -1044,6 +1049,7 @@ static void ath_radio_enable(struct ath_softc *sc) | |||
1044 | struct ieee80211_channel *channel = sc->hw->conf.channel; | 1049 | struct ieee80211_channel *channel = sc->hw->conf.channel; |
1045 | int r; | 1050 | int r; |
1046 | 1051 | ||
1052 | ath9k_ps_wakeup(sc); | ||
1047 | spin_lock_bh(&sc->sc_resetlock); | 1053 | spin_lock_bh(&sc->sc_resetlock); |
1048 | 1054 | ||
1049 | r = ath9k_hw_reset(ah, ah->ah_curchan, false); | 1055 | r = ath9k_hw_reset(ah, ah->ah_curchan, false); |
@@ -1075,6 +1081,7 @@ static void ath_radio_enable(struct ath_softc *sc) | |||
1075 | ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); | 1081 | ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0); |
1076 | 1082 | ||
1077 | ieee80211_wake_queues(sc->hw); | 1083 | ieee80211_wake_queues(sc->hw); |
1084 | ath9k_ps_restore(sc); | ||
1078 | } | 1085 | } |
1079 | 1086 | ||
1080 | static void ath_radio_disable(struct ath_softc *sc) | 1087 | static void ath_radio_disable(struct ath_softc *sc) |
@@ -1083,6 +1090,7 @@ static void ath_radio_disable(struct ath_softc *sc) | |||
1083 | struct ieee80211_channel *channel = sc->hw->conf.channel; | 1090 | struct ieee80211_channel *channel = sc->hw->conf.channel; |
1084 | int r; | 1091 | int r; |
1085 | 1092 | ||
1093 | ath9k_ps_wakeup(sc); | ||
1086 | ieee80211_stop_queues(sc->hw); | 1094 | ieee80211_stop_queues(sc->hw); |
1087 | 1095 | ||
1088 | /* Disable LED */ | 1096 | /* Disable LED */ |
@@ -1108,6 +1116,7 @@ static void ath_radio_disable(struct ath_softc *sc) | |||
1108 | 1116 | ||
1109 | ath9k_hw_phy_disable(ah); | 1117 | ath9k_hw_phy_disable(ah); |
1110 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); | 1118 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); |
1119 | ath9k_ps_restore(sc); | ||
1111 | } | 1120 | } |
1112 | 1121 | ||
1113 | static bool ath_is_rfkill_set(struct ath_softc *sc) | 1122 | static bool ath_is_rfkill_set(struct ath_softc *sc) |
@@ -1259,6 +1268,8 @@ void ath_detach(struct ath_softc *sc) | |||
1259 | struct ieee80211_hw *hw = sc->hw; | 1268 | struct ieee80211_hw *hw = sc->hw; |
1260 | int i = 0; | 1269 | int i = 0; |
1261 | 1270 | ||
1271 | ath9k_ps_wakeup(sc); | ||
1272 | |||
1262 | DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); | 1273 | DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); |
1263 | 1274 | ||
1264 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) | 1275 | #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) |
@@ -1283,6 +1294,7 @@ void ath_detach(struct ath_softc *sc) | |||
1283 | 1294 | ||
1284 | ath9k_hw_detach(sc->sc_ah); | 1295 | ath9k_hw_detach(sc->sc_ah); |
1285 | ath9k_exit_debug(sc); | 1296 | ath9k_exit_debug(sc); |
1297 | ath9k_ps_restore(sc); | ||
1286 | } | 1298 | } |
1287 | 1299 | ||
1288 | static int ath_init(u16 devid, struct ath_softc *sc) | 1300 | static int ath_init(u16 devid, struct ath_softc *sc) |
@@ -1526,7 +1538,9 @@ int ath_attach(u16 devid, struct ath_softc *sc) | |||
1526 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | 1538 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
1527 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | 1539 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | |
1528 | IEEE80211_HW_SIGNAL_DBM | | 1540 | IEEE80211_HW_SIGNAL_DBM | |
1529 | IEEE80211_HW_AMPDU_AGGREGATION; | 1541 | IEEE80211_HW_AMPDU_AGGREGATION | |
1542 | IEEE80211_HW_SUPPORTS_PS | | ||
1543 | IEEE80211_HW_PS_NULLFUNC_STACK; | ||
1530 | 1544 | ||
1531 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah)) | 1545 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah)) |
1532 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 1546 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; |
@@ -2090,6 +2104,27 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
2090 | struct ieee80211_conf *conf = &hw->conf; | 2104 | struct ieee80211_conf *conf = &hw->conf; |
2091 | 2105 | ||
2092 | mutex_lock(&sc->mutex); | 2106 | mutex_lock(&sc->mutex); |
2107 | if (changed & IEEE80211_CONF_CHANGE_PS) { | ||
2108 | if (conf->flags & IEEE80211_CONF_PS) { | ||
2109 | if ((sc->sc_imask & ATH9K_INT_TIM_TIMER) == 0) { | ||
2110 | sc->sc_imask |= ATH9K_INT_TIM_TIMER; | ||
2111 | ath9k_hw_set_interrupts(sc->sc_ah, | ||
2112 | sc->sc_imask); | ||
2113 | } | ||
2114 | ath9k_hw_setrxabort(sc->sc_ah, 1); | ||
2115 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); | ||
2116 | } else { | ||
2117 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); | ||
2118 | ath9k_hw_setrxabort(sc->sc_ah, 0); | ||
2119 | sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; | ||
2120 | if (sc->sc_imask & ATH9K_INT_TIM_TIMER) { | ||
2121 | sc->sc_imask &= ~ATH9K_INT_TIM_TIMER; | ||
2122 | ath9k_hw_set_interrupts(sc->sc_ah, | ||
2123 | sc->sc_imask); | ||
2124 | } | ||
2125 | } | ||
2126 | } | ||
2127 | |||
2093 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 2128 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
2094 | struct ieee80211_channel *curchan = hw->conf.channel; | 2129 | struct ieee80211_channel *curchan = hw->conf.channel; |
2095 | int pos; | 2130 | int pos; |
@@ -2310,6 +2345,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
2310 | struct ath_softc *sc = hw->priv; | 2345 | struct ath_softc *sc = hw->priv; |
2311 | int ret = 0; | 2346 | int ret = 0; |
2312 | 2347 | ||
2348 | ath9k_ps_wakeup(sc); | ||
2313 | DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); | 2349 | DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); |
2314 | 2350 | ||
2315 | switch (cmd) { | 2351 | switch (cmd) { |
@@ -2333,6 +2369,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
2333 | ret = -EINVAL; | 2369 | ret = -EINVAL; |
2334 | } | 2370 | } |
2335 | 2371 | ||
2372 | ath9k_ps_restore(sc); | ||
2336 | return ret; | 2373 | return ret; |
2337 | } | 2374 | } |
2338 | 2375 | ||