Commit 3506e0c4 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

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: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarMichael 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fa23f5cc
...@@ -724,6 +724,7 @@ struct b43_wldev { ...@@ -724,6 +724,7 @@ struct b43_wldev {
bool short_preamble; /* TRUE, if short preamble is enabled. */ bool short_preamble; /* TRUE, if short preamble is enabled. */
bool short_slot; /* TRUE, if short slot timing is enabled. */ bool short_slot; /* TRUE, if short slot timing is enabled. */
bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool radio_hw_enable; /* saved state of radio hardware enabled state */
bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */
/* PHY/Radio device. */ /* PHY/Radio device. */
struct b43_phy phy; struct b43_phy phy;
......
...@@ -116,7 +116,10 @@ static void b43_unregister_led(struct b43_led *led) ...@@ -116,7 +116,10 @@ static void b43_unregister_led(struct b43_led *led)
{ {
if (!led->dev) if (!led->dev)
return; return;
led_classdev_unregister(&led->led_dev); if (led->dev->suspend_in_progress)
led_classdev_unregister_suspended(&led->led_dev);
else
led_classdev_unregister(&led->led_dev);
b43_led_turn_off(led->dev, led->index, led->activelow); b43_led_turn_off(led->dev, led->index, led->activelow);
led->dev = NULL; led->dev = NULL;
} }
......
...@@ -2555,10 +2555,10 @@ static int b43_rng_read(struct hwrng *rng, u32 * data) ...@@ -2555,10 +2555,10 @@ static int b43_rng_read(struct hwrng *rng, u32 * data)
return (sizeof(u16)); return (sizeof(u16));
} }
static void b43_rng_exit(struct b43_wl *wl) static void b43_rng_exit(struct b43_wl *wl, bool suspended)
{ {
if (wl->rng_initialized) if (wl->rng_initialized)
hwrng_unregister(&wl->rng); __hwrng_unregister(&wl->rng, suspended);
} }
static int b43_rng_init(struct b43_wl *wl) static int b43_rng_init(struct b43_wl *wl)
...@@ -3418,8 +3418,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) ...@@ -3418,8 +3418,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
macctl |= B43_MACCTL_PSM_JMP0; macctl |= B43_MACCTL_PSM_JMP0;
b43_write32(dev, B43_MMIO_MACCTL, macctl); b43_write32(dev, B43_MMIO_MACCTL, macctl);
b43_leds_exit(dev); if (!dev->suspend_in_progress) {
b43_rng_exit(dev->wl); b43_leds_exit(dev);
b43_rng_exit(dev->wl, false);
}
b43_dma_free(dev); b43_dma_free(dev);
b43_chip_exit(dev); b43_chip_exit(dev);
b43_radio_turn_off(dev, 1); b43_radio_turn_off(dev, 1);
...@@ -3535,11 +3537,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev) ...@@ -3535,11 +3537,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
b43_upload_card_macaddress(dev); b43_upload_card_macaddress(dev);
b43_security_init(dev); b43_security_init(dev);
b43_rng_init(wl); if (!dev->suspend_in_progress)
b43_rng_init(wl);
b43_set_status(dev, B43_STAT_INITIALIZED); b43_set_status(dev, B43_STAT_INITIALIZED);
b43_leds_init(dev); if (!dev->suspend_in_progress)
b43_leds_init(dev);
out: out:
return err; return err;
...@@ -4136,6 +4140,7 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state) ...@@ -4136,6 +4140,7 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state)
b43dbg(wl, "Suspending...\n"); b43dbg(wl, "Suspending...\n");
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
wldev->suspend_in_progress = true;
wldev->suspend_init_status = b43_status(wldev); wldev->suspend_init_status = b43_status(wldev);
if (wldev->suspend_init_status >= B43_STAT_STARTED) if (wldev->suspend_init_status >= B43_STAT_STARTED)
b43_wireless_core_stop(wldev); b43_wireless_core_stop(wldev);
...@@ -4167,15 +4172,17 @@ static int b43_resume(struct ssb_device *dev) ...@@ -4167,15 +4172,17 @@ static int b43_resume(struct ssb_device *dev)
if (wldev->suspend_init_status >= B43_STAT_STARTED) { if (wldev->suspend_init_status >= B43_STAT_STARTED) {
err = b43_wireless_core_start(wldev); err = b43_wireless_core_start(wldev);
if (err) { if (err) {
b43_leds_exit(wldev);
b43_rng_exit(wldev->wl, true);
b43_wireless_core_exit(wldev); b43_wireless_core_exit(wldev);
b43err(wl, "Resume failed at core start\n"); b43err(wl, "Resume failed at core start\n");
goto out; goto out;
} }
} }
mutex_unlock(&wl->mutex);
b43dbg(wl, "Device resumed.\n"); b43dbg(wl, "Device resumed.\n");
out: out:
wldev->suspend_in_progress = false;
mutex_unlock(&wl->mutex);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment