diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2008-02-05 01:30:15 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 12:44:23 -0500 |
commit | 3506e0c49a5ceba72c0405d1a470184c2d6705f7 (patch) | |
tree | 960333db4879feb5a0615d96687909a186a83ff3 /drivers/net/wireless/b43 | |
parent | fa23f5cce8cda2095013afc837ccf74b352f9f7b (diff) |
b43: avoid unregistering device objects during suspend
Modify the b43 driver to avoid deadlocking suspend and resume, which happens
as a result of attempting to unregister device objects locked by the PM core
during suspend/resume cycles. Also, make it use a suspend-safe method of
unregistering device object in the resume error path.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Michael Buesch <mb@bu3sch.de>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: "John W. Linville" <linville@tuxdriver.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Len Brown <lenb@kernel.org>
Cc: Greg KH <greg@kroah.com>
Cc: Kay Sievers <kay.sievers@vrfy.org>
Cc: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/net/wireless/b43')
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/b43/leds.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 25 |
3 files changed, 21 insertions, 10 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 32a24f5c4fa6..08a011f0834a 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -724,6 +724,7 @@ struct b43_wldev { | |||
724 | bool short_preamble; /* TRUE, if short preamble is enabled. */ | 724 | bool short_preamble; /* TRUE, if short preamble is enabled. */ |
725 | bool short_slot; /* TRUE, if short slot timing is enabled. */ | 725 | bool short_slot; /* TRUE, if short slot timing is enabled. */ |
726 | bool radio_hw_enable; /* saved state of radio hardware enabled state */ | 726 | bool radio_hw_enable; /* saved state of radio hardware enabled state */ |
727 | bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ | ||
727 | 728 | ||
728 | /* PHY/Radio device. */ | 729 | /* PHY/Radio device. */ |
729 | struct b43_phy phy; | 730 | struct b43_phy phy; |
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 4b590d8c65ff..0908335892db 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c | |||
@@ -116,7 +116,10 @@ static void b43_unregister_led(struct b43_led *led) | |||
116 | { | 116 | { |
117 | if (!led->dev) | 117 | if (!led->dev) |
118 | return; | 118 | return; |
119 | led_classdev_unregister(&led->led_dev); | 119 | if (led->dev->suspend_in_progress) |
120 | led_classdev_unregister_suspended(&led->led_dev); | ||
121 | else | ||
122 | led_classdev_unregister(&led->led_dev); | ||
120 | b43_led_turn_off(led->dev, led->index, led->activelow); | 123 | b43_led_turn_off(led->dev, led->index, led->activelow); |
121 | led->dev = NULL; | 124 | led->dev = NULL; |
122 | } | 125 | } |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6faa57a2242e..ef65c41af00f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -2555,10 +2555,10 @@ static int b43_rng_read(struct hwrng *rng, u32 * data) | |||
2555 | return (sizeof(u16)); | 2555 | return (sizeof(u16)); |
2556 | } | 2556 | } |
2557 | 2557 | ||
2558 | static void b43_rng_exit(struct b43_wl *wl) | 2558 | static void b43_rng_exit(struct b43_wl *wl, bool suspended) |
2559 | { | 2559 | { |
2560 | if (wl->rng_initialized) | 2560 | if (wl->rng_initialized) |
2561 | hwrng_unregister(&wl->rng); | 2561 | __hwrng_unregister(&wl->rng, suspended); |
2562 | } | 2562 | } |
2563 | 2563 | ||
2564 | static int b43_rng_init(struct b43_wl *wl) | 2564 | static int b43_rng_init(struct b43_wl *wl) |
@@ -3418,8 +3418,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) | |||
3418 | macctl |= B43_MACCTL_PSM_JMP0; | 3418 | macctl |= B43_MACCTL_PSM_JMP0; |
3419 | b43_write32(dev, B43_MMIO_MACCTL, macctl); | 3419 | b43_write32(dev, B43_MMIO_MACCTL, macctl); |
3420 | 3420 | ||
3421 | b43_leds_exit(dev); | 3421 | if (!dev->suspend_in_progress) { |
3422 | b43_rng_exit(dev->wl); | 3422 | b43_leds_exit(dev); |
3423 | b43_rng_exit(dev->wl, false); | ||
3424 | } | ||
3423 | b43_dma_free(dev); | 3425 | b43_dma_free(dev); |
3424 | b43_chip_exit(dev); | 3426 | b43_chip_exit(dev); |
3425 | b43_radio_turn_off(dev, 1); | 3427 | b43_radio_turn_off(dev, 1); |
@@ -3535,11 +3537,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev) | |||
3535 | ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ | 3537 | ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ |
3536 | b43_upload_card_macaddress(dev); | 3538 | b43_upload_card_macaddress(dev); |
3537 | b43_security_init(dev); | 3539 | b43_security_init(dev); |
3538 | b43_rng_init(wl); | 3540 | if (!dev->suspend_in_progress) |
3541 | b43_rng_init(wl); | ||
3539 | 3542 | ||
3540 | b43_set_status(dev, B43_STAT_INITIALIZED); | 3543 | b43_set_status(dev, B43_STAT_INITIALIZED); |
3541 | 3544 | ||
3542 | b43_leds_init(dev); | 3545 | if (!dev->suspend_in_progress) |
3546 | b43_leds_init(dev); | ||
3543 | out: | 3547 | out: |
3544 | return err; | 3548 | return err; |
3545 | 3549 | ||
@@ -4136,6 +4140,7 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state) | |||
4136 | b43dbg(wl, "Suspending...\n"); | 4140 | b43dbg(wl, "Suspending...\n"); |
4137 | 4141 | ||
4138 | mutex_lock(&wl->mutex); | 4142 | mutex_lock(&wl->mutex); |
4143 | wldev->suspend_in_progress = true; | ||
4139 | wldev->suspend_init_status = b43_status(wldev); | 4144 | wldev->suspend_init_status = b43_status(wldev); |
4140 | if (wldev->suspend_init_status >= B43_STAT_STARTED) | 4145 | if (wldev->suspend_init_status >= B43_STAT_STARTED) |
4141 | b43_wireless_core_stop(wldev); | 4146 | b43_wireless_core_stop(wldev); |
@@ -4167,15 +4172,17 @@ static int b43_resume(struct ssb_device *dev) | |||
4167 | if (wldev->suspend_init_status >= B43_STAT_STARTED) { | 4172 | if (wldev->suspend_init_status >= B43_STAT_STARTED) { |
4168 | err = b43_wireless_core_start(wldev); | 4173 | err = b43_wireless_core_start(wldev); |
4169 | if (err) { | 4174 | if (err) { |
4175 | b43_leds_exit(wldev); | ||
4176 | b43_rng_exit(wldev->wl, true); | ||
4170 | b43_wireless_core_exit(wldev); | 4177 | b43_wireless_core_exit(wldev); |
4171 | b43err(wl, "Resume failed at core start\n"); | 4178 | b43err(wl, "Resume failed at core start\n"); |
4172 | goto out; | 4179 | goto out; |
4173 | } | 4180 | } |
4174 | } | 4181 | } |
4175 | mutex_unlock(&wl->mutex); | ||
4176 | |||
4177 | b43dbg(wl, "Device resumed.\n"); | 4182 | b43dbg(wl, "Device resumed.\n"); |
4178 | out: | 4183 | out: |
4184 | wldev->suspend_in_progress = false; | ||
4185 | mutex_unlock(&wl->mutex); | ||
4179 | return err; | 4186 | return err; |
4180 | } | 4187 | } |
4181 | 4188 | ||