aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c105
1 files changed, 46 insertions, 59 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index d0a4b9b270c5..dfa78e8b6470 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
@@ -1245,7 +1251,6 @@ static void ath9k_reclaim_beacon(struct ath_softc *sc,
1245 ath9k_set_beaconing_status(sc, false); 1251 ath9k_set_beaconing_status(sc, false);
1246 ath_beacon_return(sc, avp); 1252 ath_beacon_return(sc, avp);
1247 ath9k_set_beaconing_status(sc, true); 1253 ath9k_set_beaconing_status(sc, true);
1248 sc->sc_flags &= ~SC_OP_BEACONS;
1249} 1254}
1250 1255
1251static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 1256static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
@@ -1376,17 +1381,9 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
1376 ath9k_calculate_summary_state(hw, vif); 1381 ath9k_calculate_summary_state(hw, vif);
1377 1382
1378 if (ath9k_uses_beacons(vif->type)) { 1383 if (ath9k_uses_beacons(vif->type)) {
1379 int error; 1384 /* Reserve a beacon slot for the vif */
1380 /* This may fail because upper levels do not have beacons
1381 * properly configured yet. That's OK, we assume it
1382 * will be properly configured and then we will be notified
1383 * in the info_changed method and set up beacons properly
1384 * there.
1385 */
1386 ath9k_set_beaconing_status(sc, false); 1385 ath9k_set_beaconing_status(sc, false);
1387 error = ath_beacon_alloc(sc, vif); 1386 ath_beacon_alloc(sc, vif);
1388 if (!error)
1389 ath_beacon_config(sc, vif);
1390 ath9k_set_beaconing_status(sc, true); 1387 ath9k_set_beaconing_status(sc, true);
1391 } 1388 }
1392} 1389}
@@ -1537,6 +1534,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
1537static void ath9k_enable_ps(struct ath_softc *sc) 1534static void ath9k_enable_ps(struct ath_softc *sc)
1538{ 1535{
1539 struct ath_hw *ah = sc->sc_ah; 1536 struct ath_hw *ah = sc->sc_ah;
1537 struct ath_common *common = ath9k_hw_common(ah);
1540 1538
1541 sc->ps_enabled = true; 1539 sc->ps_enabled = true;
1542 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { 1540 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
@@ -1546,11 +1544,13 @@ static void ath9k_enable_ps(struct ath_softc *sc)
1546 } 1544 }
1547 ath9k_hw_setrxabort(ah, 1); 1545 ath9k_hw_setrxabort(ah, 1);
1548 } 1546 }
1547 ath_dbg(common, PS, "PowerSave enabled\n");
1549} 1548}
1550 1549
1551static void ath9k_disable_ps(struct ath_softc *sc) 1550static void ath9k_disable_ps(struct ath_softc *sc)
1552{ 1551{
1553 struct ath_hw *ah = sc->sc_ah; 1552 struct ath_hw *ah = sc->sc_ah;
1553 struct ath_common *common = ath9k_hw_common(ah);
1554 1554
1555 sc->ps_enabled = false; 1555 sc->ps_enabled = false;
1556 ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); 1556 ath9k_hw_setpower(ah, ATH9K_PM_AWAKE);
@@ -1565,7 +1565,7 @@ static void ath9k_disable_ps(struct ath_softc *sc)
1565 ath9k_hw_set_interrupts(ah); 1565 ath9k_hw_set_interrupts(ah);
1566 } 1566 }
1567 } 1567 }
1568 1568 ath_dbg(common, PS, "PowerSave disabled\n");
1569} 1569}
1570 1570
1571static int ath9k_config(struct ieee80211_hw *hw, u32 changed) 1571static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1993,7 +1993,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1993 struct ath_common *common = ath9k_hw_common(ah); 1993 struct ath_common *common = ath9k_hw_common(ah);
1994 struct ath_vif *avp = (void *)vif->drv_priv; 1994 struct ath_vif *avp = (void *)vif->drv_priv;
1995 int slottime; 1995 int slottime;
1996 int error;
1997 1996
1998 ath9k_ps_wakeup(sc); 1997 ath9k_ps_wakeup(sc);
1999 mutex_lock(&sc->mutex); 1998 mutex_lock(&sc->mutex);
@@ -2026,13 +2025,25 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
2026 } 2025 }
2027 } 2026 }
2028 2027
2029 /* Enable transmission of beacons (AP, IBSS, MESH) */ 2028 /*
2030 if ((changed & BSS_CHANGED_BEACON) || 2029 * In case of AP mode, the HW TSF has to be reset
2031 ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) { 2030 * when the beacon interval changes.
2031 */
2032 if ((changed & BSS_CHANGED_BEACON_INT) &&
2033 (vif->type == NL80211_IFTYPE_AP))
2034 sc->sc_flags |= SC_OP_TSF_RESET;
2035
2036 /* Configure beaconing (AP, IBSS, MESH) */
2037 if (ath9k_uses_beacons(vif->type) &&
2038 ((changed & BSS_CHANGED_BEACON) ||
2039 (changed & BSS_CHANGED_BEACON_ENABLED) ||
2040 (changed & BSS_CHANGED_BEACON_INT))) {
2032 ath9k_set_beaconing_status(sc, false); 2041 ath9k_set_beaconing_status(sc, false);
2033 error = ath_beacon_alloc(sc, vif); 2042 if (bss_conf->enable_beacon)
2034 if (!error) 2043 ath_beacon_alloc(sc, vif);
2035 ath_beacon_config(sc, vif); 2044 else
2045 avp->is_bslot_active = false;
2046 ath_beacon_config(sc, vif);
2036 ath9k_set_beaconing_status(sc, true); 2047 ath9k_set_beaconing_status(sc, true);
2037 } 2048 }
2038 2049
@@ -2055,30 +2066,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
2055 } 2066 }
2056 } 2067 }
2057 2068
2058 /* Disable transmission of beacons */
2059 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
2060 !bss_conf->enable_beacon) {
2061 ath9k_set_beaconing_status(sc, false);
2062 avp->is_bslot_active = false;
2063 ath9k_set_beaconing_status(sc, true);
2064 }
2065
2066 if (changed & BSS_CHANGED_BEACON_INT) {
2067 /*
2068 * In case of AP mode, the HW TSF has to be reset
2069 * when the beacon interval changes.
2070 */
2071 if (vif->type == NL80211_IFTYPE_AP) {
2072 sc->sc_flags |= SC_OP_TSF_RESET;
2073 ath9k_set_beaconing_status(sc, false);
2074 error = ath_beacon_alloc(sc, vif);
2075 if (!error)
2076 ath_beacon_config(sc, vif);
2077 ath9k_set_beaconing_status(sc, true);
2078 } else
2079 ath_beacon_config(sc, vif);
2080 }
2081
2082 mutex_unlock(&sc->mutex); 2069 mutex_unlock(&sc->mutex);
2083 ath9k_ps_restore(sc); 2070 ath9k_ps_restore(sc);
2084} 2071}