PM / Domains: Use power.sybsys_data to reduce overhead
Currently pm_genpd_runtime_resume() has to walk the list of devices from the device's PM domain to find the corresponding device list object containing the need_restore field to check if the driver's .runtime_resume() callback should be executed for the device. This is suboptimal and can be simplified by using power.sybsys_data to store device information used by the generic PM domains code. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
This commit is contained in:
parent
ef27bed187
commit
4605ab653c
|
@ -114,11 +114,9 @@ void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
|
||||||
if (!dev->power.subsys_data) {
|
|
||||||
pm_clk_create(dev);
|
|
||||||
pm_clk_add(dev, NULL);
|
|
||||||
}
|
|
||||||
pm_genpd_add_device(&sh7372_pd->genpd, dev);
|
pm_genpd_add_device(&sh7372_pd->genpd, dev);
|
||||||
|
if (pm_clk_no_clocks(dev))
|
||||||
|
pm_clk_add(dev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
|
void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
|
||||||
|
|
|
@ -181,18 +181,18 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __pm_genpd_save_device - Save the pre-suspend state of a device.
|
* __pm_genpd_save_device - Save the pre-suspend state of a device.
|
||||||
* @dle: Device list entry of the device to save the state of.
|
* @pdd: Domain data of the device to save the state of.
|
||||||
* @genpd: PM domain the device belongs to.
|
* @genpd: PM domain the device belongs to.
|
||||||
*/
|
*/
|
||||||
static int __pm_genpd_save_device(struct dev_list_entry *dle,
|
static int __pm_genpd_save_device(struct pm_domain_data *pdd,
|
||||||
struct generic_pm_domain *genpd)
|
struct generic_pm_domain *genpd)
|
||||||
__releases(&genpd->lock) __acquires(&genpd->lock)
|
__releases(&genpd->lock) __acquires(&genpd->lock)
|
||||||
{
|
{
|
||||||
struct device *dev = dle->dev;
|
struct device *dev = pdd->dev;
|
||||||
struct device_driver *drv = dev->driver;
|
struct device_driver *drv = dev->driver;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (dle->need_restore)
|
if (pdd->need_restore)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mutex_unlock(&genpd->lock);
|
mutex_unlock(&genpd->lock);
|
||||||
|
@ -210,24 +210,24 @@ static int __pm_genpd_save_device(struct dev_list_entry *dle,
|
||||||
mutex_lock(&genpd->lock);
|
mutex_lock(&genpd->lock);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
dle->need_restore = true;
|
pdd->need_restore = true;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __pm_genpd_restore_device - Restore the pre-suspend state of a device.
|
* __pm_genpd_restore_device - Restore the pre-suspend state of a device.
|
||||||
* @dle: Device list entry of the device to restore the state of.
|
* @pdd: Domain data of the device to restore the state of.
|
||||||
* @genpd: PM domain the device belongs to.
|
* @genpd: PM domain the device belongs to.
|
||||||
*/
|
*/
|
||||||
static void __pm_genpd_restore_device(struct dev_list_entry *dle,
|
static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
|
||||||
struct generic_pm_domain *genpd)
|
struct generic_pm_domain *genpd)
|
||||||
__releases(&genpd->lock) __acquires(&genpd->lock)
|
__releases(&genpd->lock) __acquires(&genpd->lock)
|
||||||
{
|
{
|
||||||
struct device *dev = dle->dev;
|
struct device *dev = pdd->dev;
|
||||||
struct device_driver *drv = dev->driver;
|
struct device_driver *drv = dev->driver;
|
||||||
|
|
||||||
if (!dle->need_restore)
|
if (!pdd->need_restore)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mutex_unlock(&genpd->lock);
|
mutex_unlock(&genpd->lock);
|
||||||
|
@ -244,7 +244,7 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle,
|
||||||
|
|
||||||
mutex_lock(&genpd->lock);
|
mutex_lock(&genpd->lock);
|
||||||
|
|
||||||
dle->need_restore = false;
|
pdd->need_restore = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -286,7 +286,7 @@ void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
|
||||||
static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
|
static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
|
||||||
__releases(&genpd->lock) __acquires(&genpd->lock)
|
__releases(&genpd->lock) __acquires(&genpd->lock)
|
||||||
{
|
{
|
||||||
struct dev_list_entry *dle;
|
struct pm_domain_data *pdd;
|
||||||
struct gpd_link *link;
|
struct gpd_link *link;
|
||||||
unsigned int not_suspended;
|
unsigned int not_suspended;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -308,8 +308,8 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
not_suspended = 0;
|
not_suspended = 0;
|
||||||
list_for_each_entry(dle, &genpd->dev_list, node)
|
list_for_each_entry(pdd, &genpd->dev_list, list_node)
|
||||||
if (dle->dev->driver && !pm_runtime_suspended(dle->dev))
|
if (pdd->dev->driver && !pm_runtime_suspended(pdd->dev))
|
||||||
not_suspended++;
|
not_suspended++;
|
||||||
|
|
||||||
if (not_suspended > genpd->in_progress)
|
if (not_suspended > genpd->in_progress)
|
||||||
|
@ -332,9 +332,9 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
|
||||||
genpd->status = GPD_STATE_BUSY;
|
genpd->status = GPD_STATE_BUSY;
|
||||||
genpd->poweroff_task = current;
|
genpd->poweroff_task = current;
|
||||||
|
|
||||||
list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
|
list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
|
||||||
ret = atomic_read(&genpd->sd_count) == 0 ?
|
ret = atomic_read(&genpd->sd_count) == 0 ?
|
||||||
__pm_genpd_save_device(dle, genpd) : -EBUSY;
|
__pm_genpd_save_device(pdd, genpd) : -EBUSY;
|
||||||
|
|
||||||
if (genpd_abort_poweroff(genpd))
|
if (genpd_abort_poweroff(genpd))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -432,24 +432,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* __pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
|
|
||||||
* @dev: Device to resume.
|
|
||||||
* @genpd: PM domain the device belongs to.
|
|
||||||
*/
|
|
||||||
static void __pm_genpd_runtime_resume(struct device *dev,
|
|
||||||
struct generic_pm_domain *genpd)
|
|
||||||
{
|
|
||||||
struct dev_list_entry *dle;
|
|
||||||
|
|
||||||
list_for_each_entry(dle, &genpd->dev_list, node) {
|
|
||||||
if (dle->dev == dev) {
|
|
||||||
__pm_genpd_restore_device(dle, genpd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
|
* pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
|
||||||
* @dev: Device to resume.
|
* @dev: Device to resume.
|
||||||
|
@ -495,7 +477,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
|
||||||
mutex_lock(&genpd->lock);
|
mutex_lock(&genpd->lock);
|
||||||
}
|
}
|
||||||
finish_wait(&genpd->status_wait_queue, &wait);
|
finish_wait(&genpd->status_wait_queue, &wait);
|
||||||
__pm_genpd_runtime_resume(dev, genpd);
|
__pm_genpd_restore_device(&dev->power.subsys_data->domain_data, genpd);
|
||||||
genpd->resume_count--;
|
genpd->resume_count--;
|
||||||
genpd_set_active(genpd);
|
genpd_set_active(genpd);
|
||||||
wake_up_all(&genpd->status_wait_queue);
|
wake_up_all(&genpd->status_wait_queue);
|
||||||
|
@ -525,8 +507,6 @@ void pm_genpd_poweroff_unused(void)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline void genpd_power_off_work_fn(struct work_struct *work) {}
|
static inline void genpd_power_off_work_fn(struct work_struct *work) {}
|
||||||
static inline void __pm_genpd_runtime_resume(struct device *dev,
|
|
||||||
struct generic_pm_domain *genpd) {}
|
|
||||||
|
|
||||||
#define pm_genpd_runtime_suspend NULL
|
#define pm_genpd_runtime_suspend NULL
|
||||||
#define pm_genpd_runtime_resume NULL
|
#define pm_genpd_runtime_resume NULL
|
||||||
|
@ -1083,7 +1063,7 @@ static void pm_genpd_complete(struct device *dev)
|
||||||
*/
|
*/
|
||||||
int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
|
int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
|
||||||
{
|
{
|
||||||
struct dev_list_entry *dle;
|
struct pm_domain_data *pdd;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
dev_dbg(dev, "%s()\n", __func__);
|
dev_dbg(dev, "%s()\n", __func__);
|
||||||
|
@ -1103,26 +1083,20 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(dle, &genpd->dev_list, node)
|
list_for_each_entry(pdd, &genpd->dev_list, list_node)
|
||||||
if (dle->dev == dev) {
|
if (pdd->dev == dev) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
dle = kzalloc(sizeof(*dle), GFP_KERNEL);
|
|
||||||
if (!dle) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dle->dev = dev;
|
|
||||||
dle->need_restore = false;
|
|
||||||
list_add_tail(&dle->node, &genpd->dev_list);
|
|
||||||
genpd->device_count++;
|
genpd->device_count++;
|
||||||
|
|
||||||
spin_lock_irq(&dev->power.lock);
|
|
||||||
dev->pm_domain = &genpd->domain;
|
dev->pm_domain = &genpd->domain;
|
||||||
spin_unlock_irq(&dev->power.lock);
|
dev_pm_get_subsys_data(dev);
|
||||||
|
pdd = &dev->power.subsys_data->domain_data;
|
||||||
|
pdd->dev = dev;
|
||||||
|
pdd->need_restore = false;
|
||||||
|
list_add_tail(&pdd->list_node, &genpd->dev_list);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
genpd_release_lock(genpd);
|
genpd_release_lock(genpd);
|
||||||
|
@ -1138,7 +1112,7 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
|
||||||
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
||||||
struct device *dev)
|
struct device *dev)
|
||||||
{
|
{
|
||||||
struct dev_list_entry *dle;
|
struct pm_domain_data *pdd;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
dev_dbg(dev, "%s()\n", __func__);
|
dev_dbg(dev, "%s()\n", __func__);
|
||||||
|
@ -1153,17 +1127,16 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(dle, &genpd->dev_list, node) {
|
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
|
||||||
if (dle->dev != dev)
|
if (pdd->dev != dev)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
spin_lock_irq(&dev->power.lock);
|
list_del_init(&pdd->list_node);
|
||||||
|
pdd->dev = NULL;
|
||||||
|
dev_pm_put_subsys_data(dev);
|
||||||
dev->pm_domain = NULL;
|
dev->pm_domain = NULL;
|
||||||
spin_unlock_irq(&dev->power.lock);
|
|
||||||
|
|
||||||
genpd->device_count--;
|
genpd->device_count--;
|
||||||
list_del(&dle->node);
|
|
||||||
kfree(dle);
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -421,12 +421,21 @@ enum rpm_request {
|
||||||
|
|
||||||
struct wakeup_source;
|
struct wakeup_source;
|
||||||
|
|
||||||
|
struct pm_domain_data {
|
||||||
|
struct list_head list_node;
|
||||||
|
struct device *dev;
|
||||||
|
bool need_restore;
|
||||||
|
};
|
||||||
|
|
||||||
struct pm_subsys_data {
|
struct pm_subsys_data {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
unsigned int refcount;
|
unsigned int refcount;
|
||||||
#ifdef CONFIG_PM_CLK
|
#ifdef CONFIG_PM_CLK
|
||||||
struct list_head clock_list;
|
struct list_head clock_list;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_PM_GENERIC_DOMAINS
|
||||||
|
struct pm_domain_data domain_data;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dev_pm_info {
|
struct dev_pm_info {
|
||||||
|
|
|
@ -61,12 +61,6 @@ struct gpd_link {
|
||||||
struct list_head slave_node;
|
struct list_head slave_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dev_list_entry {
|
|
||||||
struct list_head node;
|
|
||||||
struct device *dev;
|
|
||||||
bool need_restore;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM_GENERIC_DOMAINS
|
#ifdef CONFIG_PM_GENERIC_DOMAINS
|
||||||
extern int pm_genpd_add_device(struct generic_pm_domain *genpd,
|
extern int pm_genpd_add_device(struct generic_pm_domain *genpd,
|
||||||
struct device *dev);
|
struct device *dev);
|
||||||
|
|
|
@ -258,6 +258,12 @@ struct pm_clk_notifier_block {
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PM_CLK
|
#ifdef CONFIG_PM_CLK
|
||||||
|
static inline bool pm_clk_no_clocks(struct device *dev)
|
||||||
|
{
|
||||||
|
return dev && dev->power.subsys_data
|
||||||
|
&& list_empty(&dev->power.subsys_data->clock_list);
|
||||||
|
}
|
||||||
|
|
||||||
extern void pm_clk_init(struct device *dev);
|
extern void pm_clk_init(struct device *dev);
|
||||||
extern int pm_clk_create(struct device *dev);
|
extern int pm_clk_create(struct device *dev);
|
||||||
extern void pm_clk_destroy(struct device *dev);
|
extern void pm_clk_destroy(struct device *dev);
|
||||||
|
@ -266,6 +272,10 @@ extern void pm_clk_remove(struct device *dev, const char *con_id);
|
||||||
extern int pm_clk_suspend(struct device *dev);
|
extern int pm_clk_suspend(struct device *dev);
|
||||||
extern int pm_clk_resume(struct device *dev);
|
extern int pm_clk_resume(struct device *dev);
|
||||||
#else
|
#else
|
||||||
|
static inline bool pm_clk_no_clocks(struct device *dev)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
static inline void pm_clk_init(struct device *dev)
|
static inline void pm_clk_init(struct device *dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue