diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-05-22 11:06:36 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-04 15:57:09 -0400 |
commit | 48e6c51bd326ce9faf07fbdf84d361c9755b7035 (patch) | |
tree | 7c578fc9984a197dd8f8a95fe5adbe4cb558fba9 | |
parent | 7dccf1f4e1696c79bff064c3770867cc53cbc71c (diff) |
b43legacy: Fix controller restart crash
This fixes a kernel crash on rmmod, in the case where the controller
was restarted before doing the rmmod.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/b43legacy/main.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 14a5eea2573e..204077c13870 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c | |||
@@ -3039,7 +3039,6 @@ static void b43legacy_set_pretbtt(struct b43legacy_wldev *dev) | |||
3039 | /* Locking: wl->mutex */ | 3039 | /* Locking: wl->mutex */ |
3040 | static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) | 3040 | static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) |
3041 | { | 3041 | { |
3042 | struct b43legacy_wl *wl = dev->wl; | ||
3043 | struct b43legacy_phy *phy = &dev->phy; | 3042 | struct b43legacy_phy *phy = &dev->phy; |
3044 | u32 macctl; | 3043 | u32 macctl; |
3045 | 3044 | ||
@@ -3054,12 +3053,6 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) | |||
3054 | macctl |= B43legacy_MACCTL_PSM_JMP0; | 3053 | macctl |= B43legacy_MACCTL_PSM_JMP0; |
3055 | b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl); | 3054 | b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl); |
3056 | 3055 | ||
3057 | mutex_unlock(&wl->mutex); | ||
3058 | /* Must unlock as it would otherwise deadlock. No races here. | ||
3059 | * Cancel possibly pending workqueues. */ | ||
3060 | cancel_work_sync(&dev->restart_work); | ||
3061 | mutex_lock(&wl->mutex); | ||
3062 | |||
3063 | b43legacy_leds_exit(dev); | 3056 | b43legacy_leds_exit(dev); |
3064 | b43legacy_rng_exit(dev->wl); | 3057 | b43legacy_rng_exit(dev->wl); |
3065 | b43legacy_pio_free(dev); | 3058 | b43legacy_pio_free(dev); |
@@ -3486,6 +3479,8 @@ static void b43legacy_chip_reset(struct work_struct *work) | |||
3486 | } | 3479 | } |
3487 | } | 3480 | } |
3488 | out: | 3481 | out: |
3482 | if (err) | ||
3483 | wl->current_dev = NULL; /* Failed to init the dev. */ | ||
3489 | mutex_unlock(&wl->mutex); | 3484 | mutex_unlock(&wl->mutex); |
3490 | if (err) | 3485 | if (err) |
3491 | b43legacyerr(wl, "Controller restart FAILED\n"); | 3486 | b43legacyerr(wl, "Controller restart FAILED\n"); |
@@ -3618,9 +3613,11 @@ static void b43legacy_one_core_detach(struct ssb_device *dev) | |||
3618 | struct b43legacy_wldev *wldev; | 3613 | struct b43legacy_wldev *wldev; |
3619 | struct b43legacy_wl *wl; | 3614 | struct b43legacy_wl *wl; |
3620 | 3615 | ||
3616 | /* Do not cancel ieee80211-workqueue based work here. | ||
3617 | * See comment in b43legacy_remove(). */ | ||
3618 | |||
3621 | wldev = ssb_get_drvdata(dev); | 3619 | wldev = ssb_get_drvdata(dev); |
3622 | wl = wldev->wl; | 3620 | wl = wldev->wl; |
3623 | cancel_work_sync(&wldev->restart_work); | ||
3624 | b43legacy_debugfs_remove_device(wldev); | 3621 | b43legacy_debugfs_remove_device(wldev); |
3625 | b43legacy_wireless_core_detach(wldev); | 3622 | b43legacy_wireless_core_detach(wldev); |
3626 | list_del(&wldev->list); | 3623 | list_del(&wldev->list); |
@@ -3789,6 +3786,10 @@ static void b43legacy_remove(struct ssb_device *dev) | |||
3789 | struct b43legacy_wl *wl = ssb_get_devtypedata(dev); | 3786 | struct b43legacy_wl *wl = ssb_get_devtypedata(dev); |
3790 | struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); | 3787 | struct b43legacy_wldev *wldev = ssb_get_drvdata(dev); |
3791 | 3788 | ||
3789 | /* We must cancel any work here before unregistering from ieee80211, | ||
3790 | * as the ieee80211 unreg will destroy the workqueue. */ | ||
3791 | cancel_work_sync(&wldev->restart_work); | ||
3792 | |||
3792 | B43legacy_WARN_ON(!wl); | 3793 | B43legacy_WARN_ON(!wl); |
3793 | if (wl->current_dev == wldev) | 3794 | if (wl->current_dev == wldev) |
3794 | ieee80211_unregister_hw(wl->hw); | 3795 | ieee80211_unregister_hw(wl->hw); |