aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Natarajan <vivek.natraj@gmail.com>2009-01-20 00:47:08 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:01:03 -0500
commit3cbb5dd73697b3f1c677daffe29f00ace22b71e9 (patch)
tree39fcb371ef37b9a2a53a4cdf72a8e98c64d9e98e
parentc5d0569882b9c264be31dcb0758961bfc479deea (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>
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h2
-rw-r--r--drivers/net/wireless/ath9k/core.h18
-rw-r--r--drivers/net/wireless/ath9k/hw.c4
-rw-r--r--drivers/net/wireless/ath9k/hw.h1
-rw-r--r--drivers/net/wireless/ath9k/main.c39
-rw-r--r--drivers/net/wireless/ath9k/recv.c6
6 files changed, 66 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 3817645b85dc..0b305b832a8c 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -793,6 +793,8 @@ struct ath_hal {
793 u16 ah_currentRD5G; 793 u16 ah_currentRD5G;
794 u16 ah_currentRD2G; 794 u16 ah_currentRD2G;
795 char ah_iso[4]; 795 char ah_iso[4];
796 enum ath9k_power_mode ah_power_mode;
797 enum ath9k_power_mode ah_restore_mode;
796 798
797 struct ath9k_channel ah_channels[150]; 799 struct ath9k_channel ah_channels[150];
798 struct ath9k_channel *ah_curchan; 800 struct ath9k_channel *ah_curchan;
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index f65933d9c653..0f50767712a6 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -676,6 +676,7 @@ enum PROT_MODE {
676#define SC_OP_RFKILL_REGISTERED BIT(11) 676#define SC_OP_RFKILL_REGISTERED BIT(11)
677#define SC_OP_RFKILL_SW_BLOCKED BIT(12) 677#define SC_OP_RFKILL_SW_BLOCKED BIT(12)
678#define SC_OP_RFKILL_HW_BLOCKED BIT(13) 678#define SC_OP_RFKILL_HW_BLOCKED BIT(13)
679#define SC_OP_WAIT_FOR_BEACON BIT(14)
679 680
680struct ath_bus_ops { 681struct ath_bus_ops {
681 void (*read_cachesize)(struct ath_softc *sc, int *csz); 682 void (*read_cachesize)(struct ath_softc *sc, int *csz);
@@ -709,6 +710,7 @@ struct ath_softc {
709 u32 sc_keymax; 710 u32 sc_keymax;
710 DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); 711 DECLARE_BITMAP(sc_keymap, ATH_KEYMAX);
711 u8 sc_splitmic; 712 u8 sc_splitmic;
713 atomic_t ps_usecount;
712 enum ath9k_int sc_imask; 714 enum ath9k_int sc_imask;
713 enum PROT_MODE sc_protmode; 715 enum PROT_MODE sc_protmode;
714 enum ath9k_ht_extprotspacing sc_ht_extprotspacing; 716 enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
@@ -777,4 +779,20 @@ static inline int ath_ahb_init(void) { return 0; };
777static inline void ath_ahb_exit(void) {}; 779static inline void ath_ahb_exit(void) {};
778#endif 780#endif
779 781
782static inline void ath9k_ps_wakeup(struct ath_softc *sc)
783{
784 if (atomic_inc_return(&sc->ps_usecount) == 1)
785 if (sc->sc_ah->ah_power_mode != ATH9K_PM_AWAKE) {
786 sc->sc_ah->ah_restore_mode = sc->sc_ah->ah_power_mode;
787 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
788 }
789}
790
791static inline void ath9k_ps_restore(struct ath_softc *sc)
792{
793 if (atomic_dec_and_test(&sc->ps_usecount))
794 if (sc->hw->conf.flags & IEEE80211_CONF_PS)
795 ath9k_hw_setpower(sc->sc_ah,
796 sc->sc_ah->ah_restore_mode);
797}
780#endif /* CORE_H */ 798#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 88c8a62e1b8a..ab15e55317c6 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -2698,7 +2698,7 @@ bool ath9k_hw_setpower(struct ath_hal *ah,
2698 int status = true, setChip = true; 2698 int status = true, setChip = true;
2699 2699
2700 DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n", 2700 DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n",
2701 modes[ahp->ah_powerMode], modes[mode], 2701 modes[ah->ah_power_mode], modes[mode],
2702 setChip ? "set chip " : ""); 2702 setChip ? "set chip " : "");
2703 2703
2704 switch (mode) { 2704 switch (mode) {
@@ -2717,7 +2717,7 @@ bool ath9k_hw_setpower(struct ath_hal *ah,
2717 "Unknown power mode %u\n", mode); 2717 "Unknown power mode %u\n", mode);
2718 return false; 2718 return false;
2719 } 2719 }
2720 ahp->ah_powerMode = mode; 2720 ah->ah_power_mode = mode;
2721 2721
2722 return status; 2722 return status;
2723} 2723}
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
index d44e016f9880..087c5718707b 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -844,7 +844,6 @@ struct ath_hal_5416 {
844 bool ah_chipFullSleep; 844 bool ah_chipFullSleep;
845 u32 ah_atimWindow; 845 u32 ah_atimWindow;
846 u16 ah_antennaSwitchSwap; 846 u16 ah_antennaSwitchSwap;
847 enum ath9k_power_mode ah_powerMode;
848 enum ath9k_ant_setting ah_diversityControl; 847 enum ath9k_ant_setting ah_diversityControl;
849 848
850 /* Calibration */ 849 /* Calibration */
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
1080static void ath_radio_disable(struct ath_softc *sc) 1087static 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
1113static bool ath_is_rfkill_set(struct ath_softc *sc) 1122static 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
1288static int ath_init(u16 devid, struct ath_softc *sc) 1300static 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
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 648bb49e6734..8da08f9b463c 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -628,6 +628,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
628 } else { 628 } else {
629 sc->rx.rxotherant = 0; 629 sc->rx.rxotherant = 0;
630 } 630 }
631
632 if (ieee80211_is_beacon(hdr->frame_control) &&
633 (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) {
634 sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
635 ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
636 }
631requeue: 637requeue:
632 list_move_tail(&bf->list, &sc->rx.rxbuf); 638 list_move_tail(&bf->list, &sc->rx.rxbuf);
633 ath_rx_buf_link(sc, bf); 639 ath_rx_buf_link(sc, bf);