Back-port of the following upstream commit... commit 8e260c22238dd8b57aefb1f5e4bd114486a9c17d Author: Ivo van Doorn Date: Fri Jul 4 13:41:31 2008 +0200 rt2x00: Use ieee80211_hw->workqueue again Remove the rt2x00 singlethreaded workqueue and move the link tuner and packet filter scheduled work to the ieee80211_hw->workqueue again. The only exception is the interface scheduled work handler which uses the mac80211 interface iterator under the RTNL lock. This work needs to be handled on the kernel workqueue to prevent lockdep issues. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- linux-2.6.18.noarch/drivers/net/wireless/rt2x00/rt2x00.h.orig 2009-06-24 07:50:07.000000000 -0400 +++ linux-2.6.18.noarch/drivers/net/wireless/rt2x00/rt2x00.h 2009-06-24 08:10:52.000000000 -0400 @@ -820,8 +820,10 @@ struct rt2x00_dev { /* * Scheduled work. + * NOTE: intf_work will use ieee80211_iterate_active_interfaces() + * which means it cannot be placed on the hw->workqueue + * due to RTNL locking requirements. */ - struct workqueue_struct *workqueue; struct work_struct intf_work; struct work_struct filter_work; --- linux-2.6.18.noarch/drivers/net/wireless/rt2x00/rt2x00dev.c.orig 2009-06-24 07:50:16.000000000 -0400 +++ linux-2.6.18.noarch/drivers/net/wireless/rt2x00/rt2x00dev.c 2009-06-24 08:12:15.000000000 -0400 @@ -75,7 +75,7 @@ static void rt2x00lib_start_link_tuner(s rt2x00lib_reset_link_tuner(rt2x00dev); - queue_delayed_work(rt2x00dev->workqueue, + queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, LINK_TUNE_INTERVAL); } @@ -396,7 +396,7 @@ static void rt2x00lib_link_tuner(void *r * Increase tuner counter, and reschedule the next link tuner run. */ rt2x00dev->link.count++; - queue_delayed_work(rt2x00dev->workqueue, + queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, LINK_TUNE_INTERVAL); } @@ -492,7 +492,7 @@ void rt2x00lib_beacondone(struct rt2x00_ rt2x00lib_beacondone_iter, rt2x00dev); - queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work); + schedule_work(&rt2x00dev->intf_work); } EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); @@ -1135,10 +1135,6 @@ int rt2x00lib_probe_dev(struct rt2x00_de /* * Initialize configuration work. */ - rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib"); - if (!rt2x00dev->workqueue) - goto exit; - INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled, rt2x00dev); INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled, rt2x00dev); @@ -1200,15 +1196,6 @@ void rt2x00lib_remove_dev(struct rt2x00_ rt2x00leds_unregister(rt2x00dev); /* - * Stop all queued work. Note that most tasks will already be halted - * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize(). - */ - if (rt2x00dev->workqueue) { - flush_workqueue(rt2x00dev->workqueue); - destroy_workqueue(rt2x00dev->workqueue); - } - - /* * Free ieee80211_hw memory. */ rt2x00lib_remove_hw(rt2x00dev); --- linux-2.6.18.noarch/drivers/net/wireless/rt2x00/rt2x00mac.c.orig 2009-06-24 07:50:07.000000000 -0400 +++ linux-2.6.18.noarch/drivers/net/wireless/rt2x00/rt2x00mac.c 2009-06-24 08:10:52.000000000 -0400 @@ -428,7 +428,7 @@ void rt2x00mac_configure_filter(struct i if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); else - queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work); + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); } EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); @@ -509,7 +509,7 @@ void rt2x00mac_bss_info_changed(struct i memcpy(&intf->conf, bss_conf, sizeof(*bss_conf)); if (delayed) { intf->delayed_flags |= delayed; - queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work); + schedule_work(&rt2x00dev->intf_work); } spin_unlock(&intf->lock); }