aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/main.c
diff options
context:
space:
mode:
authorSujith Manoharan <c_manoha@qca.qualcomm.com>2012-04-24 00:53:20 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-24 14:54:28 -0400
commitad12886091cbc955dafd6cb91de2411b3ff36b39 (patch)
treeb49ac5d2614afedefdf15fafdecdd4d7a2d40e93 /drivers/net/wireless/ath/ath9k/main.c
parent7e3ed02c6e65a0cb4c9259c0d34740305d9aa5e7 (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.c43
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,
1528static void ath9k_enable_ps(struct ath_softc *sc) 1534static 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
1542static void ath9k_disable_ps(struct ath_softc *sc) 1550static 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
1562static int ath9k_config(struct ieee80211_hw *hw, u32 changed) 1571static int ath9k_config(struct ieee80211_hw *hw, u32 changed)