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. > /* 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 (wldev->suspend_init_status >= B43_STAT_INITIALIZED) > - b43_wireless_core_exit(wldev); > + __b43_wireless_core_exit(wldev, false); > mutex_unlock(&wl->mutex); > > b43dbg(wl, "Device suspended.\n"); > @@ -4046,7 +4065,7 @@ static int b43_resume(struct ssb_device > > mutex_lock(&wl->mutex); > if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) { > - err = b43_wireless_core_init(wldev); > + err = __b43_wireless_core_init(wldev, false); > if (err) { > b43err(wl, "Resume failed at core init\n"); > goto out; > @@ -4055,7 +4074,9 @@ static int b43_resume(struct ssb_device > if (wldev->suspend_init_status >= B43_STAT_STARTED) { > err = b43_wireless_core_start(wldev); > if (err) { > - b43_wireless_core_exit(wldev); > + b43_leds_resume_exit(wldev); > + __b43_rng_exit(wldev->wl, true); > + __b43_wireless_core_exit(wldev, false); > b43err(wl, "Resume failed at core start\n"); > goto out; > } > 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); > +} No obfuscation please. > #else /* CONFIG_B43_LEDS */ > /* LED support disabled */ > @@ -59,6 +66,9 @@ static inline void b43_leds_init(struct > static inline void b43_leds_exit(struct b43_wldev *dev) > { > } > +static inline void b43_leds_resume_exit(struct b43_wldev *dev) > +{ > +} > #endif /* CONFIG_B43_LEDS */ > > #endif /* B43_LEDS_H_ */ > Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.c > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/leds.c > +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.c > @@ -112,11 +112,14 @@ static int b43_register_led(struct b43_w > return 0; > } > > -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) > + 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); > } > Index: linux-2.6.24-rc8-mm1/drivers/leds/led-class.c > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/drivers/leds/led-class.c > +++ linux-2.6.24-rc8-mm1/drivers/leds/led-class.c > @@ -137,12 +137,14 @@ err_out: > EXPORT_SYMBOL_GPL(led_classdev_register); > > /** > - * led_classdev_unregister - unregisters a object of led_properties class. > + * __led_classdev_unregister - unregisters a object of led_properties class. > * @led_cdev: the led device to unregister > + * @suspended: indicates whether system-wide suspend or resume is in progress > * > * Unregisters a previously registered via led_classdev_register object. > */ > -void led_classdev_unregister(struct led_classdev *led_cdev) > +void __led_classdev_unregister(struct led_classdev *led_cdev, > + bool suspended) > { > device_remove_file(led_cdev->dev, &dev_attr_brightness); > #ifdef CONFIG_LEDS_TRIGGERS > @@ -153,13 +155,16 @@ void led_classdev_unregister(struct led_ > up_write(&led_cdev->trigger_lock); > #endif > > - device_unregister(led_cdev->dev); > + if (suspended) > + device_pm_schedule_removal(led_cdev->dev); > + else > + device_unregister(led_cdev->dev); > > down_write(&leds_list_lock); > list_del(&led_cdev->node); > up_write(&leds_list_lock); > } > -EXPORT_SYMBOL_GPL(led_classdev_unregister); > +EXPORT_SYMBOL_GPL(__led_classdev_unregister); > > static int __init leds_init(void) > { > Index: linux-2.6.24-rc8-mm1/include/linux/leds.h > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/include/linux/leds.h > +++ linux-2.6.24-rc8-mm1/include/linux/leds.h > @@ -59,7 +59,15 @@ struct led_classdev { > > extern int led_classdev_register(struct device *parent, > struct led_classdev *led_cdev); > -extern void led_classdev_unregister(struct led_classdev *led_cdev); > +extern void __led_classdev_unregister(struct led_classdev *led_cdev, bool sus); > +static inline void led_classdev_unregister(struct led_classdev *lcd) > +{ > + __led_classdev_unregister(lcd, false); > +} > +static inline void led_classdev_unregister_suspended(struct led_classdev *lcd) > +{ > + __led_classdev_unregister(lcd, true); > +} > extern void led_classdev_suspend(struct led_classdev *led_cdev); > extern void led_classdev_resume(struct led_classdev *led_cdev); > > Index: linux-2.6.24-rc8-mm1/drivers/base/power/main.c > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/drivers/base/power/main.c > +++ linux-2.6.24-rc8-mm1/drivers/base/power/main.c > @@ -129,6 +129,7 @@ void device_pm_schedule_removal(struct d > list_move_tail(&dev->power.entry, &dpm_destroy); > mutex_unlock(&dpm_list_mtx); > } > +EXPORT_SYMBOL_GPL(device_pm_schedule_removal); > > /** > * pm_sleep_lock - mutual exclusion for registration and suspend > Index: linux-2.6.24-rc8-mm1/include/linux/device.h > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/include/linux/device.h > +++ linux-2.6.24-rc8-mm1/include/linux/device.h > @@ -532,11 +532,17 @@ extern struct device *device_create(stru > extern void device_destroy(struct class *cls, dev_t devt); > #ifdef CONFIG_PM_SLEEP > extern void destroy_suspended_device(struct class *cls, dev_t devt); > +extern void device_pm_schedule_removal(struct device *); > #else /* !CONFIG_PM_SLEEP */ > static inline void destroy_suspended_device(struct class *cls, dev_t devt) > { > device_destroy(cls, devt); > } > + > +static inline void device_pm_schedule_removal(struct device *dev) > +{ > + device_unregister(dev); > +} > #endif /* !CONFIG_PM_SLEEP */ > > /* > Index: linux-2.6.24-rc8-mm1/drivers/base/power/power.h > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/drivers/base/power/power.h > +++ linux-2.6.24-rc8-mm1/drivers/base/power/power.h > @@ -13,7 +13,6 @@ static inline struct device *to_device(s > > extern void device_pm_add(struct device *); > extern void device_pm_remove(struct device *); > -extern void device_pm_schedule_removal(struct device *); > extern int pm_sleep_lock(void); > extern void pm_sleep_unlock(void); > > Index: linux-2.6.24-rc8-mm1/drivers/char/misc.c > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/drivers/char/misc.c > +++ linux-2.6.24-rc8-mm1/drivers/char/misc.c > @@ -232,8 +232,9 @@ int misc_register(struct miscdevice * mi > } > > /** > - * misc_deregister - unregister a miscellaneous device > + * __misc_deregister - unregister a miscellaneous device > * @misc: device to unregister > + * @suspended: to be set if the function is used during suspend/resume > * > * Unregister a miscellaneous device that was previously > * successfully registered with misc_register(). Success > @@ -241,7 +242,7 @@ int misc_register(struct miscdevice * mi > * indicates an error. > */ > > -int misc_deregister(struct miscdevice * misc) > +int __misc_deregister(struct miscdevice *misc, bool suspended) > { > int i = misc->minor; > > @@ -250,7 +251,11 @@ int misc_deregister(struct miscdevice * > > mutex_lock(&misc_mtx); > list_del(&misc->list); > - device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); > + if (suspended) > + destroy_suspended_device(misc_class, > + MKDEV(MISC_MAJOR, misc->minor)); > + else > + device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); > if (i < DYNAMIC_MINORS && i>0) { > misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); > } > @@ -259,7 +264,7 @@ int misc_deregister(struct miscdevice * > } > > EXPORT_SYMBOL(misc_register); > -EXPORT_SYMBOL(misc_deregister); > +EXPORT_SYMBOL(__misc_deregister); > > static int __init misc_init(void) > { > Index: linux-2.6.24-rc8-mm1/include/linux/miscdevice.h > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/include/linux/miscdevice.h > +++ linux-2.6.24-rc8-mm1/include/linux/miscdevice.h > @@ -43,7 +43,15 @@ struct miscdevice { > }; > > extern int misc_register(struct miscdevice * misc); > -extern int misc_deregister(struct miscdevice * misc); > +extern int __misc_deregister(struct miscdevice *misc, bool suspended); > +static inline int misc_deregister(struct miscdevice *misc) > +{ > + return __misc_deregister(misc, false); > +} > +static inline int misc_deregister_suspended(struct miscdevice *misc) > +{ > + return __misc_deregister(misc, true); > +} > > #define MODULE_ALIAS_MISCDEV(minor) \ > MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \ > Index: linux-2.6.24-rc8-mm1/drivers/char/hw_random/core.c > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/drivers/char/hw_random/core.c > +++ linux-2.6.24-rc8-mm1/drivers/char/hw_random/core.c > @@ -234,11 +234,11 @@ static DEVICE_ATTR(rng_available, S_IRUG > NULL); > > > -static void unregister_miscdev(void) > +static void unregister_miscdev(bool suspended) > { > device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available); > device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); > - misc_deregister(&rng_miscdev); > + __misc_deregister(&rng_miscdev, suspended); > } > > static int register_miscdev(void) > @@ -313,7 +313,7 @@ out: > } > EXPORT_SYMBOL_GPL(hwrng_register); > > -void hwrng_unregister(struct hwrng *rng) > +void __hwrng_unregister(struct hwrng *rng, bool suspended) > { > int err; > > @@ -332,11 +332,11 @@ void hwrng_unregister(struct hwrng *rng) > } > } > if (list_empty(&rng_list)) > - unregister_miscdev(); > + unregister_miscdev(suspended); > > mutex_unlock(&rng_mutex); > } > -EXPORT_SYMBOL_GPL(hwrng_unregister); > +EXPORT_SYMBOL_GPL(__hwrng_unregister); > > > MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); > Index: linux-2.6.24-rc8-mm1/include/linux/hw_random.h > =================================================================== > --- linux-2.6.24-rc8-mm1.orig/include/linux/hw_random.h > +++ linux-2.6.24-rc8-mm1/include/linux/hw_random.h > @@ -44,7 +44,15 @@ struct hwrng { > /** Register a new Hardware Random Number Generator driver. */ > extern int hwrng_register(struct hwrng *rng); > /** Unregister a Hardware Random Number Generator driver. */ > -extern void hwrng_unregister(struct hwrng *rng); > +extern void __hwrng_unregister(struct hwrng *rng, bool suspended); > +static inline void hwrng_unregister(struct hwrng *rng) > +{ > + __hwrng_unregister(rng, false); > +} > +static inline void hwrng_unregister_suspended(struct hwrng *rng) > +{ > + __hwrng_unregister(rng, true); > +} > > #endif /* __KERNEL__ */ > #endif /* LINUX_HWRANDOM_H_ */ > > _______________________________________________ linux-pm mailing list linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/linux-pm