]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
mac80211: move netdev queue enabling to correct spot
authorJohannes Berg <johannes.berg@intel.com>
Mon, 22 Mar 2010 20:42:43 +0000 (13:42 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 26 Apr 2010 14:41:17 +0000 (07:41 -0700)
commit 7236fe29fd72d17074574ba312e7f1bb9d10abaa upstream.

"mac80211: fix skb buffering issue" still left a race
between enabling the hardware queues and the virtual
interface queues. In hindsight it's totally obvious
that enabling the netdev queues for a hardware queue
when the hardware queue is enabled is wrong, because
it could well possible that we can fill the hw queue
with packets we already have pending. Thus, we must
only enable the netdev queues once all the pending
packets have been processed and sent off to the device.

In testing, I haven't been able to trigger this race
condition, but it's clearly there, possibly only when
aggregation is being enabled.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
net/mac80211/tx.c
net/mac80211/util.c

index 441f68e3f3790c5a0c9012927f25901643f87ce2..d3efff204143d4c2a8f66dc0639b2caa0e330078 100644 (file)
@@ -1881,6 +1881,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
 void ieee80211_tx_pending(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *)data;
+       struct ieee80211_sub_if_data *sdata;
        unsigned long flags;
        int i;
        bool txok;
@@ -1921,6 +1922,11 @@ void ieee80211_tx_pending(unsigned long data)
                        if (!txok)
                                break;
                }
+
+               if (skb_queue_empty(&local->pending[i]))
+                       list_for_each_entry_rcu(sdata, &local->interfaces, list)
+                               netif_tx_wake_queue(
+                                       netdev_get_tx_queue(sdata->dev, i));
        }
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
 
index 553cffe9ab37045acf717e6b11022bc0381fc0e3..6a97c76036c884ed1c5f743b7a3ba57ecd0f3e27 100644 (file)
@@ -280,13 +280,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
                /* someone still has this queue stopped */
                return;
 
-       if (!skb_queue_empty(&local->pending[queue]))
+       if (skb_queue_empty(&local->pending[queue])) {
+               rcu_read_lock();
+               list_for_each_entry_rcu(sdata, &local->interfaces, list)
+                       netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
+               rcu_read_unlock();
+       } else
                tasklet_schedule(&local->tx_pending_tasklet);
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list)
-               netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
-       rcu_read_unlock();
 }
 
 void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,