diff options
author | Sujith Manoharan <c_manoha@qca.qualcomm.com> | 2012-04-24 00:53:20 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-04-24 14:54:28 -0400 |
commit | ad12886091cbc955dafd6cb91de2411b3ff36b39 (patch) | |
tree | b49ac5d2614afedefdf15fafdecdd4d7a2d40e93 /drivers/net/wireless/ath/ath9k/main.c | |
parent | 7e3ed02c6e65a0cb4c9259c0d34740305d9aa5e7 (diff) |
ath9k: Fix IDLE Powersave
* PS_WAIT_FOR_TX_ACK is used in network-sleep mode and checking
it for handling IDLE transitions is incorrect. Fix this.
* RX PCU/DMA engines have to be stopped before setting the chip into
full-sleep mode - otherwise the chip becomes mute.
* Make things a bit clear by checking explicitly for network-sleep
mode in the tx() routine and add a couple of debug statements
to aid PS debugging.
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 43 |
1 files changed, 26 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1fc6e331589a..f4b7334cd27c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -113,21 +113,25 @@ void ath9k_ps_restore(struct ath_softc *sc) | |||
113 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 113 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
114 | enum ath9k_power_mode mode; | 114 | enum ath9k_power_mode mode; |
115 | unsigned long flags; | 115 | unsigned long flags; |
116 | bool reset; | ||
116 | 117 | ||
117 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | 118 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
118 | if (--sc->ps_usecount != 0) | 119 | if (--sc->ps_usecount != 0) |
119 | goto unlock; | 120 | goto unlock; |
120 | 121 | ||
121 | if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK)) | 122 | if (sc->ps_idle) { |
123 | ath9k_hw_setrxabort(sc->sc_ah, 1); | ||
124 | ath9k_hw_stopdmarecv(sc->sc_ah, &reset); | ||
122 | mode = ATH9K_PM_FULL_SLEEP; | 125 | mode = ATH9K_PM_FULL_SLEEP; |
123 | else if (sc->ps_enabled && | 126 | } else if (sc->ps_enabled && |
124 | !(sc->ps_flags & (PS_WAIT_FOR_BEACON | | 127 | !(sc->ps_flags & (PS_WAIT_FOR_BEACON | |
125 | PS_WAIT_FOR_CAB | | 128 | PS_WAIT_FOR_CAB | |
126 | PS_WAIT_FOR_PSPOLL_DATA | | 129 | PS_WAIT_FOR_PSPOLL_DATA | |
127 | PS_WAIT_FOR_TX_ACK))) | 130 | PS_WAIT_FOR_TX_ACK))) { |
128 | mode = ATH9K_PM_NETWORK_SLEEP; | 131 | mode = ATH9K_PM_NETWORK_SLEEP; |
129 | else | 132 | } else { |
130 | goto unlock; | 133 | goto unlock; |
134 | } | ||
131 | 135 | ||
132 | spin_lock(&common->cc_lock); | 136 | spin_lock(&common->cc_lock); |
133 | ath_hw_cycle_counters_update(common); | 137 | ath_hw_cycle_counters_update(common); |
@@ -1100,14 +1104,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1100 | } | 1104 | } |
1101 | } | 1105 | } |
1102 | 1106 | ||
1103 | /* | 1107 | if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP)) { |
1104 | * Cannot tx while the hardware is in full sleep, it first needs a full | ||
1105 | * chip reset to recover from that | ||
1106 | */ | ||
1107 | if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) | ||
1108 | goto exit; | ||
1109 | |||
1110 | if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { | ||
1111 | /* | 1108 | /* |
1112 | * We are using PS-Poll and mac80211 can request TX while in | 1109 | * We are using PS-Poll and mac80211 can request TX while in |
1113 | * power save mode. Need to wake up hardware for the TX to be | 1110 | * power save mode. Need to wake up hardware for the TX to be |
@@ -1126,12 +1123,21 @@ static void ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1126 | } | 1123 | } |
1127 | /* | 1124 | /* |
1128 | * The actual restore operation will happen only after | 1125 | * The actual restore operation will happen only after |
1129 | * the sc_flags bit is cleared. We are just dropping | 1126 | * the ps_flags bit is cleared. We are just dropping |
1130 | * the ps_usecount here. | 1127 | * the ps_usecount here. |
1131 | */ | 1128 | */ |
1132 | ath9k_ps_restore(sc); | 1129 | ath9k_ps_restore(sc); |
1133 | } | 1130 | } |
1134 | 1131 | ||
1132 | /* | ||
1133 | * Cannot tx while the hardware is in full sleep, it first needs a full | ||
1134 | * chip reset to recover from that | ||
1135 | */ | ||
1136 | if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP)) { | ||
1137 | ath_err(common, "TX while HW is in FULL_SLEEP mode\n"); | ||
1138 | goto exit; | ||
1139 | } | ||
1140 | |||
1135 | memset(&txctl, 0, sizeof(struct ath_tx_control)); | 1141 | memset(&txctl, 0, sizeof(struct ath_tx_control)); |
1136 | txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; | 1142 | txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; |
1137 | 1143 | ||
@@ -1528,6 +1534,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
1528 | static void ath9k_enable_ps(struct ath_softc *sc) | 1534 | static void ath9k_enable_ps(struct ath_softc *sc) |
1529 | { | 1535 | { |
1530 | struct ath_hw *ah = sc->sc_ah; | 1536 | struct ath_hw *ah = sc->sc_ah; |
1537 | struct ath_common *common = ath9k_hw_common(ah); | ||
1531 | 1538 | ||
1532 | sc->ps_enabled = true; | 1539 | sc->ps_enabled = true; |
1533 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { | 1540 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { |
@@ -1537,11 +1544,13 @@ static void ath9k_enable_ps(struct ath_softc *sc) | |||
1537 | } | 1544 | } |
1538 | ath9k_hw_setrxabort(ah, 1); | 1545 | ath9k_hw_setrxabort(ah, 1); |
1539 | } | 1546 | } |
1547 | ath_dbg(common, PS, "PowerSave enabled\n"); | ||
1540 | } | 1548 | } |
1541 | 1549 | ||
1542 | static void ath9k_disable_ps(struct ath_softc *sc) | 1550 | static void ath9k_disable_ps(struct ath_softc *sc) |
1543 | { | 1551 | { |
1544 | struct ath_hw *ah = sc->sc_ah; | 1552 | struct ath_hw *ah = sc->sc_ah; |
1553 | struct ath_common *common = ath9k_hw_common(ah); | ||
1545 | 1554 | ||
1546 | sc->ps_enabled = false; | 1555 | sc->ps_enabled = false; |
1547 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); | 1556 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); |
@@ -1556,7 +1565,7 @@ static void ath9k_disable_ps(struct ath_softc *sc) | |||
1556 | ath9k_hw_set_interrupts(ah); | 1565 | ath9k_hw_set_interrupts(ah); |
1557 | } | 1566 | } |
1558 | } | 1567 | } |
1559 | 1568 | ath_dbg(common, PS, "PowerSave disabled\n"); | |
1560 | } | 1569 | } |
1561 | 1570 | ||
1562 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | 1571 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) |