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>
This commit is contained in:
parent
fa23f5cce8
commit
3506e0c49a
@ -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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user