diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 105 |
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 | ||
1251 | static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | 1256 | static 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, | |||
1537 | static void ath9k_enable_ps(struct ath_softc *sc) | 1534 | static 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 | ||
1551 | static void ath9k_disable_ps(struct ath_softc *sc) | 1550 | static 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 | ||
1571 | static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | 1571 | static 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 | } |