aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2x00dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 9ea677320daa..cc4fee105ed6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -74,7 +74,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
74 74
75 rt2x00lib_reset_link_tuner(rt2x00dev); 75 rt2x00lib_reset_link_tuner(rt2x00dev);
76 76
77 queue_delayed_work(rt2x00dev->hw->workqueue, 77 queue_delayed_work(rt2x00dev->workqueue,
78 &rt2x00dev->link.work, LINK_TUNE_INTERVAL); 78 &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
79} 79}
80 80
@@ -138,14 +138,6 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
138 return; 138 return;
139 139
140 /* 140 /*
141 * Stop all scheduled work.
142 */
143 if (work_pending(&rt2x00dev->intf_work))
144 cancel_work_sync(&rt2x00dev->intf_work);
145 if (work_pending(&rt2x00dev->filter_work))
146 cancel_work_sync(&rt2x00dev->filter_work);
147
148 /*
149 * Stop the TX queues. 141 * Stop the TX queues.
150 */ 142 */
151 ieee80211_stop_queues(rt2x00dev->hw); 143 ieee80211_stop_queues(rt2x00dev->hw);
@@ -400,8 +392,8 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
400 * Increase tuner counter, and reschedule the next link tuner run. 392 * Increase tuner counter, and reschedule the next link tuner run.
401 */ 393 */
402 rt2x00dev->link.count++; 394 rt2x00dev->link.count++;
403 queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, 395 queue_delayed_work(rt2x00dev->workqueue,
404 LINK_TUNE_INTERVAL); 396 &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
405} 397}
406 398
407static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) 399static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
@@ -434,6 +426,15 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
434 426
435 spin_unlock(&intf->lock); 427 spin_unlock(&intf->lock);
436 428
429 /*
430 * It is possible the radio was disabled while the work had been
431 * scheduled. If that happens we should return here immediately,
432 * note that in the spinlock protected area above the delayed_flags
433 * have been cleared correctly.
434 */
435 if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
436 return;
437
437 if (delayed_flags & DELAYED_UPDATE_BEACON) { 438 if (delayed_flags & DELAYED_UPDATE_BEACON) {
438 skb = ieee80211_beacon_get(rt2x00dev->hw, vif); 439 skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
439 if (skb && 440 if (skb &&
@@ -442,7 +443,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
442 } 443 }
443 444
444 if (delayed_flags & DELAYED_CONFIG_ERP) 445 if (delayed_flags & DELAYED_CONFIG_ERP)
445 rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf); 446 rt2x00lib_config_erp(rt2x00dev, intf, &conf);
446 447
447 if (delayed_flags & DELAYED_LED_ASSOC) 448 if (delayed_flags & DELAYED_LED_ASSOC)
448 rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); 449 rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
@@ -488,7 +489,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
488 rt2x00lib_beacondone_iter, 489 rt2x00lib_beacondone_iter,
489 rt2x00dev); 490 rt2x00dev);
490 491
491 queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); 492 queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
492} 493}
493EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); 494EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
494 495
@@ -1003,6 +1004,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
1003 /* 1004 /*
1004 * Initialize configuration work. 1005 * Initialize configuration work.
1005 */ 1006 */
1007 rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib");
1008 if (!rt2x00dev->workqueue)
1009 goto exit;
1010
1006 INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); 1011 INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
1007 INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); 1012 INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
1008 INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); 1013 INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
@@ -1063,6 +1068,13 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
1063 rt2x00leds_unregister(rt2x00dev); 1068 rt2x00leds_unregister(rt2x00dev);
1064 1069
1065 /* 1070 /*
1071 * Stop all queued work. Note that most tasks will already be halted
1072 * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize().
1073 */
1074 flush_workqueue(rt2x00dev->workqueue);
1075 destroy_workqueue(rt2x00dev->workqueue);
1076
1077 /*
1066 * Free ieee80211_hw memory. 1078 * Free ieee80211_hw memory.
1067 */ 1079 */
1068 rt2x00lib_remove_hw(rt2x00dev); 1080 rt2x00lib_remove_hw(rt2x00dev);