From: Ivo van Doorn 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 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));