diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 38 |
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 | ||
407 | static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) | 399 | static 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 | } |
493 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); | 494 | EXPORT_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); |