ath9k: fix processing of TX PS null data frames
When mac80211 was telling us to go into Powersave we listened and immediately turned RX off. This meant hardware would not see the ACKs from the AP we're associated with and hardware we'd end up retransmiting the null data frame in a loop helplessly. Fix this by keeping track of the transmitted nullfunc frames and only when we are sure the AP has sent back an ACK do we go ahead and shut RX off. Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: Vivek Natarajan <Vivek.Natarajan@atheros.com> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
このコミットが含まれているのは:
@@ -2701,8 +2701,15 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We just prepare to enable PS. We have to wait until our AP has
|
||||
* ACK'd our null data frame to disable RX otherwise we'll ignore
|
||||
* those ACKs and end up retransmitting the same null data frames.
|
||||
* IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
|
||||
*/
|
||||
if (changed & IEEE80211_CONF_CHANGE_PS) {
|
||||
if (conf->flags & IEEE80211_CONF_PS) {
|
||||
sc->sc_flags |= SC_OP_PS_ENABLED;
|
||||
if (!(ah->caps.hw_caps &
|
||||
ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
|
||||
@@ -2710,11 +2717,20 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
||||
ath9k_hw_set_interrupts(sc->sc_ah,
|
||||
sc->imask);
|
||||
}
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 1);
|
||||
}
|
||||
sc->ps_enabled = true;
|
||||
/*
|
||||
* At this point we know hardware has received an ACK
|
||||
* of a previously sent null data frame.
|
||||
*/
|
||||
if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) {
|
||||
sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
|
||||
sc->ps_enabled = true;
|
||||
ath9k_hw_setrxabort(sc->sc_ah, 1);
|
||||
}
|
||||
} else {
|
||||
sc->ps_enabled = false;
|
||||
sc->sc_flags &= ~(SC_OP_PS_ENABLED |
|
||||
SC_OP_NULLFUNC_COMPLETED);
|
||||
ath9k_setpower(sc, ATH9K_PM_AWAKE);
|
||||
if (!(ah->caps.hw_caps &
|
||||
ATH9K_HW_CAP_AUTOSLEEP)) {
|
||||
|
新しいイシューから参照
ユーザーをブロックする