Re: b43_suspend problem
On Tuesday 22 January 2008 00:36:45 Rafael J. Wysocki wrote: I still don't like this function wrapping. I'm pretty sure the additional parameter to the function is not needed. We can check dev-suspend_in_progress to find out if we are in a up/down or in a suspend/resume cycle. You're right, I overlooked that. [snip] The patch looks good. Did you try it on b43 hardware? -- Greetings Michael. ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
Re: b43_suspend problem
On Monday 21 January 2008, Rafael J. Wysocki wrote: I modified the patch to implement something like this. This still is one big patch against everything what's necessary. [BTW, in the current version of the code, b43_resume() may leave wl-mutex locked in the error paths, which also is fixed by the patch.] Whoopsy, thanks for catching this. Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/main.c +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c @@ -2470,10 +2470,10 @@ static int b43_rng_read(struct hwrng *rn 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) - hwrng_unregister(wl-rng); + __hwrng_unregister(wl-rng, suspended); } static int b43_rng_init(struct b43_wl *wl) @@ -3298,8 +3298,10 @@ static void b43_wireless_core_exit(struc return; b43_set_status(dev, B43_STAT_UNINIT); - b43_leds_exit(dev); - b43_rng_exit(dev-wl); + if (!dev-suspend_in_progress) { + b43_leds_exit(dev); + b43_rng_exit(dev-wl, false); + } b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); @@ -3420,11 +3422,13 @@ static int b43_wireless_core_init(struct memset(wl-mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(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_leds_init(dev); + if (!dev-suspend_in_progress) + b43_leds_init(dev); out: return err; @@ -4024,6 +4028,7 @@ static int b43_suspend(struct ssb_device b43dbg(wl, Suspending...\n); mutex_lock(wl-mutex); + wldev-suspend_in_progress = true; wldev-suspend_init_status = b43_status(wldev); if (wldev-suspend_init_status = B43_STAT_STARTED) b43_wireless_core_stop(wldev); @@ -4055,15 +4060,17 @@ static int b43_resume(struct ssb_device if (wldev-suspend_init_status = B43_STAT_STARTED) { err = b43_wireless_core_start(wldev); if (err) { + b43_leds_resume_exit(wldev); + b43_rng_exit(wldev-wl, true); b43_wireless_core_exit(wldev); b43err(wl, Resume failed at core start\n); goto out; } } - mutex_unlock(wl-mutex); - b43dbg(wl, Device resumed.\n); - out: + out: + wldev-suspend_in_progress = false; + mutex_unlock(wl-mutex); return err; } This part looks OK. Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.h === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/leds.h +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.h @@ -43,8 +43,15 @@ enum b43_led_behaviour { }; void b43_leds_init(struct b43_wldev *dev); -void b43_leds_exit(struct b43_wldev *dev); - +void __b43_leds_exit(struct b43_wldev *dev, bool suspended); +static inline void b43_leds_exit(struct b43_wldev *dev) +{ + __b43_leds_exit(dev, false); +} +static inline void b43_leds_resume_exit(struct b43_wldev *dev) +{ + __b43_leds_exit(dev, true); +} I still don't like this function wrapping. I'm pretty sure the additional parameter to the function is not needed. We can check dev-suspend_in_progress to find out if we are in a up/down or in a suspend/resume cycle. -static void b43_unregister_led(struct b43_led *led) +static void b43_unregister_led(struct b43_led *led, bool suspended) { if (!led-dev) return; - led_classdev_unregister(led-led_dev); + if (suspended) You can check led-dev-suspend_in_progress here. + led_classdev_unregister_suspended(led-led_dev); + else + led_classdev_unregister(led-led_dev); b43_led_turn_off(led-dev, led-index, led-activelow); led-dev = NULL; } @@ -230,10 +233,10 @@ void b43_leds_init(struct b43_wldev *dev } } -void b43_leds_exit(struct b43_wldev *dev) +void __b43_leds_exit(struct b43_wldev *dev, bool suspended) { - b43_unregister_led(dev-led_tx); - b43_unregister_led(dev-led_rx); - b43_unregister_led(dev-led_assoc); - b43_unregister_led(dev-led_radio); + b43_unregister_led(dev-led_tx, suspended); + b43_unregister_led(dev-led_rx, suspended); + b43_unregister_led(dev-led_assoc, suspended); + b43_unregister_led(dev-led_radio, suspended); } Don't need this hunk. Check led-dev-suspend_in_progress in b43_unregister_led. #endif /* __KERNEL__ */ #endif /* LINUX_HWRANDOM_H_ */ Index:
Re: b43_suspend problem
On Monday, 21 of January 2008, Michael Buesch wrote: On Monday 21 January 2008, Rafael J. Wysocki wrote: [--snip--] Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.h === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/leds.h +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.h @@ -43,8 +43,15 @@ enum b43_led_behaviour { }; void b43_leds_init(struct b43_wldev *dev); -void b43_leds_exit(struct b43_wldev *dev); - +void __b43_leds_exit(struct b43_wldev *dev, bool suspended); +static inline void b43_leds_exit(struct b43_wldev *dev) +{ + __b43_leds_exit(dev, false); +} +static inline void b43_leds_resume_exit(struct b43_wldev *dev) +{ + __b43_leds_exit(dev, true); +} I still don't like this function wrapping. I'm pretty sure the additional parameter to the function is not needed. We can check dev-suspend_in_progress to find out if we are in a up/down or in a suspend/resume cycle. You're right, I overlooked that. -static void b43_unregister_led(struct b43_led *led) +static void b43_unregister_led(struct b43_led *led, bool suspended) { if (!led-dev) return; - led_classdev_unregister(led-led_dev); + if (suspended) You can check led-dev-suspend_in_progress here. + led_classdev_unregister_suspended(led-led_dev); + else + led_classdev_unregister(led-led_dev); b43_led_turn_off(led-dev, led-index, led-activelow); led-dev = NULL; } @@ -230,10 +233,10 @@ void b43_leds_init(struct b43_wldev *dev } } -void b43_leds_exit(struct b43_wldev *dev) +void __b43_leds_exit(struct b43_wldev *dev, bool suspended) { - b43_unregister_led(dev-led_tx); - b43_unregister_led(dev-led_rx); - b43_unregister_led(dev-led_assoc); - b43_unregister_led(dev-led_radio); + b43_unregister_led(dev-led_tx, suspended); + b43_unregister_led(dev-led_rx, suspended); + b43_unregister_led(dev-led_assoc, suspended); + b43_unregister_led(dev-led_radio, suspended); } Don't need this hunk. Check led-dev-suspend_in_progress in b43_unregister_led. #endif /* __KERNEL__ */ #endif /* LINUX_HWRANDOM_H_ */ Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/b43.h === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/b43.h +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/b43.h @@ -706,6 +706,7 @@ struct b43_wldev { bool short_preamble;/* TRUE, if short preamble is enabled. */ bool short_slot;/* TRUE, if short slot timing is enabled. */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ + bool suspend_in_progress; Please add a comment like: /* TRUE, if we are in a suspend/resume cycle */ Sure, I just didn't know what to write in the comment. :-) Revised patch below, please have a look. Thanks, Rafael --- drivers/base/power/main.c |1 + drivers/base/power/power.h |1 - drivers/char/hw_random/core.c | 10 +- drivers/char/misc.c | 13 + drivers/leds/led-class.c| 13 + drivers/net/wireless/b43/b43.h |1 + drivers/net/wireless/b43/leds.c |5 - drivers/net/wireless/b43/main.c | 25 - include/linux/device.h |6 ++ include/linux/hw_random.h | 10 +- include/linux/leds.h| 10 +- include/linux/miscdevice.h | 10 +- 12 files changed, 78 insertions(+), 27 deletions(-) Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/main.c +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c @@ -2470,10 +2470,10 @@ static int b43_rng_read(struct hwrng *rn 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) - hwrng_unregister(wl-rng); + __hwrng_unregister(wl-rng, suspended); } static int b43_rng_init(struct b43_wl *wl) @@ -3298,8 +3298,10 @@ static void b43_wireless_core_exit(struc return; b43_set_status(dev, B43_STAT_UNINIT); - b43_leds_exit(dev); - b43_rng_exit(dev-wl); + if (!dev-suspend_in_progress) { + b43_leds_exit(dev); + b43_rng_exit(dev-wl, false); + } b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); @@ -3420,11 +3422,13 @@ static int b43_wireless_core_init(struct memset(wl-mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); b43_security_init(dev); - b43_rng_init(wl); + if (!dev-suspend_in_progress) + b43_rng_init(wl);
Re: b43_suspend problem
On Sunday, 20 of January 2008, Michael Buesch wrote: On Sunday 20 January 2008, Rafael J. Wysocki wrote: On Sunday, 13 of January 2008, Alan Stern wrote: On Sun, 13 Jan 2008, Michael Buesch wrote: Besides, if you're going to register the device right back again during the subsequent resume, then why go to the trouble of unregistering it during suspend? Why not just leave it registered the whole time and avoid all the complication (and excess meaningless uevents)? Well, because not doing it complicates code :) Currently suspend/resume calls the same code as init/exit. The b43 init/exit code is really complicated, compared to other drivers, due to dozens of hardware versions. So I just avoided having yet other codepaths for suspend/resume. But I will add a flag to the device structure that's used to avoid unregistering stuff. Instead of adding an extra flag you should refactor the code. Have a common enable subroutine that can be called for both init and resume, and a common disable subroutine that can be called for both exit and suspend. Then the method routines themselves will contain only the portions unique to their particular functions, making them shorter and simpler. Well, it doesn't seem to be that easy. I tried to fix the issue myself and finally obtained the appended, apparently working, patch (against 2.6.24-rc8-mm1). Well, it should have been a series of patches against multiple subsystems, but I thought it would be instructive to put everything needed into one bigger patch for starters. Greetings, Rafael --- drivers/base/power/main.c |1 drivers/base/power/power.h |1 drivers/char/hw_random/core.c | 10 - drivers/char/misc.c | 13 drivers/leds/led-class.c| 13 drivers/net/wireless/b43/leds.c | 17 +-- drivers/net/wireless/b43/leds.h | 14 +++-- drivers/net/wireless/b43/main.c | 43 +--- include/linux/device.h |6 + include/linux/hw_random.h | 10 - include/linux/leds.h| 10 - include/linux/miscdevice.h | 10 - 12 files changed, 111 insertions(+), 37 deletions(-) Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/main.c +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c @@ -2470,10 +2470,15 @@ static int b43_rng_read(struct hwrng *rn 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) - hwrng_unregister(wl-rng); + __hwrng_unregister(wl-rng, suspended); +} + +static void b43_rng_exit(struct b43_wl *wl) +{ + __b43_rng_exit(wl, false); } static int b43_rng_init(struct b43_wl *wl) @@ -3289,7 +3294,7 @@ static void b43_set_retry_limits(struct /* Shutdown a wireless core */ /* Locking: wl-mutex */ -static void b43_wireless_core_exit(struct b43_wldev *dev) +static void __b43_wireless_core_exit(struct b43_wldev *dev, bool no_suspend) { struct b43_phy *phy = dev-phy; @@ -3298,8 +3303,10 @@ static void b43_wireless_core_exit(struc return; b43_set_status(dev, B43_STAT_UNINIT); - b43_leds_exit(dev); - b43_rng_exit(dev-wl); + if (no_suspend) { + b43_leds_exit(dev); + b43_rng_exit(dev-wl); + } b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); @@ -3313,8 +3320,13 @@ static void b43_wireless_core_exit(struc ssb_bus_may_powerdown(dev-dev-bus); } +static void b43_wireless_core_exit(struct b43_wldev *dev) +{ + __b43_wireless_core_exit(dev, true); +} Nah, please don't obfuscate the code. Better add a flag to struct b43_wldev and check that in the few places that need different behaviour. I can do that, if you prefer, but that will look worse, IMHO. Thanks, Rafael ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
Re: b43_suspend problem
On Sunday 20 January 2008, Rafael J. Wysocki wrote: Nah, please don't obfuscate the code. Better add a flag to struct b43_wldev and check that in the few places that need different behaviour. I can do that, if you prefer, but that will look worse, IMHO. I'm pretty sure it won't. We had such a flag in the past for firmware. (Fixed that differently now). You simply have do do dev-suspending = 1; at the beginning of suspend/resume and dev-suspending = 0; at the end. The if() checks in the code remain the same. The only thing that this approach won't do it clutter the (already hard to understand) interface up/down API. And that is good. We already have enough special cases for this stuff due to device weirdness. Let's not make it worse. I had a hard time to make a sane API for this (look at bcm43xx to compare to the old crap that doesn't work on lots of devices. ;) ) Thanks for doing this patch. ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
Re: b43_suspend problem
On Sunday, 20 of January 2008, Michael Buesch wrote: On Sunday 20 January 2008, Rafael J. Wysocki wrote: Nah, please don't obfuscate the code. Better add a flag to struct b43_wldev and check that in the few places that need different behaviour. I can do that, if you prefer, but that will look worse, IMHO. I'm pretty sure it won't. We had such a flag in the past for firmware. (Fixed that differently now). You simply have do do dev-suspending = 1; at the beginning of suspend/resume and dev-suspending = 0; at the end. The if() checks in the code remain the same. The only thing that this approach won't do it clutter the (already hard to understand) interface up/down API. And that is good. We already have enough special cases for this stuff due to device weirdness. Let's not make it worse. I had a hard time to make a sane API for this (look at bcm43xx to compare to the old crap that doesn't work on lots of devices. ;) ) I modified the patch to implement something like this. This still is one big patch against everything what's necessary. [BTW, in the current version of the code, b43_resume() may leave wl-mutex locked in the error paths, which also is fixed by the patch.] Please have a look. Thanks for doing this patch. You're welcome. :-) Thanks, Rafael --- drivers/base/power/main.c |1 + drivers/base/power/power.h |1 - drivers/char/hw_random/core.c | 10 +- drivers/char/misc.c | 13 + drivers/leds/led-class.c| 13 + drivers/net/wireless/b43/b43.h |1 + drivers/net/wireless/b43/leds.c | 17 ++--- drivers/net/wireless/b43/leds.h | 14 -- drivers/net/wireless/b43/main.c | 25 - include/linux/device.h |6 ++ include/linux/hw_random.h | 10 +- include/linux/leds.h| 10 +- include/linux/miscdevice.h | 10 +- 13 files changed, 96 insertions(+), 35 deletions(-) Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/main.c +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c @@ -2470,10 +2470,10 @@ static int b43_rng_read(struct hwrng *rn 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) - hwrng_unregister(wl-rng); + __hwrng_unregister(wl-rng, suspended); } static int b43_rng_init(struct b43_wl *wl) @@ -3298,8 +3298,10 @@ static void b43_wireless_core_exit(struc return; b43_set_status(dev, B43_STAT_UNINIT); - b43_leds_exit(dev); - b43_rng_exit(dev-wl); + if (!dev-suspend_in_progress) { + b43_leds_exit(dev); + b43_rng_exit(dev-wl, false); + } b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); @@ -3420,11 +3422,13 @@ static int b43_wireless_core_init(struct memset(wl-mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(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_leds_init(dev); + if (!dev-suspend_in_progress) + b43_leds_init(dev); out: return err; @@ -4024,6 +4028,7 @@ static int b43_suspend(struct ssb_device b43dbg(wl, Suspending...\n); mutex_lock(wl-mutex); + wldev-suspend_in_progress = true; wldev-suspend_init_status = b43_status(wldev); if (wldev-suspend_init_status = B43_STAT_STARTED) b43_wireless_core_stop(wldev); @@ -4055,15 +4060,17 @@ static int b43_resume(struct ssb_device if (wldev-suspend_init_status = B43_STAT_STARTED) { err = b43_wireless_core_start(wldev); if (err) { + b43_leds_resume_exit(wldev); + b43_rng_exit(wldev-wl, true); b43_wireless_core_exit(wldev); b43err(wl, Resume failed at core start\n); goto out; } } - mutex_unlock(wl-mutex); - b43dbg(wl, Device resumed.\n); - out: + out: + wldev-suspend_in_progress = false; + mutex_unlock(wl-mutex); return err; } Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.h === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/leds.h +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.h @@ -43,8 +43,15 @@ enum b43_led_behaviour { }; void b43_leds_init(struct b43_wldev *dev); -void b43_leds_exit(struct b43_wldev *dev); - +void __b43_leds_exit(struct b43_wldev *dev, bool
Re: b43_suspend problem
On Sunday, 13 of January 2008, Alan Stern wrote: On Sun, 13 Jan 2008, Michael Buesch wrote: Besides, if you're going to register the device right back again during the subsequent resume, then why go to the trouble of unregistering it during suspend? Why not just leave it registered the whole time and avoid all the complication (and excess meaningless uevents)? Well, because not doing it complicates code :) Currently suspend/resume calls the same code as init/exit. The b43 init/exit code is really complicated, compared to other drivers, due to dozens of hardware versions. So I just avoided having yet other codepaths for suspend/resume. But I will add a flag to the device structure that's used to avoid unregistering stuff. Instead of adding an extra flag you should refactor the code. Have a common enable subroutine that can be called for both init and resume, and a common disable subroutine that can be called for both exit and suspend. Then the method routines themselves will contain only the portions unique to their particular functions, making them shorter and simpler. Well, it doesn't seem to be that easy. I tried to fix the issue myself and finally obtained the appended, apparently working, patch (against 2.6.24-rc8-mm1). Well, it should have been a series of patches against multiple subsystems, but I thought it would be instructive to put everything needed into one bigger patch for starters. Greetings, Rafael --- drivers/base/power/main.c |1 drivers/base/power/power.h |1 drivers/char/hw_random/core.c | 10 - drivers/char/misc.c | 13 drivers/leds/led-class.c| 13 drivers/net/wireless/b43/leds.c | 17 +-- drivers/net/wireless/b43/leds.h | 14 +++-- drivers/net/wireless/b43/main.c | 43 +--- include/linux/device.h |6 + include/linux/hw_random.h | 10 - include/linux/leds.h| 10 - include/linux/miscdevice.h | 10 - 12 files changed, 111 insertions(+), 37 deletions(-) Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/main.c +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c @@ -2470,10 +2470,15 @@ static int b43_rng_read(struct hwrng *rn 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) - hwrng_unregister(wl-rng); + __hwrng_unregister(wl-rng, suspended); +} + +static void b43_rng_exit(struct b43_wl *wl) +{ + __b43_rng_exit(wl, false); } static int b43_rng_init(struct b43_wl *wl) @@ -3289,7 +3294,7 @@ static void b43_set_retry_limits(struct /* Shutdown a wireless core */ /* Locking: wl-mutex */ -static void b43_wireless_core_exit(struct b43_wldev *dev) +static void __b43_wireless_core_exit(struct b43_wldev *dev, bool no_suspend) { struct b43_phy *phy = dev-phy; @@ -3298,8 +3303,10 @@ static void b43_wireless_core_exit(struc return; b43_set_status(dev, B43_STAT_UNINIT); - b43_leds_exit(dev); - b43_rng_exit(dev-wl); + if (no_suspend) { + b43_leds_exit(dev); + b43_rng_exit(dev-wl); + } b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); @@ -3313,8 +3320,13 @@ static void b43_wireless_core_exit(struc ssb_bus_may_powerdown(dev-dev-bus); } +static void b43_wireless_core_exit(struct b43_wldev *dev) +{ + __b43_wireless_core_exit(dev, true); +} + /* Initialize a wireless core */ -static int b43_wireless_core_init(struct b43_wldev *dev) +static int __b43_wireless_core_init(struct b43_wldev *dev, bool no_suspend) { struct b43_wl *wl = dev-wl; struct ssb_bus *bus = dev-dev-bus; @@ -3420,11 +3432,13 @@ static int b43_wireless_core_init(struct memset(wl-mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); b43_security_init(dev); - b43_rng_init(wl); + if (no_suspend) + b43_rng_init(wl); b43_set_status(dev, B43_STAT_INITIALIZED); - b43_leds_init(dev); + if (no_suspend) + b43_leds_init(dev); out: return err; @@ -3442,6 +3456,11 @@ out: return err; } +static int b43_wireless_core_init(struct b43_wldev *dev) +{ + return __b43_wireless_core_init(dev, true); +} + static int b43_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { @@ -4028,7 +4047,7 @@ static int b43_suspend(struct ssb_device if (wldev-suspend_init_status = B43_STAT_STARTED) b43_wireless_core_stop(wldev); if
Re: b43_suspend problem
On Sunday 13 January 2008 18:08:57 Alan Stern wrote: On Sun, 13 Jan 2008, Rafael J. Wysocki wrote: On Sunday, 13 of January 2008, Michael Buesch wrote: On Sunday 13 January 2008 00:08:29 Rafael J. Wysocki wrote: There is a problem with b43_suspend() that it (indirectly) causes b43_leds_exit() to be called, which attempts to unregister the leds device objects, which is forbidden (ie. you can't unregister and/or register devices during a suspend or resume). Why? Well, the unregistering itself is not really harmful, provided that the device is not registered back during the subsequent resume. The PM core uses a list of active devices that are added to the list in device_add(). The ordering of this list is important, because it is expected to reflect the order in which the devices are to be suspended. This list is manipulated during suspend/resume and devices are moved from it and back to it, so unregistering devices during a suspend and registering them during the subsequent resume generally changes its ordering and may lead to problems during the next suspend/resume cycle. This is also undesirable if we're going to stop using the freezer for suspend/resume at one point in the future. I'm sure Alan can add some more details. Indeed. A system suspend is a delicate operation, and the PM core needs to access all the devices in the system. To have devices being registered and unregistered at the same time would cause a lot of confusion. In self defense, the PM core starts out by acquiring all the device semaphores before calling the suspend routines. This means that if a suspend routine tries to unregister anything, it will deadlock at the point where the driver core tries to acquire the device semaphore prior to invoking the driver's remove method. Besides, if you're going to register the device right back again during the subsequent resume, then why go to the trouble of unregistering it during suspend? Why not just leave it registered the whole time and avoid all the complication (and excess meaningless uevents)? Well, because not doing it complicates code :) Currently suspend/resume calls the same code as init/exit. The b43 init/exit code is really complicated, compared to other drivers, due to dozens of hardware versions. So I just avoided having yet other codepaths for suspend/resume. But I will add a flag to the device structure that's used to avoid unregistering stuff. -- Greetings Michael. ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
Re: b43_suspend problem
On Sunday, 13 of January 2008, Michael Buesch wrote: On Sunday 13 January 2008 00:08:29 Rafael J. Wysocki wrote: There is a problem with b43_suspend() that it (indirectly) causes b43_leds_exit() to be called, which attempts to unregister the leds device objects, which is forbidden (ie. you can't unregister and/or register devices during a suspend or resume). Why? Well, the unregistering itself is not really harmful, provided that the device is not registered back during the subsequent resume. The PM core uses a list of active devices that are added to the list in device_add(). The ordering of this list is important, because it is expected to reflect the order in which the devices are to be suspended. This list is manipulated during suspend/resume and devices are moved from it and back to it, so unregistering devices during a suspend and registering them during the subsequent resume generally changes its ordering and may lead to problems during the next suspend/resume cycle. This is also undesirable if we're going to stop using the freezer for suspend/resume at one point in the future. I'm sure Alan can add some more details. Greetings, Rafael ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev