diff options
author | Dan Williams <dcbw@redhat.com> | 2008-09-08 16:34:40 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-09-11 15:53:38 -0400 |
commit | 71b35f3abeb8f7f7e0afd7573424540cc5aae2d5 (patch) | |
tree | 08c190a3d56d5ca9a4347b797035db63f89592ed /drivers | |
parent | 771fd565195727d12f0b75d918b9fcb9f33a5476 (diff) |
libertas: clear current command on card removal
If certain commands were in-flight when the card was pulled or the
driver rmmod-ed, cleanup would block on the work queue stopping, but the
work queue was in turn blocked on the current command being canceled,
which didn't happen. Fix that.
Signed-off-by: Dan Williams <dcbw@redhat.com>
Cc: stable <stable@kernel.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2436634b6b7e..73dc8c72402a 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -1205,7 +1205,13 @@ void lbs_remove_card(struct lbs_private *priv) | |||
1205 | cancel_delayed_work_sync(&priv->scan_work); | 1205 | cancel_delayed_work_sync(&priv->scan_work); |
1206 | cancel_delayed_work_sync(&priv->assoc_work); | 1206 | cancel_delayed_work_sync(&priv->assoc_work); |
1207 | cancel_work_sync(&priv->mcast_work); | 1207 | cancel_work_sync(&priv->mcast_work); |
1208 | |||
1209 | /* worker thread destruction blocks on the in-flight command which | ||
1210 | * should have been cleared already in lbs_stop_card(). | ||
1211 | */ | ||
1212 | lbs_deb_main("destroying worker thread\n"); | ||
1208 | destroy_workqueue(priv->work_thread); | 1213 | destroy_workqueue(priv->work_thread); |
1214 | lbs_deb_main("done destroying worker thread\n"); | ||
1209 | 1215 | ||
1210 | if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { | 1216 | if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { |
1211 | priv->psmode = LBS802_11POWERMODECAM; | 1217 | priv->psmode = LBS802_11POWERMODECAM; |
@@ -1323,14 +1329,26 @@ void lbs_stop_card(struct lbs_private *priv) | |||
1323 | device_remove_file(&dev->dev, &dev_attr_lbs_rtap); | 1329 | device_remove_file(&dev->dev, &dev_attr_lbs_rtap); |
1324 | } | 1330 | } |
1325 | 1331 | ||
1326 | /* Flush pending command nodes */ | 1332 | /* Delete the timeout of the currently processing command */ |
1327 | del_timer_sync(&priv->command_timer); | 1333 | del_timer_sync(&priv->command_timer); |
1334 | |||
1335 | /* Flush pending command nodes */ | ||
1328 | spin_lock_irqsave(&priv->driver_lock, flags); | 1336 | spin_lock_irqsave(&priv->driver_lock, flags); |
1337 | lbs_deb_main("clearing pending commands\n"); | ||
1329 | list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { | 1338 | list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { |
1330 | cmdnode->result = -ENOENT; | 1339 | cmdnode->result = -ENOENT; |
1331 | cmdnode->cmdwaitqwoken = 1; | 1340 | cmdnode->cmdwaitqwoken = 1; |
1332 | wake_up_interruptible(&cmdnode->cmdwait_q); | 1341 | wake_up_interruptible(&cmdnode->cmdwait_q); |
1333 | } | 1342 | } |
1343 | |||
1344 | /* Flush the command the card is currently processing */ | ||
1345 | if (priv->cur_cmd) { | ||
1346 | lbs_deb_main("clearing current command\n"); | ||
1347 | priv->cur_cmd->result = -ENOENT; | ||
1348 | priv->cur_cmd->cmdwaitqwoken = 1; | ||
1349 | wake_up_interruptible(&priv->cur_cmd->cmdwait_q); | ||
1350 | } | ||
1351 | lbs_deb_main("done clearing commands\n"); | ||
1334 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 1352 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
1335 | 1353 | ||
1336 | unregister_netdev(dev); | 1354 | unregister_netdev(dev); |