From: Ivo van Doorn <ivdoorn@gmail.com>
To: "John W. Linville" <linville@tuxdriver.com>
Cc: linux-wireless@vger.kernel.org, users@rt2x00.serialmonkey.com
Subject: [PATCH 11/17] rt2x00: Add "flush" queue command
Date: Mon, 13 Dec 2010 12:35:40 +0100 [thread overview]
Message-ID: <201012131235.41811.IvDoorn@gmail.com> (raw)
In-Reply-To: <201012131235.19063.IvDoorn@gmail.com>
Add a new command to the queue handlers: "flush",
this moves the flush() callback from mac80211
into rt2x00queue and adds support for flushing
the RX queue as well.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Helmut Schaa <helmut.schaa@googlemail.com>
---
drivers/net/wireless/rt2x00/rt2500usb.c | 3 +-
drivers/net/wireless/rt2x00/rt2800usb.c | 3 +-
drivers/net/wireless/rt2x00/rt2x00.h | 21 +++++++
drivers/net/wireless/rt2x00/rt2x00dev.c | 1 +
drivers/net/wireless/rt2x00/rt2x00mac.c | 32 +----------
drivers/net/wireless/rt2x00/rt2x00queue.c | 85 +++++++++++++++++++++++++++++
drivers/net/wireless/rt2x00/rt2x00usb.c | 70 ++++++++++++++++--------
drivers/net/wireless/rt2x00/rt2x00usb.h | 4 +-
drivers/net/wireless/rt2x00/rt73usb.c | 3 +-
9 files changed, 161 insertions(+), 61 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index a56b38f..6b3b1de4 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -785,8 +785,6 @@ static void rt2500usb_stop_queue(struct data_queue *queue)
default:
break;
}
-
- rt2x00usb_stop_queue(queue);
}
/*
@@ -1842,6 +1840,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.start_queue = rt2500usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt2500usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 60b5503..3e0205d 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -96,8 +96,6 @@ static void rt2800usb_stop_queue(struct data_queue *queue)
default:
break;
}
-
- rt2x00usb_stop_queue(queue);
}
/*
@@ -623,6 +621,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.start_queue = rt2800usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt2800usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt2800usb_write_tx_desc,
.write_tx_data = rt2800usb_write_tx_data,
.write_beacon = rt2800_write_beacon,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 511ca91..520e736 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -575,6 +575,7 @@ struct rt2x00lib_ops {
void (*start_queue) (struct data_queue *queue);
void (*kick_queue) (struct data_queue *queue);
void (*stop_queue) (struct data_queue *queue);
+ void (*flush_queue) (struct data_queue *queue);
/*
* TX control handlers
@@ -1108,6 +1109,16 @@ void rt2x00queue_start_queue(struct data_queue *queue);
void rt2x00queue_stop_queue(struct data_queue *queue);
/**
+ * rt2x00queue_flush_queue - Flush a data queue
+ * @queue: Pointer to &struct data_queue.
+ * @drop: True to drop all pending frames.
+ *
+ * This function will flush the queue. After this call
+ * the queue is guarenteed to be empty.
+ */
+void rt2x00queue_flush_queue(struct data_queue *queue, bool drop);
+
+/**
* rt2x00queue_start_queues - Start all data queues
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
@@ -1124,6 +1135,16 @@ void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev);
*/
void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);
+/**
+ * rt2x00queue_flush_queues - Flush all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @drop: True to drop all pending frames.
+ *
+ * This function will loop through all available queues to flush
+ * any pending frames.
+ */
+void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop);
+
/*
* Debugfs handlers.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index fbc98dd..01c8415 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -94,6 +94,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
*/
rt2x00link_stop_tuner(rt2x00dev);
rt2x00queue_stop_queues(rt2x00dev);
+ rt2x00queue_flush_queues(rt2x00dev, true);
/*
* Disable radio.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c4abb20..4cac7ad 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -718,36 +718,8 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
- unsigned int i = 0;
- ieee80211_stop_queues(hw);
-
- /*
- * Run over all queues to kick them, this will force
- * any pending frames to be transmitted.
- */
- tx_queue_for_each(rt2x00dev, queue) {
- rt2x00dev->ops->lib->kick_queue(queue);
- }
-
- /**
- * All queues have been kicked, now wait for each queue
- * to become empty. With a bit of luck, we only have to wait
- * for the first queue to become empty, because while waiting
- * for the that queue, the other queues will have transmitted
- * all their frames as well (since they were already kicked).
- */
- tx_queue_for_each(rt2x00dev, queue) {
- for (i = 0; i < 10; i++) {
- if (rt2x00queue_empty(queue))
- break;
- msleep(100);
- }
-
- if (!rt2x00queue_empty(queue))
- WARNING(rt2x00dev, "Failed to flush queue %d\n", queue->qid);
- }
-
- ieee80211_wake_queues(hw);
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_flush_queue(queue, drop);
}
EXPORT_SYMBOL_GPL(rt2x00mac_flush);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 558965f..313a8fa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -780,6 +780,12 @@ void rt2x00queue_unpause_queue(struct data_queue *queue)
*/
ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
break;
+ case QID_RX:
+ /*
+ * For RX we need to kick the queue now in order to
+ * receive frames.
+ */
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
default:
break;
}
@@ -823,6 +829,74 @@ void rt2x00queue_stop_queue(struct data_queue *queue)
}
EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue);
+void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
+{
+ unsigned int i;
+ bool started;
+ bool tx_queue =
+ (queue->qid == QID_AC_BE) ||
+ (queue->qid == QID_AC_BK) ||
+ (queue->qid == QID_AC_VI) ||
+ (queue->qid == QID_AC_VO);
+
+ mutex_lock(&queue->status_lock);
+
+ /*
+ * If the queue has been started, we must stop it temporarily
+ * to prevent any new frames to be queued on the device. If
+ * we are not dropping the pending frames, the queue must
+ * only be stopped in the software and not the hardware,
+ * otherwise the queue will never become empty on its own.
+ */
+ started = test_bit(QUEUE_STARTED, &queue->flags);
+ if (started) {
+ /*
+ * Pause the queue
+ */
+ rt2x00queue_pause_queue(queue);
+
+ /*
+ * If we are not supposed to drop any pending
+ * frames, this means we must force a start (=kick)
+ * to the queue to make sure the hardware will
+ * start transmitting.
+ */
+ if (!drop && tx_queue)
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
+ }
+
+ /*
+ * Check if driver supports flushing, we can only guarentee
+ * full support for flushing if the driver is able
+ * to cancel all pending frames (drop = true).
+ */
+ if (drop && queue->rt2x00dev->ops->lib->flush_queue)
+ queue->rt2x00dev->ops->lib->flush_queue(queue);
+
+ /*
+ * When we don't want to drop any frames, or when
+ * the driver doesn't fully flush the queue correcly,
+ * we must wait for the queue to become empty.
+ */
+ for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++)
+ msleep(10);
+
+ /*
+ * The queue flush has failed...
+ */
+ if (unlikely(!rt2x00queue_empty(queue)))
+ WARNING(queue->rt2x00dev, "Queue %d failed to flush", queue->qid);
+
+ /*
+ * Restore the queue to the previous status
+ */
+ if (started)
+ rt2x00queue_unpause_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_flush_queue);
+
void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
@@ -857,6 +931,17 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2x00queue_stop_queues);
+void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_flush_queue(queue, drop);
+
+ rt2x00queue_flush_queue(rt2x00dev->rx, drop);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_flush_queues);
+
static void rt2x00queue_reset(struct data_queue *queue)
{
unsigned long irqflags;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index fca29ae..cd80eec 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -366,7 +366,7 @@ void rt2x00usb_kick_queue(struct data_queue *queue)
}
EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);
-static void rt2x00usb_kill_entry(struct queue_entry *entry)
+static void rt2x00usb_flush_entry(struct queue_entry *entry)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
@@ -385,37 +385,61 @@ static void rt2x00usb_kill_entry(struct queue_entry *entry)
usb_kill_urb(bcn_priv->guardian_urb);
}
-void rt2x00usb_stop_queue(struct data_queue *queue)
+void rt2x00usb_flush_queue(struct data_queue *queue)
{
+ struct work_struct *completion;
+ unsigned int i;
+
rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
- rt2x00usb_kill_entry);
+ rt2x00usb_flush_entry);
+
+ /*
+ * Obtain the queue completion handler
+ */
+ switch (queue->qid) {
+ case QID_AC_BE:
+ case QID_AC_BK:
+ case QID_AC_VI:
+ case QID_AC_VO:
+ completion = &queue->rt2x00dev->txdone_work;
+ break;
+ case QID_RX:
+ completion = &queue->rt2x00dev->rxdone_work;
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < 20; i++) {
+ /*
+ * Check if the driver is already done, otherwise we
+ * have to sleep a little while to give the driver/hw
+ * the oppurtunity to complete interrupt process itself.
+ */
+ if (rt2x00queue_empty(queue))
+ break;
+
+ /*
+ * Schedule the completion handler manually, when this
+ * worker function runs, it should cleanup the queue.
+ */
+ ieee80211_queue_work(queue->rt2x00dev->hw, completion);
+
+ /*
+ * Wait for a little while to give the driver
+ * the oppurtunity to recover itself.
+ */
+ msleep(10);
+ }
}
-EXPORT_SYMBOL_GPL(rt2x00usb_stop_queue);
+EXPORT_SYMBOL_GPL(rt2x00usb_flush_queue);
static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
-
WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
" invoke forced forced reset\n", queue->qid);
- /*
- * Temporarily disable the TX queue, this will force mac80211
- * to use the other queues until this queue has been restored.
- */
- rt2x00queue_stop_queue(queue);
-
- /*
- * In case that a driver has overriden the txdone_work
- * function, we invoke the TX done through there.
- */
- rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work);
-
- /*
- * The queue has been reset, and mac80211 is allowed to use the
- * queue again.
- */
- rt2x00queue_start_queue(queue);
+ rt2x00queue_flush_queue(queue, true);
}
static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 05a5424..6aaf51f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -387,13 +387,13 @@ struct queue_entry_priv_usb_bcn {
void rt2x00usb_kick_queue(struct data_queue *queue);
/**
- * rt2x00usb_stop_queue - Stop data queue
+ * rt2x00usb_flush_queue - Flush data queue
* @queue: Data queue to stop
*
* This will walk through all entries of the queue and kill all
* URB's which were send to the device.
*/
-void rt2x00usb_stop_queue(struct data_queue *queue);
+void rt2x00usb_flush_queue(struct data_queue *queue);
/**
* rt2x00usb_watchdog - Watchdog for USB communication
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index f55e74e..0b3959b 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1077,8 +1077,6 @@ static void rt73usb_stop_queue(struct data_queue *queue)
default:
break;
}
-
- rt2x00usb_stop_queue(queue);
}
/*
@@ -2309,6 +2307,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.start_queue = rt73usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt73usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt73usb_write_tx_desc,
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
--
1.7.2.3
next prev parent reply other threads:[~2010-12-13 11:40 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-13 11:31 [PATCH 01/17] rt2x00: Add rt2800 EEPROM definition Ivo van Doorn
2010-12-13 11:31 ` [PATCH 02/17] rt2x00: Implement get_survey callback for rt2800 Ivo van Doorn
2010-12-13 11:32 ` [PATCH 03/17] rt2x00: Add RF chip definition Ivo van Doorn
2010-12-13 11:32 ` [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use Ivo van Doorn
2010-12-13 11:33 ` [PATCH 05/17] rt2x00: Ensure TX-ed frames are returned in the original state Ivo van Doorn
2010-12-13 11:33 ` [PATCH 06/17] rt2x00: Don't frequently reset beacon interval in AdHoc mode Ivo van Doorn
2010-12-13 11:34 ` [PATCH 07/17] rt2x00: trivial: add missing \n on warnings Ivo van Doorn
2010-12-13 11:34 ` [PATCH 08/17] rt2x00: Introduce 3 queue commands in drivers (start, kick, stop) Ivo van Doorn
2010-12-13 11:34 ` [PATCH 09/17] rt2x00: Reorganize queue callback functions Ivo van Doorn
2010-12-13 11:35 ` [PATCH 10/17] rt2x00: Protect queue control with mutex Ivo van Doorn
2010-12-13 11:35 ` Ivo van Doorn [this message]
2010-12-13 11:36 ` [PATCH 12/17] rt2x00: Cleanup RX index counting Ivo van Doorn
2010-12-13 11:36 ` [PATCH 13/17] rt2x00: Introduce extra queue entry sanity flag Ivo van Doorn
2010-12-13 11:36 ` [PATCH 14/17] rt2x00: Fix WMM Queue naming Ivo van Doorn
2010-12-13 11:38 ` [PATCH 15/17] rt2x00: remove stray semicolon Ivo van Doorn
2010-12-13 11:39 ` [PATCH 16/17] rt2x00: Pad beacon to multiple of 32 bits Ivo van Doorn
2010-12-13 11:39 ` [PATCH 17/17] rt2x00: Fix firmware loading regression on x86_64 Ivo van Doorn
2010-12-14 17:49 ` [PATCH 14/17] rt2x00: Fix WMM Queue naming Helmut Schaa
2010-12-14 18:44 ` Ivo Van Doorn
2010-12-14 18:57 ` Helmut Schaa
2010-12-14 19:24 ` Johannes Stezenbach
2010-12-15 16:38 ` Ivo Van Doorn
2010-12-13 12:27 ` [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use Walter Goldens
2010-12-13 12:36 ` Ivo Van Doorn
2010-12-13 13:16 ` Walter Goldens
2010-12-16 13:04 ` Walter Goldens
2010-12-16 14:10 ` wimaxd daemon bug Alexander Khryukin
2010-12-17 13:58 ` Alexander Khryukin
2010-12-16 20:43 ` [PATCH 04/17] rt2x00: fix hang when unplugging USB device in use Ivo Van Doorn
2010-12-17 11:56 ` Walter Goldens
2010-12-17 15:02 ` Johannes Stezenbach
2010-12-17 16:33 ` Walter Goldens
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201012131235.41811.IvDoorn@gmail.com \
--to=ivdoorn@gmail.com \
--cc=linux-wireless@vger.kernel.org \
--cc=linville@tuxdriver.com \
--cc=users@rt2x00.serialmonkey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.