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 2673d568bca..c997d4f28ab 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -75,7 +75,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) | |||
75 | 75 | ||
76 | rt2x00lib_reset_link_tuner(rt2x00dev); | 76 | rt2x00lib_reset_link_tuner(rt2x00dev); |
77 | 77 | ||
78 | queue_delayed_work(rt2x00dev->hw->workqueue, | 78 | queue_delayed_work(rt2x00dev->workqueue, |
79 | &rt2x00dev->link.work, LINK_TUNE_INTERVAL); | 79 | &rt2x00dev->link.work, LINK_TUNE_INTERVAL); |
80 | } | 80 | } |
81 | 81 | ||
@@ -137,14 +137,6 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) | |||
137 | return; | 137 | return; |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * Stop all scheduled work. | ||
141 | */ | ||
142 | if (work_pending(&rt2x00dev->intf_work)) | ||
143 | cancel_work_sync(&rt2x00dev->intf_work); | ||
144 | if (work_pending(&rt2x00dev->filter_work)) | ||
145 | cancel_work_sync(&rt2x00dev->filter_work); | ||
146 | |||
147 | /* | ||
148 | * Stop the TX queues. | 140 | * Stop the TX queues. |
149 | */ | 141 | */ |
150 | ieee80211_stop_queues(rt2x00dev->hw); | 142 | ieee80211_stop_queues(rt2x00dev->hw); |
@@ -398,8 +390,8 @@ static void rt2x00lib_link_tuner(struct work_struct *work) | |||
398 | * Increase tuner counter, and reschedule the next link tuner run. | 390 | * Increase tuner counter, and reschedule the next link tuner run. |
399 | */ | 391 | */ |
400 | rt2x00dev->link.count++; | 392 | rt2x00dev->link.count++; |
401 | queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, | 393 | queue_delayed_work(rt2x00dev->workqueue, |
402 | LINK_TUNE_INTERVAL); | 394 | &rt2x00dev->link.work, LINK_TUNE_INTERVAL); |
403 | } | 395 | } |
404 | 396 | ||
405 | static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) | 397 | static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) |
@@ -433,6 +425,15 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, | |||
433 | 425 | ||
434 | spin_unlock(&intf->lock); | 426 | spin_unlock(&intf->lock); |
435 | 427 | ||
428 | /* | ||
429 | * It is possible the radio was disabled while the work had been | ||
430 | * scheduled. If that happens we should return here immediately, | ||
431 | * note that in the spinlock protected area above the delayed_flags | ||
432 | * have been cleared correctly. | ||
433 | */ | ||
434 | if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
435 | return; | ||
436 | |||
436 | if (delayed_flags & DELAYED_UPDATE_BEACON) { | 437 | if (delayed_flags & DELAYED_UPDATE_BEACON) { |
437 | skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control); | 438 | skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control); |
438 | if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, | 439 | if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, |
@@ -441,7 +442,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, | |||
441 | } | 442 | } |
442 | 443 | ||
443 | if (delayed_flags & DELAYED_CONFIG_ERP) | 444 | if (delayed_flags & DELAYED_CONFIG_ERP) |
444 | rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf); | 445 | rt2x00lib_config_erp(rt2x00dev, intf, &conf); |
445 | 446 | ||
446 | if (delayed_flags & DELAYED_LED_ASSOC) | 447 | if (delayed_flags & DELAYED_LED_ASSOC) |
447 | rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); | 448 | rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); |
@@ -487,7 +488,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) | |||
487 | rt2x00lib_beacondone_iter, | 488 | rt2x00lib_beacondone_iter, |
488 | rt2x00dev); | 489 | rt2x00dev); |
489 | 490 | ||
490 | queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); | 491 | queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work); |
491 | } | 492 | } |
492 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); | 493 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); |
493 | 494 | ||
@@ -1130,6 +1131,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1130 | /* | 1131 | /* |
1131 | * Initialize configuration work. | 1132 | * Initialize configuration work. |
1132 | */ | 1133 | */ |
1134 | rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib"); | ||
1135 | if (!rt2x00dev->workqueue) | ||
1136 | goto exit; | ||
1137 | |||
1133 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); | 1138 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); |
1134 | INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); | 1139 | INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); |
1135 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); | 1140 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); |
@@ -1190,6 +1195,13 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) | |||
1190 | rt2x00leds_unregister(rt2x00dev); | 1195 | rt2x00leds_unregister(rt2x00dev); |
1191 | 1196 | ||
1192 | /* | 1197 | /* |
1198 | * Stop all queued work. Note that most tasks will already be halted | ||
1199 | * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize(). | ||
1200 | */ | ||
1201 | flush_workqueue(rt2x00dev->workqueue); | ||
1202 | destroy_workqueue(rt2x00dev->workqueue); | ||
1203 | |||
1204 | /* | ||
1193 | * Free ieee80211_hw memory. | 1205 | * Free ieee80211_hw memory. |
1194 | */ | 1206 | */ |
1195 | rt2x00lib_remove_hw(rt2x00dev); | 1207 | rt2x00lib_remove_hw(rt2x00dev); |