rt2x00: Move TX/RX work into dedicated workqueue
authorIvo van Doorn <IvDoorn@gmail.com>
Sun, 30 Jan 2011 12:24:05 +0000 (13:24 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 31 Jan 2011 20:06:25 +0000 (15:06 -0500)
The TX/RX work structures must be able to run independently
of other workqueues. This is because mac80211 might use
the flush() callback function from various context, which depends
on the TX/RX work to complete while the main thread is blocked
(until the the TX queues are empty).

This should reduce the number of  'Queue %d failed to flush' warnings.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00link.c
drivers/net/wireless/rt2x00/rt2x00usb.c

index 7661e4f60ddcfd83fed380e97c7ae96053d3f776..39bc2faf179305ec78bc7ec0a80fc30682eee18d 100644 (file)
@@ -860,6 +860,13 @@ struct rt2x00_dev {
         */
        struct ieee80211_low_level_stats low_level_stats;
 
+       /**
+        * Work queue for all work which should not be placed
+        * on the mac80211 workqueue (because of dependencies
+        * between various work structures).
+        */
+       struct workqueue_struct *workqueue;
+
        /*
         * Scheduled work.
         * NOTE: intf_work will use ieee80211_iterate_active_interfaces()
index e7162852ec34f820dfa23ef03b583d7a82a90d15..9de9dbe943998e1790a8d514157eea8028410238 100644 (file)
@@ -997,8 +997,15 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
                    BIT(NL80211_IFTYPE_WDS);
 
        /*
-        * Initialize configuration work.
+        * Initialize work.
         */
+       rt2x00dev->workqueue =
+           alloc_ordered_workqueue(wiphy_name(rt2x00dev->hw->wiphy), 0);
+       if (!rt2x00dev->workqueue) {
+               retval = -ENOMEM;
+               goto exit;
+       }
+
        INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
 
        /*
@@ -1057,6 +1064,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
        cancel_work_sync(&rt2x00dev->intf_work);
        cancel_work_sync(&rt2x00dev->rxdone_work);
        cancel_work_sync(&rt2x00dev->txdone_work);
+       destroy_workqueue(rt2x00dev->workqueue);
 
        /*
         * Free the tx status fifo.
index bfda60eaf4efc6b888091f7e7976cd7a2c4d0267..c975b0a12e950a5bfc3764ecec16fb6478580b18 100644 (file)
@@ -417,7 +417,8 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
            !test_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags))
                return;
 
-       schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL);
+       ieee80211_queue_delayed_work(rt2x00dev->hw,
+                                    &link->watchdog_work, WATCHDOG_INTERVAL);
 }
 
 void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -441,7 +442,9 @@ static void rt2x00link_watchdog(struct work_struct *work)
        rt2x00dev->ops->lib->watchdog(rt2x00dev);
 
        if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
-               schedule_delayed_work(&link->watchdog_work, WATCHDOG_INTERVAL);
+               ieee80211_queue_delayed_work(rt2x00dev->hw,
+                                            &link->watchdog_work,
+                                            WATCHDOG_INTERVAL);
 }
 
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
index 1a9937d5aff65e923498cc31208fd1e8b42e3168..fbe735f5b352319198a3fae5be0560b9e8b5b429 100644 (file)
@@ -227,7 +227,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
         * Schedule the delayed work for reading the TX status
         * from the device.
         */
-       ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work);
+       queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
 }
 
 static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
@@ -320,7 +320,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
         * Schedule the delayed work for reading the RX status
         * from the device.
         */
-       ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
+       queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work);
 }
 
 static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
@@ -429,7 +429,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue)
                 * Schedule the completion handler manually, when this
                 * worker function runs, it should cleanup the queue.
                 */
-               ieee80211_queue_work(queue->rt2x00dev->hw, completion);
+               queue_work(queue->rt2x00dev->workqueue, completion);
 
                /*
                 * Wait for a little while to give the driver
@@ -453,7 +453,7 @@ static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
        WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
                " invoke forced tx handler\n", queue->qid);
 
-       ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work);
+       queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work);
 }
 
 void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)