All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 16/32] rt2x00: Make sure TX rings are empty when scanning
@ 2006-04-27 22:03 Ivo van Doorn
  0 siblings, 0 replies; only message in thread
From: Ivo van Doorn @ 2006-04-27 22:03 UTC (permalink / raw)
  To: netdev; +Cc: rt2x00-devel

[-- Attachment #1: Type: text/plain, Size: 15118 bytes --]

From: Ivo van Doorn <IvDoorn@gmail.com>

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 <IvDoorn@gmail.com>

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 #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2006-04-27 22:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-27 22:03 [PATCH 16/32] rt2x00: Make sure TX rings are empty when scanning Ivo van Doorn

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.