aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-02-05 01:30:15 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:23 -0500
commit3506e0c49a5ceba72c0405d1a470184c2d6705f7 (patch)
tree960333db4879feb5a0615d96687909a186a83ff3 /drivers/net/wireless/b43
parentfa23f5cce8cda2095013afc837ccf74b352f9f7b (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.h1
-rw-r--r--drivers/net/wireless/b43/leds.c5
-rw-r--r--drivers/net/wireless/b43/main.c25
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
2558static void b43_rng_exit(struct b43_wl *wl) 2558static 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
2564static int b43_rng_init(struct b43_wl *wl) 2564static 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);
3543out: 3547out:
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