mac80211: fix fragmentation kludge
authorTomas Winkler <tomas.winkler@intel.com>
Thu, 24 Jul 2008 15:46:44 +0000 (18:46 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 1 Aug 2008 19:31:33 +0000 (15:31 -0400)
This patch make mac80211 transmit correctly fragmented packet after
queue was stopped

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/ieee80211_i.h
net/mac80211/tx.c
net/mac80211/util.c

index a4f9a832722a90a0e435b9dab8c8a16f3957162f..a2e200f9811e0b929e5ccabe86edbcd81a331018 100644 (file)
@@ -586,6 +586,7 @@ struct ieee80211_local {
        struct timer_list sta_cleanup;
 
        unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
+       unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
        struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES];
        struct tasklet_struct tx_pending_tasklet;
 
index 69019e943873b697a4d383b0933318928512b4e5..771ec68b848d31a653d3a353e8094affc37833b8 100644 (file)
@@ -1060,13 +1060,14 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
                          struct ieee80211_tx_data *tx)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_info *info;
        int ret, i;
 
-       if (netif_subqueue_stopped(local->mdev, skb))
-               return IEEE80211_TX_AGAIN;
-
        if (skb) {
+               if (netif_subqueue_stopped(local->mdev, skb))
+                       return IEEE80211_TX_AGAIN;
+               info =  IEEE80211_SKB_CB(skb);
+
                ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
                                     "TX to low-level driver", skb);
                ret = local->ops->tx(local_to_hw(local), skb);
@@ -1215,6 +1216,7 @@ retry:
 
                if (ret == IEEE80211_TX_FRAG_AGAIN)
                        skb = NULL;
+
                set_bit(queue, local->queues_pending);
                smp_mb();
                /*
@@ -1708,14 +1710,19 @@ void ieee80211_tx_pending(unsigned long data)
        netif_tx_lock_bh(dev);
        for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
                /* Check that this queue is ok */
-               if (__netif_subqueue_stopped(local->mdev, i))
+               if (__netif_subqueue_stopped(local->mdev, i) &&
+                   !test_bit(i, local->queues_pending_run))
                        continue;
 
                if (!test_bit(i, local->queues_pending)) {
+                       clear_bit(i, local->queues_pending_run);
                        ieee80211_wake_queue(&local->hw, i);
                        continue;
                }
 
+               clear_bit(i, local->queues_pending_run);
+               netif_start_subqueue(local->mdev, i);
+
                store = &local->pending_packet[i];
                tx.extra_frag = store->extra_frag;
                tx.num_extra_frag = store->num_extra_frag;
index 19f85e1b369576c1f340ec563c794d87079e1df1..0d463c80c4045359a8c8f0dc6df29903eae4f8a0 100644 (file)
@@ -361,6 +361,7 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
        struct ieee80211_local *local = hw_to_local(hw);
 
        if (test_bit(queue, local->queues_pending)) {
+               set_bit(queue, local->queues_pending_run);
                tasklet_schedule(&local->tx_pending_tasklet);
        } else {
                netif_wake_subqueue(local->mdev, queue);