From 98247e0a408b4b551441bee5068eaa59ee646a11 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Sat, 9 Aug 2003 21:58:35 -0700 Subject: [PATCH] [power] Add PM usage counting - Add ->pm_users and ->pm_parent fields to struct dev_pm_info. - Add function device_pm_set_parent() The default power parent for a device is the device's physical parent, but a driver may change it to represent a tranversal power dependency. Though it's not incorporated into the suspend/resume sequences yet, the core will respect the power tree, rather than the physical/electrical one. Also added is a power usage count for devices, which indicates how many devices are dependent on that one for power (how many children it has in the power tree). The core will use this count to determine whether or not a device can be put into a low power state or not. --- drivers/base/power/main.c | 45 ++++++++++++++++++++++++++++++++++++++- include/linux/pm.h | 6 ++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index c622902b441bb..37e027c733a09 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -22,7 +22,7 @@ #define DEBUG #include - +#include "power.h" LIST_HEAD(dpm_active); LIST_HEAD(dpm_suspended); @@ -39,6 +39,46 @@ static struct attribute_group pm_attr_group = { .attrs = power_attrs, }; + +/* + * PM Reference Counting. + */ + +static inline void device_pm_hold(struct device * dev) +{ + atomic_inc(&dev->power.pm_users); +} + +static inline void device_pm_release(struct device * dev) +{ + atomic_inc(&dev->power.pm_users); +} + + +/** + * device_pm_set_parent - Specify power dependency. + * @dev: Device who needs power. + * @parent: Device that supplies power. + * + * This function is used to manually describe a power-dependency + * relationship. It may be used to specify a transversal relationship + * (where the power supplier is not the physical (or electrical) + * ancestor of a specific device. + * The effect of this is that the supplier will not be powered down + * before the power dependent. + */ + +void device_pm_set_parent(struct device * dev, struct device * parent) +{ + struct device * old_parent = dev->power.pm_parent; + if (old_parent) + device_pm_release(old_parent); + dev->power.pm_parent = parent; + if (parent) + device_pm_hold(parent); +} +EXPORT_SYMBOL(device_pm_set_parent); + int device_pm_add(struct device * dev) { int error; @@ -47,6 +87,7 @@ int device_pm_add(struct device * dev) dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); down(&dpm_sem); list_add_tail(&dev->power.entry,&dpm_active); + device_pm_set_parent(dev,dev->parent); error = sysfs_create_group(&dev->kobj,&pm_attr_group); up(&dpm_sem); return error; @@ -61,3 +102,5 @@ void device_pm_remove(struct device * dev) list_del(&dev->power.entry); up(&dpm_sem); } + + diff --git a/include/linux/pm.h b/include/linux/pm.h index 9750051e4b4ec..6942ad5d5cb3c 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -25,6 +25,7 @@ #include #include +#include /* * Power management requests @@ -188,15 +189,20 @@ static inline void pm_dev_idle(struct pm_dev *dev) {} extern void (*pm_idle)(void); extern void (*pm_power_off)(void); +struct device; struct dev_pm_info { #ifdef CONFIG_PM u32 power_state; u8 * saved_state; + atomic_t pm_users; + struct device * pm_parent; struct list_head entry; #endif }; +extern void device_pm_set_parent(struct device * dev, struct device * parent); + extern int device_pm_suspend(u32 state); extern int device_pm_power_down(u32 state); extern void device_pm_power_up(void); -- 2.53.0