aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-11-06 05:35:50 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-06 16:49:10 -0500
commitaf81858172cc0f3da81946aab919c26e4b364efc (patch)
tree8e7a4bf30ff7c23636d810c5a912ff7e3ddb7333 /net/mac80211/tx.c
parent70d9f405d09e334b609702d88ee03b6119c4b45e (diff)
mac80211: async station powersave handling
Some devices require that all frames to a station are flushed when that station goes into powersave mode before being able to send frames to that station again when it wakes up or polls -- all in order to avoid reordering and too many or too few frames being sent to the station when it polls. Normally, this is the case unless the station goes to sleep and wakes up very quickly again. But in that case, frames for it may be pending on the hardware queues, and thus races could happen in the case of multiple hardware queues used for QoS/WMM. Normally this isn't a problem, but with the iwlwifi mechanism we need to make sure the race doesn't happen. This makes mac80211 able to cope with the race with driver help by a new WLAN_STA_PS_DRIVER per-station flag that can be controlled by the driver and tells mac80211 whether it can transmit frames or not. This flag must be set according to very specific rules outlined in the documentation for the function that controls it. When we buffer new frames for the station, we normally set the TIM bit right away, but while the driver has blocked transmission to that sta we need to avoid that as well since we cannot respond to the station if it wakes up due to the TIM bit. Once the driver unblocks, we can set the TIM bit. Similarly, when the station just wakes up, we need to wait until all other frames are flushed before we can transmit frames to that station, so the same applies here, we need to wait for the driver to give the OK. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r--net/mac80211/tx.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c7dc8ccff5b2..bfaa43e096d2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -374,7 +374,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
374 374
375 staflags = get_sta_flags(sta); 375 staflags = get_sta_flags(sta);
376 376
377 if (unlikely((staflags & WLAN_STA_PS) && 377 if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) &&
378 !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { 378 !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
379#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 379#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
380 printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " 380 printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries "
@@ -397,8 +397,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
397 } else 397 } else
398 tx->local->total_ps_buffered++; 398 tx->local->total_ps_buffered++;
399 399
400 /* Queue frame to be sent after STA sends an PS Poll frame */ 400 /*
401 if (skb_queue_empty(&sta->ps_tx_buf)) 401 * Queue frame to be sent after STA wakes up/polls,
402 * but don't set the TIM bit if the driver is blocking
403 * wakeup or poll response transmissions anyway.
404 */
405 if (skb_queue_empty(&sta->ps_tx_buf) &&
406 !(staflags & WLAN_STA_PS_DRIVER))
402 sta_info_set_tim_bit(sta); 407 sta_info_set_tim_bit(sta);
403 408
404 info->control.jiffies = jiffies; 409 info->control.jiffies = jiffies;
@@ -408,7 +413,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
408 return TX_QUEUED; 413 return TX_QUEUED;
409 } 414 }
410#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 415#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
411 else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) { 416 else if (unlikely(staflags & WLAN_STA_PS_STA)) {
412 printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " 417 printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll "
413 "set -> send frame\n", tx->dev->name, 418 "set -> send frame\n", tx->dev->name,
414 sta->sta.addr); 419 sta->sta.addr);