mac80211: dynamic PS - don't enter PS when TX frames are pending
authorArik Nemtsov <arik@wizery.com>
Sun, 26 Jun 2011 09:06:54 +0000 (12:06 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 27 Jun 2011 19:09:42 +0000 (15:09 -0400)
Use the tx_frames_pending() driver callback to determine if Tx frames are
pending for its internal queues. If so postpone the dynamic PS timeout
to avoid interrupting Tx traffic.

The commit e8306f989483e4b97a8b37dd268de6c8c6f35e75 enabled this
behavior for drivers with IEEE80211_HW_PS_NULLFUNC_STACK. We enable this
for all drivers supporting dynamic PS.

This patch helps improve performance in noisy environments.

Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/mlme.c

index 0f6052faeb457c1126875f6fbdc26d5589dbe2ce..b87420088c33cb4504e6c77199c49a49c2363fd6 100644 (file)
@@ -760,23 +760,34 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
        if (local->hw.conf.flags & IEEE80211_CONF_PS)
                return;
 
-       /*
-        * transmission can be stopped by others which leads to
-        * dynamic_ps_timer expiry. Postpond the ps timer if it
-        * is not the actual idle state.
-        */
-       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-       for (q = 0; q < local->hw.queues; q++) {
-               if (local->queue_stop_reasons[q]) {
-                       spin_unlock_irqrestore(&local->queue_stop_reason_lock,
-                                              flags);
+       if (!local->disable_dynamic_ps &&
+           local->hw.conf.dynamic_ps_timeout > 0) {
+               /* don't enter PS if TX frames are pending */
+               if (drv_tx_frames_pending(local)) {
                        mod_timer(&local->dynamic_ps_timer, jiffies +
                                  msecs_to_jiffies(
                                  local->hw.conf.dynamic_ps_timeout));
                        return;
                }
+
+               /*
+                * transmission can be stopped by others which leads to
+                * dynamic_ps_timer expiry. Postpone the ps timer if it
+                * is not the actual idle state.
+                */
+               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+               for (q = 0; q < local->hw.queues; q++) {
+                       if (local->queue_stop_reasons[q]) {
+                               spin_unlock_irqrestore(&local->queue_stop_reason_lock,
+                                                      flags);
+                               mod_timer(&local->dynamic_ps_timer, jiffies +
+                                         msecs_to_jiffies(
+                                         local->hw.conf.dynamic_ps_timeout));
+                               return;
+                       }
+               }
+               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
        }
-       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
        if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
            (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) {
@@ -801,7 +812,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
        }
 
-       netif_tx_wake_all_queues(sdata->dev);
+       if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
+               netif_tx_wake_all_queues(sdata->dev);
 }
 
 void ieee80211_dynamic_ps_timer(unsigned long data)