From: Ivo van Doorn <[EMAIL PROTECTED]>

Improve the waiting when a skb buffer needs to be send
before the channel switch. This also makes sure no
pending packets are still on the TX ring while making the
channel switch.

Signed-off-by: Ivo van Doorn <[EMAIL PROTECTED]>

diff -uprN wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2400pci.c 
wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
--- wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2400pci.c  
2006-04-27 21:47:52.000000000 +0200
+++ wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2400pci.c    
2006-04-27 21:48:21.000000000 +0200
@@ -838,7 +838,6 @@ rt2400pci_txdone(void *data)
        struct rt2x00_pci       *rt2x00pci = (struct rt2x00_pci*)ring->dev;
        struct net_device       *net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
        struct data_entry       *entry;
-       struct skb_cb           *cb;
        struct txd              *txd;
        int                     tx_status;
        int                     ack;
@@ -851,13 +850,6 @@ rt2400pci_txdone(void *data)
                || !rt2x00_get_field32(txd->word0, TXD_W0_VALID))
                        break;
 
-               /*
-                * Check if this frame was send for the scan routine.
-                */
-               cb = (struct skb_cb*)&entry->skb->cb;
-               if (rt2x00pci->scan && cb->scan_complete)
-                       complete(&rt2x00pci->scan->completion);
-
                ack = rt2x00_get_field32(txd->word0, TXD_W0_ACK);
 
                /*
@@ -896,6 +888,18 @@ rt2400pci_txdone(void *data)
 
                rt2x00_ring_index_done_inc(ring);
        } while (!rt2x00_ring_empty(ring));
+
+       /*
+        * Check if we are waiting on an empty queue
+        * to start scanning.
+        */
+       if (rt2x00pci->scan
+       && rt2x00_ring_empty(&rt2x00pci->tx)
+       && rt2x00_ring_empty(&rt2x00pci->atim)
+       && rt2x00_ring_empty(&rt2x00pci->prio)) {
+               rt2x00pci->scan->status = SCANNING_READY;
+               complete(&rt2x00pci->scan->completion);
+       }
 }
 
 static irqreturn_t
@@ -1517,6 +1521,14 @@ rt2400pci_stop(struct net_device *net_de
        rt2x00_register_write(rt2x00pci, CSR8, reg);
 
        /*
+        * Cancel scanning.
+        */
+       if (rt2x00pci->scan) {
+               rt2x00pci->scan->status = SCANNING_CANCELLED;
+               complete_all(&rt2x00pci->scan->completion);
+       }
+
+       /*
         * Free DMA rings.
         */
        rt2400pci_free_rings(rt2x00pci);
@@ -1564,35 +1576,23 @@ static void
 rt2400pci_scan(void *data)
 {
        struct rt2x00_pci       *rt2x00pci = data;
-       struct net_device       *net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
-       struct skb_cb           *cb;
 
        if (unlikely(!rt2x00pci->scan))
                return;
 
        /*
-        * Check if we have to send a packet before the
-        * channel switch.
+        * Before we can start switch the channel for scanning
+        * we need to wait untill all TX rings are empty to
+        * guarentee that all frames are send on the correct channel.
         */
-       if (rt2x00pci->scan->conf.skb) {
-               cb = (struct skb_cb*)&rt2x00pci->scan->conf.skb->cb;
-               cb->scan_complete = 1;
-
-               if (rt2400pci_tx(net_dev, rt2x00pci->scan->conf.skb,
-                       rt2x00pci->scan->conf.tx_control))
-                       goto exit;
-
-               /*
-                * Wait for the frame to be correctly transmitted.
-                */
+       if (rt2x00pci->scan->status != SCANNING_READY)
                wait_for_completion(&rt2x00pci->scan->completion);
-       }
 
        /*
         * Check if this scan has been cancelled while
         * work was still scheduled.
         */
-       if (rt2x00pci->scan->cancelled)
+       if (rt2x00pci->scan->status == SCANNING_CANCELLED)
                goto exit;
 
        /*
@@ -1633,9 +1633,24 @@ rt2400pci_passive_scan(struct net_device
 {
        struct rt2x00_pci       *rt2x00pci = ieee80211_dev_hw_data(net_dev);
 
+       if (rt2x00pci->scan)
+               return -EBUSY;
+
+       /*
+        * Allocate scanning structure to store scanning info.
+        */
        rt2x00pci->scan = kmalloc(sizeof(struct scanning), GFP_ATOMIC);
        if (!rt2x00pci->scan)
-               return 0;
+               return -ENOMEM;
+
+       /*
+        * Check if we have to send a packet before the
+        * channel switch.
+        */
+       if (conf->skb) {
+               if (rt2400pci_tx(net_dev, conf->skb, conf->tx_control))
+                       goto exit;
+       }
 
        /*
         * Initialize Scanning structure.
@@ -1646,14 +1661,21 @@ rt2400pci_passive_scan(struct net_device
 
        rt2x00pci->scan->state = state;
 
-       rt2x00pci->scan->cancelled = 0;
+       rt2x00pci->scan->status = 0;
 
        /*
         * Queue work.
         */
-       queue_work(rt2x00pci->workqueue, &rt2x00pci->scan_work);
+       if (!queue_work(rt2x00pci->workqueue, &rt2x00pci->scan_work))
+               goto exit;
 
        return 0;
+
+exit:
+       kfree(rt2x00pci->scan);
+       rt2x00pci->scan = NULL;
+
+       return -EIO;
 }
 
 static int
@@ -2207,11 +2229,6 @@ rt2400pci_uninitialize(struct net_device
                rt2x00pci->csr_addr = NULL;
        }
 
-       if (rt2x00pci->scan) {
-               rt2x00pci->scan->cancelled = 1;
-               complete_all(&rt2x00pci->scan->completion);
-       }
-
        if (likely(rt2x00pci->workqueue)) {
                flush_workqueue(rt2x00pci->workqueue);
                destroy_workqueue(rt2x00pci->workqueue);
diff -uprN wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2500pci.c 
wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
--- wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2500pci.c  
2006-04-27 21:47:52.000000000 +0200
+++ wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2500pci.c    
2006-04-27 21:48:21.000000000 +0200
@@ -923,7 +923,6 @@ rt2500pci_txdone(void *data)
        struct rt2x00_pci       *rt2x00pci = (struct rt2x00_pci*)ring->dev;
        struct net_device       *net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
        struct data_entry       *entry;
-       struct skb_cb           *cb;
        struct txd              *txd;
        int                     tx_status;
        int                     ack;
@@ -936,13 +935,6 @@ rt2500pci_txdone(void *data)
                || !rt2x00_get_field32(txd->word0, TXD_W0_VALID))
                        break;
 
-               /*
-                * Check if this frame was send for the scan routine.
-                */
-               cb = (struct skb_cb*)&entry->skb->cb;
-               if (rt2x00pci->scan && cb->scan_complete)
-                       complete(&rt2x00pci->scan->completion);
-
                ack = rt2x00_get_field32(txd->word0, TXD_W0_ACK);
 
                /*
@@ -981,6 +973,18 @@ rt2500pci_txdone(void *data)
 
                rt2x00_ring_index_done_inc(ring);
        } while (!rt2x00_ring_empty(ring));
+
+       /*
+        * Check if we are waiting on an empty queue
+        * to start scanning.
+        */
+       if (rt2x00pci->scan
+       && rt2x00_ring_empty(&rt2x00pci->tx)
+       && rt2x00_ring_empty(&rt2x00pci->atim)
+       && rt2x00_ring_empty(&rt2x00pci->prio)) {
+               rt2x00pci->scan->status = SCANNING_READY;
+               complete(&rt2x00pci->scan->completion);
+       }
 }
 
 static irqreturn_t
@@ -1630,6 +1634,14 @@ rt2500pci_stop(struct net_device *net_de
        rt2x00_register_write(rt2x00pci, CSR8, reg);
 
        /*
+        * Cancel scanning.
+        */
+       if (rt2x00pci->scan) {
+               rt2x00pci->scan->status = SCANNING_CANCELLED;
+               complete_all(&rt2x00pci->scan->completion);
+       }
+
+       /*
         * Free DMA rings.
         */
        rt2500pci_free_rings(rt2x00pci);
@@ -1677,35 +1689,23 @@ static void
 rt2500pci_scan(void *data)
 {
        struct rt2x00_pci       *rt2x00pci = data;
-       struct net_device       *net_dev = pci_get_drvdata(rt2x00pci->pci_dev);
-       struct skb_cb           *cb;
 
        if (unlikely(!rt2x00pci->scan))
                return;
 
        /*
-        * Check if we have to send a packet before the
-        * channel switch.
+        * Before we can start switch the channel for scanning
+        * we need to wait untill all TX rings are empty to
+        * guarentee that all frames are send on the correct channel.
         */
-       if (rt2x00pci->scan->conf.skb) {
-               cb = (struct skb_cb*)&rt2x00pci->scan->conf.skb->cb;
-               cb->scan_complete = 1;
-
-               if (rt2500pci_tx(net_dev, rt2x00pci->scan->conf.skb,
-                       rt2x00pci->scan->conf.tx_control))
-                       goto exit;
-
-               /*
-                * Wait for the frame to be correctly transmitted.
-                */
+       if (rt2x00pci->scan->status != SCANNING_READY)
                wait_for_completion(&rt2x00pci->scan->completion);
-       }
 
        /*
         * Check if this scan has been cancelled while
         * work was still scheduled.
         */
-       if (rt2x00pci->scan->cancelled)
+       if (rt2x00pci->scan->status == SCANNING_CANCELLED)
                goto exit;
 
        /*
@@ -1742,9 +1742,24 @@ rt2500pci_passive_scan(struct net_device
 {
        struct rt2x00_pci       *rt2x00pci = ieee80211_dev_hw_data(net_dev);
 
+       if (rt2x00pci->scan)
+               return -EBUSY;
+
+       /*
+        * Allocate scanning structure to store scanning info.
+        */
        rt2x00pci->scan = kmalloc(sizeof(struct scanning), GFP_ATOMIC);
        if (!rt2x00pci->scan)
-               return 0;
+               return -ENOMEM;
+
+       /*
+        * Check if we have to send a packet before the
+        * channel switch.
+        */
+       if (conf->skb) {
+               if (rt2500pci_tx(net_dev, conf->skb, conf->tx_control))
+                       goto exit;
+       }
 
        /*
         * Initialize Scanning structure.
@@ -1755,14 +1770,21 @@ rt2500pci_passive_scan(struct net_device
 
        rt2x00pci->scan->state = state;
 
-       rt2x00pci->scan->cancelled = 0;
+       rt2x00pci->scan->status = 0;
 
        /*
         * Queue work.
         */
-       queue_work(rt2x00pci->workqueue, &rt2x00pci->scan_work);
+       if (!queue_work(rt2x00pci->workqueue, &rt2x00pci->scan_work))
+               goto exit;
 
        return 0;
+
+exit:
+       kfree(rt2x00pci->scan);
+       rt2x00pci->scan = NULL;
+
+       return -EIO;
 }
 
 static int
@@ -2505,20 +2527,15 @@ rt2500pci_uninitialize(struct net_device
                rt2x00pci->csr_addr = NULL;
        }
 
-       if (rt2x00pci->scan) {
-               rt2x00pci->scan->cancelled = 1;
-               complete_all(&rt2x00pci->scan->completion);
-       }
-
        if (likely(rt2x00pci->workqueue)) {
                flush_workqueue(rt2x00pci->workqueue);
                destroy_workqueue(rt2x00pci->workqueue);
                rt2x00pci->workqueue = NULL;
        }
 
-               kfree(rt2x00pci->hw.modes);
-               rt2x00pci->hw.modes = NULL;
-       }
+       kfree(rt2x00pci->hw.modes);
+       rt2x00pci->hw.modes = NULL;
+}
 
 /*
  * PCI driver handlers.
diff -uprN wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2500usb.c 
wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
--- wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2500usb.c  
2006-04-27 21:47:52.000000000 +0200
+++ wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2500usb.c    
2006-04-27 21:48:21.000000000 +0200
@@ -769,7 +769,6 @@ rt2500usb_txdone(void *data)
        struct net_device       *net_dev = usb_get_intfdata(
                                                rt2x00usb->usb_intf);
        struct data_entry       *entry;
-       struct skb_cb           *cb;
        struct txd              *txd;
        int                     ack;
 
@@ -777,13 +776,6 @@ rt2500usb_txdone(void *data)
                entry = rt2x00_get_data_entry_done(ring);
                txd = entry->desc_addr;
 
-               /*
-                * Check if this frame was send for the scan routine.
-                */
-               cb = (struct skb_cb*)&entry->skb->cb;
-               if (rt2x00usb->scan && cb->scan_complete)
-                       complete(&rt2x00usb->scan->completion);
-
                ack = rt2x00_get_field32(txd->word0, TXD_W0_ACK);
        
                /*
@@ -815,6 +807,18 @@ rt2500usb_txdone(void *data)
        
                rt2x00_ring_index_done_inc(entry->ring);
        } while (!rt2x00_ring_empty(ring));
+
+       /*
+        * Check if we are waiting on an empty queue
+        * to start scanning.
+        */
+       if (rt2x00usb->scan
+       && rt2x00_ring_empty(&rt2x00usb->tx)
+       && rt2x00_ring_empty(&rt2x00usb->atim)
+       && rt2x00_ring_empty(&rt2x00usb->prio)) {
+               rt2x00usb->scan->status = SCANNING_READY;
+               complete(&rt2x00usb->scan->completion);
+       }
 }
 
 static void
@@ -1368,6 +1372,14 @@ rt2500usb_stop(struct net_device *net_de
        rt2x00_register_write(rt2x00usb, MAC_CSR14, 0x2121);
 
        /*
+        * Cancel scanning.
+        */
+       if (rt2x00usb->scan) {
+               rt2x00usb->scan->status = SCANNING_CANCELLED;
+               complete_all(&rt2x00usb->scan->completion);
+       }
+
+       /*
         * Free DMA rings.
         */
        rt2500usb_free_rings(rt2x00usb);
@@ -1414,36 +1426,23 @@ static void
 rt2500usb_scan(void *data)
 {
        struct rt2x00_usb       *rt2x00usb = data;
-       struct net_device       *net_dev =
-               usb_get_intfdata(rt2x00usb->usb_intf);
-       struct skb_cb           *cb;
 
        if (unlikely(!rt2x00usb->scan))
                return;
 
        /*
-        * Check if we have to send a packet before the
-        * channel switch.
+        * Before we can start switch the channel for scanning
+        * we need to wait untill all TX rings are empty to
+        * guarentee that all frames are send on the correct channel.
         */
-       if (rt2x00usb->scan->conf.skb) {
-               cb = (struct skb_cb*)&rt2x00usb->scan->conf.skb->cb;
-               cb->scan_complete = 1;
-
-               if (rt2500usb_tx(net_dev, rt2x00usb->scan->conf.skb,
-                       rt2x00usb->scan->conf.tx_control))
-                       goto exit;
-
-               /*
-                * Wait for the frame to be correctly transmitted.
-                */
+       if (rt2x00usb->scan->status != SCANNING_READY)
                wait_for_completion(&rt2x00usb->scan->completion);
-       }
 
        /*
         * Check if this scan has been cancelled while
         * work was still scheduled.
         */
-       if (rt2x00usb->scan->cancelled)
+       if (rt2x00usb->scan->status == SCANNING_CANCELLED)
                goto exit;
 
        /*
@@ -1480,9 +1479,24 @@ rt2500usb_passive_scan(struct net_device
 {
        struct rt2x00_usb       *rt2x00usb = ieee80211_dev_hw_data(net_dev);
 
+       if (rt2x00usb->scan)
+               return -EBUSY;
+
+       /*
+        * Allocate scanning structure to store scanning info.
+        */
        rt2x00usb->scan = kmalloc(sizeof(struct scanning), GFP_ATOMIC);
        if (!rt2x00usb->scan)
-               return 0;
+               return -ENOMEM;
+
+       /*
+        * Check if we have to send a packet before the
+        * channel switch.
+        */
+       if (conf->skb) {
+               if (rt2500usb_tx(net_dev, conf->skb, conf->tx_control))
+                       goto exit;
+       }
 
        /*
         * Initialize Scanning structure.
@@ -1493,14 +1507,21 @@ rt2500usb_passive_scan(struct net_device
 
        rt2x00usb->scan->state = state;
 
-       rt2x00usb->scan->cancelled = 0;
+       rt2x00usb->scan->status = 0;
 
        /*
         * Queue work.
         */
-       queue_work(rt2x00usb->workqueue, &rt2x00usb->scan_work);
+       if (!queue_work(rt2x00usb->workqueue, &rt2x00usb->scan_work))
+               goto exit;
 
        return 0;
+
+exit:
+       kfree(rt2x00usb->scan);
+       rt2x00usb->scan = NULL;
+
+       return -EIO;
 }
 
 static int
@@ -2121,19 +2142,14 @@ rt2500usb_uninitialize(struct net_device
 
        kfree(rt2x00usb->eeprom);
 
-       if (rt2x00usb->scan) {
-               rt2x00usb->scan->cancelled = 1;
-               complete_all(&rt2x00usb->scan->completion);
-       }
-
        if (likely(rt2x00usb->workqueue)) {
                flush_workqueue(rt2x00usb->workqueue);
                destroy_workqueue(rt2x00usb->workqueue);
                rt2x00usb->workqueue = NULL;
        }
 
-               kfree(rt2x00usb->hw.modes);
-               rt2x00usb->hw.modes = NULL;
+       kfree(rt2x00usb->hw.modes);
+       rt2x00usb->hw.modes = NULL;
 }
 
 /*
diff -uprN wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2x00.h 
wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2x00.h
--- wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2x00.h     
2006-04-27 21:47:52.000000000 +0200
+++ wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2x00.h       
2006-04-27 21:48:21.000000000 +0200
@@ -428,15 +428,6 @@ rt2x00_rf(const struct _rt2x00_chip *chi
 }
 
 /*
- * Data to be placed in the skb->cb array.
- * therefor this structure may not exceed the 40 bytes.
- */
-struct skb_cb{
-       int                                     scan_complete;
-} __attribute__ ((packed));
-
-
-/*
  * data_ring
  * Data rings are used by the device to send and receive packets.
  * The data_addr is the base address of the data memory.
@@ -589,7 +580,9 @@ struct scanning{
        /*
         * Flag to see if this scan has been cancelled.
         */
-       short                                   cancelled;
+       short                                   status;
+#define SCANNING_READY                         0x0001
+#define SCANNING_CANCELLED                     0x0002
 } __attribute__ ((packed));
 
 

Attachment: pgpyyTDFWpS5Z.pgp
Description: PGP signature

Reply via email to