summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rt2x00/rt2x00usb.c
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2010-07-11 12:25:46 +0200
committerJohn W. Linville <linville@tuxdriver.com>2010-07-12 16:05:34 -0400
commitc965c74bbc650e5466d2f3e32bd28112ebcdd00c (patch)
treeb24e5a745a40b5f7d83b8fb7b04a5abd1c32445f /drivers/net/wireless/rt2x00/rt2x00usb.c
parent223dcc26591aa8e4a6bf623164b775b5bd89c9e1 (diff)
rt2x00: Implement watchdog monitoring
Implement watchdog monitoring for USB devices (PCI support can be added later). This will determine if URBs being uploaded to the hardware are actually returning. Both rt2500usb and rt2800usb have shown that URBs being uploaded can remain hanging without being released by the hardware. By using this watchdog, a queue can be reset when this occurs. For rt2800usb it has been tested that the connection is preserved even though this interruption. Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00usb.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index a22837c560fd..ff3a36622d1b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -292,6 +292,56 @@ void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue);
+static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue)
+{
+ struct queue_entry_priv_usb *entry_priv;
+ unsigned short threshold = queue->threshold;
+
+ WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid);
+
+ /*
+ * Temporarily disable the TX queue, this will force mac80211
+ * to use the other queues until this queue has been restored.
+ *
+ * Set the queue threshold to the queue limit. This prevents the
+ * queue from being enabled during the txdone handler.
+ */
+ queue->threshold = queue->limit;
+ ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+
+ /*
+ * Reset all currently uploaded TX frames.
+ */
+ while (!rt2x00queue_empty(queue)) {
+ entry_priv = rt2x00queue_get_entry(queue, Q_INDEX_DONE)->priv_data;
+ usb_kill_urb(entry_priv->urb);
+
+ /*
+ * We need a short delay here to wait for
+ * the URB to be canceled and invoked the tx_done handler.
+ */
+ udelay(200);
+ }
+
+ /*
+ * The queue has been reset, and mac80211 is allowed to use the
+ * queue again.
+ */
+ queue->threshold = threshold;
+ ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+}
+
+void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ if (rt2x00queue_timeout(queue))
+ rt2x00usb_watchdog_reset_tx(queue);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
+
/*
* RX data handlers.
*/