aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-11-16 07:08:41 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-12-07 15:19:34 -0500
commitc0c1174144dd619456be5930d733028a055ef425 (patch)
tree21935e2a32845647269a5c7848d22286c01e024b
parentc8e8868e3bf2ee0b6e606ce43af023b5f6edc954 (diff)
ath9k: rework power state handling
Turning off the radio when mac80211 tells the driver that it's idle is not a good idea, as idle interfaces might still occasionally scan or send packets. The only time the radio can be safely turned off is when drv_stop has been called. In the mean time, use sc->ps_idle only to indicate network sleep vs full sleep. Move the LED GPIO changes out of the PCI suspend/resume path, the start/stop functions already take care of that. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c156
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c21
2 files changed, 47 insertions, 130 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 3733828e72bc..8b0feecf3fae 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -887,82 +887,6 @@ chip_reset:
887#undef SCHED_INTR 887#undef SCHED_INTR
888} 888}
889 889
890static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
891{
892 struct ath_hw *ah = sc->sc_ah;
893 struct ath_common *common = ath9k_hw_common(ah);
894 struct ieee80211_channel *channel = hw->conf.channel;
895 int r;
896
897 ath9k_ps_wakeup(sc);
898 spin_lock_bh(&sc->sc_pcu_lock);
899 atomic_set(&ah->intr_ref_cnt, -1);
900
901 ath9k_hw_configpcipowersave(ah, false);
902
903 if (!ah->curchan)
904 ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah);
905
906 r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
907 if (r) {
908 ath_err(common,
909 "Unable to reset channel (%u MHz), reset status %d\n",
910 channel->center_freq, r);
911 }
912
913 ath_complete_reset(sc, true);
914
915 /* Enable LED */
916 ath9k_hw_cfg_output(ah, ah->led_pin,
917 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
918 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
919
920 spin_unlock_bh(&sc->sc_pcu_lock);
921
922 ath9k_ps_restore(sc);
923}
924
925void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
926{
927 struct ath_hw *ah = sc->sc_ah;
928 struct ieee80211_channel *channel = hw->conf.channel;
929 int r;
930
931 ath9k_ps_wakeup(sc);
932
933 ath_cancel_work(sc);
934
935 spin_lock_bh(&sc->sc_pcu_lock);
936
937 /*
938 * Keep the LED on when the radio is disabled
939 * during idle unassociated state.
940 */
941 if (!sc->ps_idle) {
942 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
943 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
944 }
945
946 ath_prepare_reset(sc, false, true);
947
948 if (!ah->curchan)
949 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
950
951 r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
952 if (r) {
953 ath_err(ath9k_hw_common(sc->sc_ah),
954 "Unable to reset channel (%u MHz), reset status %d\n",
955 channel->center_freq, r);
956 }
957
958 ath9k_hw_phy_disable(ah);
959
960 ath9k_hw_configpcipowersave(ah, true);
961
962 spin_unlock_bh(&sc->sc_pcu_lock);
963 ath9k_ps_restore(sc);
964}
965
966static int ath_reset(struct ath_softc *sc, bool retry_tx) 890static int ath_reset(struct ath_softc *sc, bool retry_tx)
967{ 891{
968 int r; 892 int r;
@@ -1098,6 +1022,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
1098 * and then setup of the interrupt mask. 1022 * and then setup of the interrupt mask.
1099 */ 1023 */
1100 spin_lock_bh(&sc->sc_pcu_lock); 1024 spin_lock_bh(&sc->sc_pcu_lock);
1025
1026 atomic_set(&ah->intr_ref_cnt, -1);
1027
1101 r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); 1028 r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
1102 if (r) { 1029 if (r) {
1103 ath_err(common, 1030 ath_err(common,
@@ -1139,6 +1066,18 @@ static int ath9k_start(struct ieee80211_hw *hw)
1139 goto mutex_unlock; 1066 goto mutex_unlock;
1140 } 1067 }
1141 1068
1069 if (ah->led_pin >= 0) {
1070 ath9k_hw_cfg_output(ah, ah->led_pin,
1071 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
1072 ath9k_hw_set_gpio(ah, ah->led_pin, 0);
1073 }
1074
1075 /*
1076 * Reset key cache to sane defaults (all entries cleared) instead of
1077 * semi-random values after suspend/resume.
1078 */
1079 ath9k_cmn_init_crypto(sc->sc_ah);
1080
1142 spin_unlock_bh(&sc->sc_pcu_lock); 1081 spin_unlock_bh(&sc->sc_pcu_lock);
1143 1082
1144 if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && 1083 if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
@@ -1237,6 +1176,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
1237 struct ath_softc *sc = hw->priv; 1176 struct ath_softc *sc = hw->priv;
1238 struct ath_hw *ah = sc->sc_ah; 1177 struct ath_hw *ah = sc->sc_ah;
1239 struct ath_common *common = ath9k_hw_common(ah); 1178 struct ath_common *common = ath9k_hw_common(ah);
1179 bool prev_idle;
1240 1180
1241 mutex_lock(&sc->mutex); 1181 mutex_lock(&sc->mutex);
1242 1182
@@ -1267,35 +1207,45 @@ static void ath9k_stop(struct ieee80211_hw *hw)
1267 * before setting the invalid flag. */ 1207 * before setting the invalid flag. */
1268 ath9k_hw_disable_interrupts(ah); 1208 ath9k_hw_disable_interrupts(ah);
1269 1209
1270 if (!(sc->sc_flags & SC_OP_INVALID)) { 1210 spin_unlock_bh(&sc->sc_pcu_lock);
1271 ath_drain_all_txq(sc, false); 1211
1272 ath_stoprecv(sc); 1212 /* we can now sync irq and kill any running tasklets, since we already
1273 ath9k_hw_phy_disable(ah); 1213 * disabled interrupts and not holding a spin lock */
1274 } else 1214 synchronize_irq(sc->irq);
1275 sc->rx.rxlink = NULL; 1215 tasklet_kill(&sc->intr_tq);
1216 tasklet_kill(&sc->bcon_tasklet);
1217
1218 prev_idle = sc->ps_idle;
1219 sc->ps_idle = true;
1220
1221 spin_lock_bh(&sc->sc_pcu_lock);
1222
1223 if (ah->led_pin >= 0) {
1224 ath9k_hw_set_gpio(ah, ah->led_pin, 1);
1225 ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
1226 }
1227
1228 ath_prepare_reset(sc, false, true);
1276 1229
1277 if (sc->rx.frag) { 1230 if (sc->rx.frag) {
1278 dev_kfree_skb_any(sc->rx.frag); 1231 dev_kfree_skb_any(sc->rx.frag);
1279 sc->rx.frag = NULL; 1232 sc->rx.frag = NULL;
1280 } 1233 }
1281 1234
1282 /* disable HAL and put h/w to sleep */ 1235 if (!ah->curchan)
1283 ath9k_hw_disable(ah); 1236 ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
1284 1237
1285 spin_unlock_bh(&sc->sc_pcu_lock); 1238 ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
1239 ath9k_hw_phy_disable(ah);
1286 1240
1287 /* we can now sync irq and kill any running tasklets, since we already 1241 ath9k_hw_configpcipowersave(ah, true);
1288 * disabled interrupts and not holding a spin lock */
1289 synchronize_irq(sc->irq);
1290 tasklet_kill(&sc->intr_tq);
1291 tasklet_kill(&sc->bcon_tasklet);
1292 1242
1293 ath9k_ps_restore(sc); 1243 spin_unlock_bh(&sc->sc_pcu_lock);
1294 1244
1295 sc->ps_idle = true; 1245 ath9k_ps_restore(sc);
1296 ath_radio_disable(sc, hw);
1297 1246
1298 sc->sc_flags |= SC_OP_INVALID; 1247 sc->sc_flags |= SC_OP_INVALID;
1248 sc->ps_idle = prev_idle;
1299 1249
1300 mutex_unlock(&sc->mutex); 1250 mutex_unlock(&sc->mutex);
1301 1251
@@ -1635,8 +1585,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1635 struct ath_hw *ah = sc->sc_ah; 1585 struct ath_hw *ah = sc->sc_ah;
1636 struct ath_common *common = ath9k_hw_common(ah); 1586 struct ath_common *common = ath9k_hw_common(ah);
1637 struct ieee80211_conf *conf = &hw->conf; 1587 struct ieee80211_conf *conf = &hw->conf;
1638 bool disable_radio = false;
1639 1588
1589 ath9k_ps_wakeup(sc);
1640 mutex_lock(&sc->mutex); 1590 mutex_lock(&sc->mutex);
1641 1591
1642 /* 1592 /*
@@ -1645,16 +1595,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1645 * of the changes. Likewise we must only disable the radio towards 1595 * of the changes. Likewise we must only disable the radio towards
1646 * the end. 1596 * the end.
1647 */ 1597 */
1648 if (changed & IEEE80211_CONF_CHANGE_IDLE) { 1598 if (changed & IEEE80211_CONF_CHANGE_IDLE)
1649 sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); 1599 sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
1650 if (!sc->ps_idle) {
1651 ath_radio_enable(sc, hw);
1652 ath_dbg(common, ATH_DBG_CONFIG,
1653 "not-idle: enabling radio\n");
1654 } else {
1655 disable_radio = true;
1656 }
1657 }
1658 1600
1659 /* 1601 /*
1660 * We just prepare to enable PS. We have to wait until our AP has 1602 * We just prepare to enable PS. We have to wait until our AP has
@@ -1760,18 +1702,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1760 ath_dbg(common, ATH_DBG_CONFIG, 1702 ath_dbg(common, ATH_DBG_CONFIG,
1761 "Set power: %d\n", conf->power_level); 1703 "Set power: %d\n", conf->power_level);
1762 sc->config.txpowlimit = 2 * conf->power_level; 1704 sc->config.txpowlimit = 2 * conf->power_level;
1763 ath9k_ps_wakeup(sc);
1764 ath9k_cmn_update_txpow(ah, sc->curtxpow, 1705 ath9k_cmn_update_txpow(ah, sc->curtxpow,
1765 sc->config.txpowlimit, &sc->curtxpow); 1706 sc->config.txpowlimit, &sc->curtxpow);
1766 ath9k_ps_restore(sc);
1767 }
1768
1769 if (disable_radio) {
1770 ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
1771 ath_radio_disable(sc, hw);
1772 } 1707 }
1773 1708
1774 mutex_unlock(&sc->mutex); 1709 mutex_unlock(&sc->mutex);
1710 ath9k_ps_restore(sc);
1775 1711
1776 return 0; 1712 return 0;
1777} 1713}
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 2dcdf63cb390..a439edc5dc06 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -307,12 +307,11 @@ static int ath_pci_suspend(struct device *device)
307 struct ieee80211_hw *hw = pci_get_drvdata(pdev); 307 struct ieee80211_hw *hw = pci_get_drvdata(pdev);
308 struct ath_softc *sc = hw->priv; 308 struct ath_softc *sc = hw->priv;
309 309
310 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
311
312 /* The device has to be moved to FULLSLEEP forcibly. 310 /* The device has to be moved to FULLSLEEP forcibly.
313 * Otherwise the chip never moved to full sleep, 311 * Otherwise the chip never moved to full sleep,
314 * when no interface is up. 312 * when no interface is up.
315 */ 313 */
314 ath9k_hw_disable(sc->sc_ah);
316 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); 315 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
317 316
318 return 0; 317 return 0;
@@ -321,8 +320,6 @@ static int ath_pci_suspend(struct device *device)
321static int ath_pci_resume(struct device *device) 320static int ath_pci_resume(struct device *device)
322{ 321{
323 struct pci_dev *pdev = to_pci_dev(device); 322 struct pci_dev *pdev = to_pci_dev(device);
324 struct ieee80211_hw *hw = pci_get_drvdata(pdev);
325 struct ath_softc *sc = hw->priv;
326 u32 val; 323 u32 val;
327 324
328 /* 325 /*
@@ -334,22 +331,6 @@ static int ath_pci_resume(struct device *device)
334 if ((val & 0x0000ff00) != 0) 331 if ((val & 0x0000ff00) != 0)
335 pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); 332 pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
336 333
337 ath9k_ps_wakeup(sc);
338 /* Enable LED */
339 ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
340 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
341 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
342
343 /*
344 * Reset key cache to sane defaults (all entries cleared) instead of
345 * semi-random values after suspend/resume.
346 */
347 ath9k_cmn_init_crypto(sc->sc_ah);
348 ath9k_ps_restore(sc);
349
350 sc->ps_idle = true;
351 ath_radio_disable(sc, hw);
352
353 return 0; 334 return 0;
354} 335}
355 336