From 55e15c949fd05d247a889df0ed0177a676fec665 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:17 +0200 Subject: [PATCH 01/32] PM / domains: Remove the pm_genpd_add|remove_callbacks APIs There are no users of these APIs. To simplify the generic power domain let's remove them. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 106 ------------------------------------ include/linux/pm_domain.h | 19 ------- 2 files changed, 125 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index eee55c1e5fde..e613e3cb96d8 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1743,112 +1743,6 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, return ret; } -/** - * pm_genpd_add_callbacks - Add PM domain callbacks to a given device. - * @dev: Device to add the callbacks to. - * @ops: Set of callbacks to add. - * @td: Timing data to add to the device along with the callbacks (optional). - * - * Every call to this routine should be balanced with a call to - * __pm_genpd_remove_callbacks() and they must not be nested. - */ -int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops, - struct gpd_timing_data *td) -{ - struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL; - int ret = 0; - - if (!(dev && ops)) - return -EINVAL; - - gpd_data_new = __pm_genpd_alloc_dev_data(dev); - if (!gpd_data_new) - return -ENOMEM; - - pm_runtime_disable(dev); - device_pm_lock(); - - ret = dev_pm_get_subsys_data(dev); - if (ret) - goto out; - - spin_lock_irq(&dev->power.lock); - - if (dev->power.subsys_data->domain_data) { - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - } else { - gpd_data = gpd_data_new; - dev->power.subsys_data->domain_data = &gpd_data->base; - } - gpd_data->refcount++; - gpd_data->ops = *ops; - if (td) - gpd_data->td = *td; - - spin_unlock_irq(&dev->power.lock); - - out: - device_pm_unlock(); - pm_runtime_enable(dev); - - if (gpd_data != gpd_data_new) - __pm_genpd_free_dev_data(dev, gpd_data_new); - - return ret; -} -EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks); - -/** - * __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device. - * @dev: Device to remove the callbacks from. - * @clear_td: If set, clear the device's timing data too. - * - * This routine can only be called after pm_genpd_add_callbacks(). - */ -int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td) -{ - struct generic_pm_domain_data *gpd_data = NULL; - bool remove = false; - int ret = 0; - - if (!(dev && dev->power.subsys_data)) - return -EINVAL; - - pm_runtime_disable(dev); - device_pm_lock(); - - spin_lock_irq(&dev->power.lock); - - if (dev->power.subsys_data->domain_data) { - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - gpd_data->ops = (struct gpd_dev_ops){ NULL }; - if (clear_td) - gpd_data->td = (struct gpd_timing_data){ 0 }; - - if (--gpd_data->refcount == 0) { - dev->power.subsys_data->domain_data = NULL; - remove = true; - } - } else { - ret = -EINVAL; - } - - spin_unlock_irq(&dev->power.lock); - - device_pm_unlock(); - pm_runtime_enable(dev); - - if (ret) - return ret; - - dev_pm_put_subsys_data(dev); - if (remove) - __pm_genpd_free_dev_data(dev, gpd_data); - - return 0; -} -EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks); - /** * pm_genpd_attach_cpuidle - Connect the given PM domain with cpuidle. * @genpd: PM domain to be connected with cpuidle. diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index ebc4c76ffb73..9ae2b9e88d61 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -151,10 +151,6 @@ extern int pm_genpd_add_subdomain_names(const char *master_name, const char *subdomain_name); extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *target); -extern int pm_genpd_add_callbacks(struct device *dev, - struct gpd_dev_ops *ops, - struct gpd_timing_data *td); -extern int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td); extern int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state); extern int pm_genpd_name_attach_cpuidle(const char *name, int state); extern int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd); @@ -217,16 +213,6 @@ static inline int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, { return -ENOSYS; } -static inline int pm_genpd_add_callbacks(struct device *dev, - struct gpd_dev_ops *ops, - struct gpd_timing_data *td) -{ - return -ENOSYS; -} -static inline int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td) -{ - return -ENOSYS; -} static inline int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int st) { return -ENOSYS; @@ -281,11 +267,6 @@ static inline int pm_genpd_name_add_device(const char *domain_name, return __pm_genpd_name_add_device(domain_name, dev, NULL); } -static inline int pm_genpd_remove_callbacks(struct device *dev) -{ - return __pm_genpd_remove_callbacks(dev, true); -} - #ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd); extern void pm_genpd_poweroff_unused(void); From 67da6d4bf43c4208433ef8f3ee487401b4dc9c74 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:18 +0200 Subject: [PATCH 02/32] PM / domains: Ignore callbacks for subsys generic_pm_domain_data In a step of simplifying the generic power domain let's move away from using these callbacks. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 131 +++--------------------------------- include/linux/pm_domain.h | 1 - 2 files changed, 8 insertions(+), 124 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index e613e3cb96d8..aa5b14c1e643 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -25,10 +25,6 @@ __routine = genpd->dev_ops.callback; \ if (__routine) { \ __ret = __routine(dev); \ - } else { \ - __routine = dev_gpd_data(dev)->ops.callback; \ - if (__routine) \ - __ret = __routine(dev); \ } \ __ret; \ }) @@ -1871,10 +1867,6 @@ static int pm_genpd_default_save_state(struct device *dev) { int (*cb)(struct device *__dev); - cb = dev_gpd_data(dev)->ops.save_state; - if (cb) - return cb(dev); - if (dev->type && dev->type->pm) cb = dev->type->pm->runtime_suspend; else if (dev->class && dev->class->pm) @@ -1898,10 +1890,6 @@ static int pm_genpd_default_restore_state(struct device *dev) { int (*cb)(struct device *__dev); - cb = dev_gpd_data(dev)->ops.restore_state; - if (cb) - return cb(dev); - if (dev->type && dev->type->pm) cb = dev->type->pm->runtime_resume; else if (dev->class && dev->class->pm) @@ -1917,109 +1905,6 @@ static int pm_genpd_default_restore_state(struct device *dev) return cb ? cb(dev) : 0; } -#ifdef CONFIG_PM_SLEEP - -/** - * pm_genpd_default_suspend - Default "device suspend" for PM domians. - * @dev: Device to handle. - */ -static int pm_genpd_default_suspend(struct device *dev) -{ - int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend; - - return cb ? cb(dev) : pm_generic_suspend(dev); -} - -/** - * pm_genpd_default_suspend_late - Default "late device suspend" for PM domians. - * @dev: Device to handle. - */ -static int pm_genpd_default_suspend_late(struct device *dev) -{ - int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; - - return cb ? cb(dev) : pm_generic_suspend_late(dev); -} - -/** - * pm_genpd_default_resume_early - Default "early device resume" for PM domians. - * @dev: Device to handle. - */ -static int pm_genpd_default_resume_early(struct device *dev) -{ - int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; - - return cb ? cb(dev) : pm_generic_resume_early(dev); -} - -/** - * pm_genpd_default_resume - Default "device resume" for PM domians. - * @dev: Device to handle. - */ -static int pm_genpd_default_resume(struct device *dev) -{ - int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume; - - return cb ? cb(dev) : pm_generic_resume(dev); -} - -/** - * pm_genpd_default_freeze - Default "device freeze" for PM domians. - * @dev: Device to handle. - */ -static int pm_genpd_default_freeze(struct device *dev) -{ - int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze; - - return cb ? cb(dev) : pm_generic_freeze(dev); -} - -/** - * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians. - * @dev: Device to handle. - */ -static int pm_genpd_default_freeze_late(struct device *dev) -{ - int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; - - return cb ? cb(dev) : pm_generic_freeze_late(dev); -} - -/** - * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians. - * @dev: Device to handle. - */ -static int pm_genpd_default_thaw_early(struct device *dev) -{ - int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; - - return cb ? cb(dev) : pm_generic_thaw_early(dev); -} - -/** - * pm_genpd_default_thaw - Default "device thaw" for PM domians. - * @dev: Device to handle. - */ -static int pm_genpd_default_thaw(struct device *dev) -{ - int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw; - - return cb ? cb(dev) : pm_generic_thaw(dev); -} - -#else /* !CONFIG_PM_SLEEP */ - -#define pm_genpd_default_suspend NULL -#define pm_genpd_default_suspend_late NULL -#define pm_genpd_default_resume_early NULL -#define pm_genpd_default_resume NULL -#define pm_genpd_default_freeze NULL -#define pm_genpd_default_freeze_late NULL -#define pm_genpd_default_thaw_early NULL -#define pm_genpd_default_thaw NULL - -#endif /* !CONFIG_PM_SLEEP */ - /** * pm_genpd_init - Initialize a generic I/O PM domain object. * @genpd: PM domain object to initialize. @@ -2071,14 +1956,14 @@ void pm_genpd_init(struct generic_pm_domain *genpd, genpd->domain.ops.complete = pm_genpd_complete; genpd->dev_ops.save_state = pm_genpd_default_save_state; genpd->dev_ops.restore_state = pm_genpd_default_restore_state; - genpd->dev_ops.suspend = pm_genpd_default_suspend; - genpd->dev_ops.suspend_late = pm_genpd_default_suspend_late; - genpd->dev_ops.resume_early = pm_genpd_default_resume_early; - genpd->dev_ops.resume = pm_genpd_default_resume; - genpd->dev_ops.freeze = pm_genpd_default_freeze; - genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late; - genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early; - genpd->dev_ops.thaw = pm_genpd_default_thaw; + genpd->dev_ops.suspend = pm_generic_suspend; + genpd->dev_ops.suspend_late = pm_generic_suspend_late; + genpd->dev_ops.resume_early = pm_generic_resume_early; + genpd->dev_ops.resume = pm_generic_resume; + genpd->dev_ops.freeze = pm_generic_freeze; + genpd->dev_ops.freeze_late = pm_generic_freeze_late; + genpd->dev_ops.thaw_early = pm_generic_thaw_early; + genpd->dev_ops.thaw = pm_generic_thaw; mutex_lock(&gpd_list_lock); list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 9ae2b9e88d61..436ea149d40c 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -108,7 +108,6 @@ struct gpd_timing_data { struct generic_pm_domain_data { struct pm_domain_data base; - struct gpd_dev_ops ops; struct gpd_timing_data td; struct notifier_block nb; struct mutex lock; From 1e0407ca54d28db8e5f02e437ff21cc6416c0be8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:19 +0200 Subject: [PATCH 03/32] PM / domains: Remove system PM callbacks from gpd_dev_ops There no users of these callbacks, let's simplify the generic power domain by removing them. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 64 +++++-------------------------------- include/linux/pm_domain.h | 8 ----- 2 files changed, 8 insertions(+), 64 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index aa5b14c1e643..e777609ccc77 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -770,46 +770,6 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev); } -static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, suspend, dev); -} - -static int genpd_suspend_late(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, suspend_late, dev); -} - -static int genpd_resume_early(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, resume_early, dev); -} - -static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, resume, dev); -} - -static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, freeze, dev); -} - -static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev); -} - -static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev); -} - -static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, thaw, dev); -} - /** * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters. * @genpd: PM domain to power off, if possible. @@ -991,7 +951,7 @@ static int pm_genpd_suspend(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_suspend_dev(genpd, dev); + return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev); } /** @@ -1012,7 +972,7 @@ static int pm_genpd_suspend_late(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_suspend_late(genpd, dev); + return genpd->suspend_power_off ? 0 : pm_generic_suspend_late(dev); } /** @@ -1099,7 +1059,7 @@ static int pm_genpd_resume_early(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_resume_early(genpd, dev); + return genpd->suspend_power_off ? 0 : pm_generic_resume_early(dev); } /** @@ -1120,7 +1080,7 @@ static int pm_genpd_resume(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_resume_dev(genpd, dev); + return genpd->suspend_power_off ? 0 : pm_generic_resume(dev); } /** @@ -1141,7 +1101,7 @@ static int pm_genpd_freeze(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev); + return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev); } /** @@ -1163,7 +1123,7 @@ static int pm_genpd_freeze_late(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_freeze_late(genpd, dev); + return genpd->suspend_power_off ? 0 : pm_generic_freeze_late(dev); } /** @@ -1227,7 +1187,7 @@ static int pm_genpd_thaw_early(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_thaw_early(genpd, dev); + return genpd->suspend_power_off ? 0 : pm_generic_thaw_early(dev); } /** @@ -1248,7 +1208,7 @@ static int pm_genpd_thaw(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev); + return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev); } /** @@ -1956,14 +1916,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd, genpd->domain.ops.complete = pm_genpd_complete; genpd->dev_ops.save_state = pm_genpd_default_save_state; genpd->dev_ops.restore_state = pm_genpd_default_restore_state; - genpd->dev_ops.suspend = pm_generic_suspend; - genpd->dev_ops.suspend_late = pm_generic_suspend_late; - genpd->dev_ops.resume_early = pm_generic_resume_early; - genpd->dev_ops.resume = pm_generic_resume; - genpd->dev_ops.freeze = pm_generic_freeze; - genpd->dev_ops.freeze_late = pm_generic_freeze_late; - genpd->dev_ops.thaw_early = pm_generic_thaw_early; - genpd->dev_ops.thaw = pm_generic_thaw; mutex_lock(&gpd_list_lock); list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 436ea149d40c..b6343d4b9b04 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -35,14 +35,6 @@ struct gpd_dev_ops { int (*stop)(struct device *dev); int (*save_state)(struct device *dev); int (*restore_state)(struct device *dev); - int (*suspend)(struct device *dev); - int (*suspend_late)(struct device *dev); - int (*resume_early)(struct device *dev); - int (*resume)(struct device *dev); - int (*freeze)(struct device *dev); - int (*freeze_late)(struct device *dev); - int (*thaw_early)(struct device *dev); - int (*thaw)(struct device *dev); bool (*active_wakeup)(struct device *dev); }; From 698616548528615052ccdff2f621f1fde3bd9a50 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:20 +0200 Subject: [PATCH 04/32] ARM: shmobile: Drop dev_irq_safe from r8a7779 genpd config The dev_irq_safe configuration is redundant, genpd don't have any special treatmeant for handling it. Let's remove it. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- arch/arm/mach-shmobile/pm-r8a7779.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c index 69f70b7f7fb2..82fe3d7f9662 100644 --- a/arch/arm/mach-shmobile/pm-r8a7779.c +++ b/arch/arm/mach-shmobile/pm-r8a7779.c @@ -87,7 +87,6 @@ static void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd) genpd->dev_ops.stop = pm_clk_suspend; genpd->dev_ops.start = pm_clk_resume; genpd->dev_ops.active_wakeup = pd_active_wakeup; - genpd->dev_irq_safe = true; genpd->power_off = pd_power_down; genpd->power_on = pd_power_up; From cec89297da88ae9e8df0e3b7ea2e7e464b038cc9 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:21 +0200 Subject: [PATCH 05/32] ARM: shmobile: Drop dev_irq_safe from R-mobile genpd config The dev_irq_safe configuration is redundant, genpd don't have any special treatmeant for handling it. Let's remove it. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- arch/arm/mach-shmobile/pm-rmobile.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c index ebdd16e94a84..818de2fddfd4 100644 --- a/arch/arm/mach-shmobile/pm-rmobile.c +++ b/arch/arm/mach-shmobile/pm-rmobile.c @@ -111,7 +111,6 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd) genpd->dev_ops.stop = pm_clk_suspend; genpd->dev_ops.start = pm_clk_resume; genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup; - genpd->dev_irq_safe = true; genpd->power_off = rmobile_pd_power_down; genpd->power_on = rmobile_pd_power_up; __rmobile_pd_power_up(rmobile_pd, false); From c5d79ec2a5715489cff16a0d1cf4fa9108a5509e Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:22 +0200 Subject: [PATCH 06/32] PM / domains: Remove dev_irq_safe from genpd config The genpd dev_irq_safe configuration somewhat overlaps with the runtime PM pm_runtime_irq_safe() option. Also, currently genpd don't have a good way to deal with these device. So, until we figured out if and how to support this in genpd, let's remove the option to configure it. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 4 ---- include/linux/pm_domain.h | 1 - 2 files changed, 5 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index e777609ccc77..4298a2bcd228 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -615,8 +615,6 @@ static int pm_genpd_runtime_suspend(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - might_sleep_if(!genpd->dev_irq_safe); - stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; if (stop_ok && !stop_ok(dev)) return -EBUSY; @@ -661,8 +659,6 @@ static int pm_genpd_runtime_resume(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - might_sleep_if(!genpd->dev_irq_safe); - /* If power.irq_safe, the PM domain is never powered off. */ if (dev->power.irq_safe) return genpd_start_dev_no_timing(genpd, dev); diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index b6343d4b9b04..360c94ceeebb 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -63,7 +63,6 @@ struct generic_pm_domain { unsigned int suspended_count; /* System suspend device counter */ unsigned int prepared_count; /* Suspend counter of prepared devices */ bool suspend_power_off; /* Power status before system suspend */ - bool dev_irq_safe; /* Device callbacks are IRQ-safe */ int (*power_off)(struct generic_pm_domain *domain); s64 power_off_latency_ns; int (*power_on)(struct generic_pm_domain *domain); From 784b0d3d8bc5b8ac60fc620c3420dc430bba61a7 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:23 +0200 Subject: [PATCH 07/32] PM / domains: Remove redundant check for CONFIG_PM CONFIG_PM_GENERIC_DOMAINS depends on CONFIG_PM, thus there are no need to check explicity for it. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 4298a2bcd228..b910d0f6ff60 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -66,8 +66,6 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name) return genpd; } -#ifdef CONFIG_PM - struct generic_pm_domain *dev_to_genpd(struct device *dev) { if (IS_ERR_OR_NULL(dev->pm_domain)) @@ -281,8 +279,6 @@ int pm_genpd_name_poweron(const char *domain_name) return genpd ? pm_genpd_poweron(genpd) : -EINVAL; } -#endif /* CONFIG_PM */ - #ifdef CONFIG_PM_RUNTIME static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd, From d47e6464ae6c96735d4706f5cb0537fe717b6b00 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:24 +0200 Subject: [PATCH 08/32] PM / domains: Remove pm_genpd_syscore_switch() API The pm_genpd_syscore_poweroff() API and pm_genpd_syscore_poweron() API makes the pm_genpd_syscore_switch() API redundant. Moreover, since there are no active users, let's just remove it. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 17 ++++++++++++++--- include/linux/pm_domain.h | 16 ++++------------ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index b910d0f6ff60..601e35b2fa71 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1292,13 +1292,13 @@ static void pm_genpd_complete(struct device *dev) } /** - * pm_genpd_syscore_switch - Switch power during system core suspend or resume. + * genpd_syscore_switch - Switch power during system core suspend or resume. * @dev: Device that normally is marked as "always on" to switch power for. * * This routine may only be called during the system core (syscore) suspend or * resume phase for devices whose "always on" flags are set. */ -void pm_genpd_syscore_switch(struct device *dev, bool suspend) +static void genpd_syscore_switch(struct device *dev, bool suspend) { struct generic_pm_domain *genpd; @@ -1314,7 +1314,18 @@ void pm_genpd_syscore_switch(struct device *dev, bool suspend) genpd->suspended_count--; } } -EXPORT_SYMBOL_GPL(pm_genpd_syscore_switch); + +void pm_genpd_syscore_poweroff(struct device *dev) +{ + genpd_syscore_switch(dev, true); +} +EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweroff); + +void pm_genpd_syscore_poweron(struct device *dev) +{ + genpd_syscore_switch(dev, false); +} +EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); #else diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 360c94ceeebb..3997af691600 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -266,19 +266,11 @@ static inline void pm_genpd_poweroff_unused(void) {} #endif #ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP -extern void pm_genpd_syscore_switch(struct device *dev, bool suspend); +extern void pm_genpd_syscore_poweroff(struct device *dev); +extern void pm_genpd_syscore_poweron(struct device *dev); #else -static inline void pm_genpd_syscore_switch(struct device *dev, bool suspend) {} +static inline void pm_genpd_syscore_poweroff(struct device *dev) {} +static inline void pm_genpd_syscore_poweron(struct device *dev) {} #endif -static inline void pm_genpd_syscore_poweroff(struct device *dev) -{ - pm_genpd_syscore_switch(dev, true); -} - -static inline void pm_genpd_syscore_poweron(struct device *dev) -{ - pm_genpd_syscore_switch(dev, false); -} - #endif /* _LINUX_PM_DOMAIN_H */ From d971f0b0eaaf3f2086bf21bbd64f7ea7e2f28459 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:25 +0200 Subject: [PATCH 09/32] PM / domains: Remove genpd_queue_power_off_work() API There are no active users of this API. Let's remove it and if future needs shows up we could consider to have a get/put API instead. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 5 ++++- include/linux/pm_domain.h | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 601e35b2fa71..d71d0458d41f 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -422,7 +422,7 @@ static bool genpd_abort_poweroff(struct generic_pm_domain *genpd) * Queue up the execution of pm_genpd_poweroff() unless it's already been done * before. */ -void genpd_queue_power_off_work(struct generic_pm_domain *genpd) +static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) { queue_work(pm_wq, &genpd->power_off_work); } @@ -729,6 +729,9 @@ static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb, return NOTIFY_DONE; } +static inline void +genpd_queue_power_off_work(struct generic_pm_domain *genpd) {} + static inline void genpd_power_off_work_fn(struct work_struct *work) {} #define pm_genpd_runtime_suspend NULL diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 3997af691600..c19c90b839b8 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -258,10 +258,8 @@ static inline int pm_genpd_name_add_device(const char *domain_name, } #ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME -extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd); extern void pm_genpd_poweroff_unused(void); #else -static inline void genpd_queue_power_off_work(struct generic_pm_domain *gpd) {} static inline void pm_genpd_poweroff_unused(void) {} #endif From 2fe71dcdfd10d3f71bb559609a8ceda9f76b1e2c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:26 +0200 Subject: [PATCH 10/32] PM / domains: Add late_initcall to disable unused PM domains As default behavior let genpd at late init try to disable the unused PM domains. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index d71d0458d41f..cf4651a15a57 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -721,6 +721,13 @@ void pm_genpd_poweroff_unused(void) mutex_unlock(&gpd_list_lock); } +static int __init genpd_poweroff_unused(void) +{ + pm_genpd_poweroff_unused(); + return 0; +} +late_initcall(genpd_poweroff_unused); + #else static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb, From 0fcc455252d2ec766deb45bb735e32c7023811fe Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:27 +0200 Subject: [PATCH 11/32] ARM: exynos: Leave disabling of unused PM domains to genpd Since genpd at late init, will try to disable unused PM domains we don't need to do it from here as well. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- arch/arm/mach-exynos/exynos.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 6a24e111d6e1..b89e5f35db84 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -193,7 +193,6 @@ static void __init exynos_init_late(void) /* to be supported later */ return; - pm_genpd_poweroff_unused(); exynos_pm_init(); } From d40fce7e625dcecb196b1e4dba4dde19fdee919c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:28 +0200 Subject: [PATCH 12/32] ARM: s3c64xx: Leave disabling of unused PM domains to genpd Since genpd at late init, will try to disable unused PM domains we don't need to do it from the machine specific code as well. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- arch/arm/mach-s3c64xx/common.c | 5 ----- arch/arm/mach-s3c64xx/common.h | 7 ------- arch/arm/mach-s3c64xx/mach-anw6410.c | 1 - arch/arm/mach-s3c64xx/mach-crag6410.c | 1 - arch/arm/mach-s3c64xx/mach-hmt.c | 1 - arch/arm/mach-s3c64xx/mach-mini6410.c | 1 - arch/arm/mach-s3c64xx/mach-ncp.c | 1 - arch/arm/mach-s3c64xx/mach-real6410.c | 1 - arch/arm/mach-s3c64xx/mach-smartq5.c | 1 - arch/arm/mach-s3c64xx/mach-smartq7.c | 1 - arch/arm/mach-s3c64xx/mach-smdk6400.c | 1 - arch/arm/mach-s3c64xx/mach-smdk6410.c | 1 - arch/arm/mach-s3c64xx/pm.c | 7 ------- 13 files changed, 29 deletions(-) diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c index 5c45aae675b6..16547f2641a3 100644 --- a/arch/arm/mach-s3c64xx/common.c +++ b/arch/arm/mach-s3c64xx/common.c @@ -440,8 +440,3 @@ void s3c64xx_restart(enum reboot_mode mode, const char *cmd) /* if all else fails, or mode was for soft, jump to 0 */ soft_restart(0); } - -void __init s3c64xx_init_late(void) -{ - s3c64xx_pm_late_initcall(); -} diff --git a/arch/arm/mach-s3c64xx/common.h b/arch/arm/mach-s3c64xx/common.h index 7043e7a3a67e..9eb864412911 100644 --- a/arch/arm/mach-s3c64xx/common.h +++ b/arch/arm/mach-s3c64xx/common.h @@ -23,7 +23,6 @@ void s3c64xx_init_irq(u32 vic0, u32 vic1); void s3c64xx_init_io(struct map_desc *mach_desc, int size); void s3c64xx_restart(enum reboot_mode mode, const char *cmd); -void s3c64xx_init_late(void); void s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, unsigned long xusbxti_f, bool is_s3c6400, void __iomem *reg_base); @@ -52,12 +51,6 @@ extern void s3c6410_map_io(void); #define s3c6410_init NULL #endif -#ifdef CONFIG_PM -int __init s3c64xx_pm_late_initcall(void); -#else -static inline int s3c64xx_pm_late_initcall(void) { return 0; } -#endif - #ifdef CONFIG_S3C64XX_PL080 extern struct pl08x_platform_data s3c64xx_dma0_plat_data; extern struct pl08x_platform_data s3c64xx_dma1_plat_data; diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c index 60576dfbea8d..6224c67f5061 100644 --- a/arch/arm/mach-s3c64xx/mach-anw6410.c +++ b/arch/arm/mach-s3c64xx/mach-anw6410.c @@ -233,7 +233,6 @@ MACHINE_START(ANW6410, "A&W6410") .init_irq = s3c6410_init_irq, .map_io = anw6410_map_io, .init_machine = anw6410_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index fe116334afda..10b913baab28 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -857,7 +857,6 @@ MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410") .init_irq = s3c6410_init_irq, .map_io = crag6410_map_io, .init_machine = crag6410_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c index 19e8feb908fd..e4b087c58ee6 100644 --- a/arch/arm/mach-s3c64xx/mach-hmt.c +++ b/arch/arm/mach-s3c64xx/mach-hmt.c @@ -277,7 +277,6 @@ MACHINE_START(HMT, "Airgoo-HMT") .init_irq = s3c6410_init_irq, .map_io = hmt_map_io, .init_machine = hmt_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c index 9cbc07602ef3..ab61af50bfb9 100644 --- a/arch/arm/mach-s3c64xx/mach-mini6410.c +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c @@ -366,7 +366,6 @@ MACHINE_START(MINI6410, "MINI6410") .init_irq = s3c6410_init_irq, .map_io = mini6410_map_io, .init_machine = mini6410_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-ncp.c b/arch/arm/mach-s3c64xx/mach-ncp.c index 4bae7dc49eea..80cb1446f69f 100644 --- a/arch/arm/mach-s3c64xx/mach-ncp.c +++ b/arch/arm/mach-s3c64xx/mach-ncp.c @@ -103,7 +103,6 @@ MACHINE_START(NCP, "NCP") .init_irq = s3c6410_init_irq, .map_io = ncp_map_io, .init_machine = ncp_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index fbad2af1ef16..85fa9598b980 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c @@ -335,7 +335,6 @@ MACHINE_START(REAL6410, "REAL6410") .init_irq = s3c6410_init_irq, .map_io = real6410_map_io, .init_machine = real6410_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c index dec4c08e834f..33224ab36fac 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq5.c +++ b/arch/arm/mach-s3c64xx/mach-smartq5.c @@ -156,7 +156,6 @@ MACHINE_START(SMARTQ5, "SmartQ 5") .init_irq = s3c6410_init_irq, .map_io = smartq_map_io, .init_machine = smartq5_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c index 27b322069c7d..fc7fece22fb0 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq7.c +++ b/arch/arm/mach-s3c64xx/mach-smartq7.c @@ -172,7 +172,6 @@ MACHINE_START(SMARTQ7, "SmartQ 7") .init_irq = s3c6410_init_irq, .map_io = smartq_map_io, .init_machine = smartq7_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smdk6400.c b/arch/arm/mach-s3c64xx/mach-smdk6400.c index 910749768340..6f425126a735 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6400.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6400.c @@ -92,7 +92,6 @@ MACHINE_START(SMDK6400, "SMDK6400") .init_irq = s3c6400_init_irq, .map_io = smdk6400_map_io, .init_machine = smdk6400_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index 1dc86d76b530..661eb662d051 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -705,7 +705,6 @@ MACHINE_START(SMDK6410, "SMDK6410") .init_irq = s3c6410_init_irq, .map_io = smdk6410_map_io, .init_machine = smdk6410_machine_init, - .init_late = s3c64xx_init_late, .init_time = samsung_timer_init, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index 6b37694fa335..aaf7bea4032f 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -347,10 +347,3 @@ static __init int s3c64xx_pm_initcall(void) return 0; } arch_initcall(s3c64xx_pm_initcall); - -int __init s3c64xx_pm_late_initcall(void) -{ - pm_genpd_poweroff_unused(); - - return 0; -} From f1bf45c70ffdcf048d046da4ad4611315f1a15bf Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:29 +0200 Subject: [PATCH 13/32] drivers: sh: Leave disabling of unused PM domains to genpd Since genpd at late init, will try to disable unused PM domains we don't need to do it from here as well. Signed-off-by: Ulf Hansson Acked-by: Simon Horman Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/sh/pm_runtime.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c index 72f63817a1a0..fe2c2d595f59 100644 --- a/drivers/sh/pm_runtime.c +++ b/drivers/sh/pm_runtime.c @@ -75,8 +75,6 @@ static struct pm_clk_notifier_block platform_bus_notifier = { .con_ids = { NULL, }, }; -static bool default_pm_on; - static int __init sh_pm_runtime_init(void) { if (IS_ENABLED(CONFIG_ARCH_SHMOBILE_MULTI)) { @@ -96,16 +94,7 @@ static int __init sh_pm_runtime_init(void) return 0; } - default_pm_on = true; pm_clk_add_notifier(&platform_bus_type, &platform_bus_notifier); return 0; } core_initcall(sh_pm_runtime_init); - -static int __init sh_pm_runtime_late_init(void) -{ - if (default_pm_on) - pm_genpd_poweroff_unused(); - return 0; -} -late_initcall(sh_pm_runtime_late_init); From 0f574d4c3a7a325cbbef28ee738dedca9851e957 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:30 +0200 Subject: [PATCH 14/32] PM / domains: Remove default_stop_ok() API There are currently no need to export default_stop_ok() as an API, instead let's keep it local to the PM domain governor. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain_governor.c | 7 ++----- include/linux/pm_domain.h | 6 ------ 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index a089e3bcdfbc..d88a62e104d4 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -42,7 +42,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data) * default_stop_ok - Default PM domain governor routine for stopping devices. * @dev: Device to check. */ -bool default_stop_ok(struct device *dev) +static bool default_stop_ok(struct device *dev) { struct gpd_timing_data *td = &dev_gpd_data(dev)->td; unsigned long flags; @@ -229,10 +229,7 @@ static bool always_on_power_down_ok(struct dev_pm_domain *domain) #else /* !CONFIG_PM_RUNTIME */ -bool default_stop_ok(struct device *dev) -{ - return false; -} +static inline bool default_stop_ok(struct device *dev) { return false; } #define default_power_down_ok NULL #define always_on_power_down_ok NULL diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index c19c90b839b8..3b59f296e6ec 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -151,8 +151,6 @@ extern void pm_genpd_init(struct generic_pm_domain *genpd, extern int pm_genpd_poweron(struct generic_pm_domain *genpd); extern int pm_genpd_name_poweron(const char *domain_name); -extern bool default_stop_ok(struct device *dev); - extern struct dev_power_governor pm_domain_always_on_gov; #else @@ -231,10 +229,6 @@ static inline int pm_genpd_name_poweron(const char *domain_name) { return -ENOSYS; } -static inline bool default_stop_ok(struct device *dev) -{ - return false; -} #define simple_qos_governor NULL #define pm_domain_always_on_gov NULL #endif From ae3c511c2d72161b11e93866203b59a3a37dfac7 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:31 +0200 Subject: [PATCH 15/32] PM / domains: Keep declaration of dev_power_governors together This is a pure code cleanup in the header file for the PM domain. No functional change. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- include/linux/pm_domain.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 3b59f296e6ec..aa03586c94a2 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -117,8 +117,6 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) return to_gpd_data(dev->power.subsys_data->domain_data); } -extern struct dev_power_governor simple_qos_governor; - extern struct generic_pm_domain *dev_to_genpd(struct device *dev); extern int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, @@ -151,6 +149,7 @@ extern void pm_genpd_init(struct generic_pm_domain *genpd, extern int pm_genpd_poweron(struct generic_pm_domain *genpd); extern int pm_genpd_name_poweron(const char *domain_name); +extern struct dev_power_governor simple_qos_governor; extern struct dev_power_governor pm_domain_always_on_gov; #else From 12e10bb60be2a4259373c05dfbf8f71b87a17421 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 16 Sep 2014 21:59:39 +0200 Subject: [PATCH 16/32] PM / domains: Spelling s/domian/domain/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index cf4651a15a57..e6a11ca3ce26 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1833,7 +1833,7 @@ int pm_genpd_name_detach_cpuidle(const char *name) /* Default device callbacks for generic PM domains. */ /** - * pm_genpd_default_save_state - Default "save device state" for PM domians. + * pm_genpd_default_save_state - Default "save device state" for PM domains. * @dev: Device to handle. */ static int pm_genpd_default_save_state(struct device *dev) @@ -1856,7 +1856,7 @@ static int pm_genpd_default_save_state(struct device *dev) } /** - * pm_genpd_default_restore_state - Default PM domians "restore device state". + * pm_genpd_default_restore_state - Default PM domains "restore device state". * @dev: Device to handle. */ static int pm_genpd_default_restore_state(struct device *dev) From c3099a5294f2c7266234e8ea35cbffc20a41aa9a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:34 +0200 Subject: [PATCH 17/32] PM / Domains: Add a detach callback to the struct dev_pm_domain The intent of this callback is to simplify detachment of devices from their PM domains. Further patches will show the benefit. Signed-off-by: Ulf Hansson Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- include/linux/pm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pm.h b/include/linux/pm.h index 72c0fe098a27..1022ba1eb4de 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -619,6 +619,7 @@ extern int dev_pm_put_subsys_data(struct device *dev); */ struct dev_pm_domain { struct dev_pm_ops ops; + void (*detach)(struct device *dev, bool power_off); }; /* From 86f1e15f5646b4855bd77025c950239650c4843e Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:35 +0200 Subject: [PATCH 18/32] ACPI / PM: Assign the ->detach() callback when attaching the PM domain As as preparation to simplify the detachment of devices from their PM domains, we assign the ->detach() callback to genpd_dev_pm_detach(). Signed-off-by: Ulf Hansson Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 67075f800e34..eec5ed5be949 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1072,6 +1072,8 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) acpi_dev_pm_full_power(adev); acpi_device_wakeup(adev, ACPI_STATE_S0, false); } + + dev->pm_domain->detach = acpi_dev_pm_detach; return 0; } EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); From aa42240ab2544a8bcb2efb400193826f57f3175e Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Fri, 19 Sep 2014 20:27:36 +0200 Subject: [PATCH 19/32] PM / Domains: Add generic OF-based PM domain look-up This patch introduces generic code to perform PM domain look-up using device tree and automatically bind devices to their PM domains. Generic device tree bindings are introduced to specify PM domains of devices in their device tree nodes. Backwards compatibility with legacy Samsung-specific PM domain bindings is provided, but for now the new code is not compiled when CONFIG_ARCH_EXYNOS is selected to avoid collision with legacy code. This will change as soon as the Exynos PM domain code gets converted to use the generic framework in further patch. This patch was originally submitted by Tomasz Figa when he was employed by Samsung. Link: http://marc.info/?l=linux-pm&m=139955349702152&w=2 Signed-off-by: Ulf Hansson Acked-by: Rob Herring Tested-by: Philipp Zabel Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- .../bindings/power/power_domain.txt | 49 +++ drivers/base/power/domain.c | 289 ++++++++++++++++++ include/linux/pm_domain.h | 52 ++++ kernel/power/Kconfig | 4 + 4 files changed, 394 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/power_domain.txt diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt new file mode 100644 index 000000000000..98c16672ab5f --- /dev/null +++ b/Documentation/devicetree/bindings/power/power_domain.txt @@ -0,0 +1,49 @@ +* Generic PM domains + +System on chip designs are often divided into multiple PM domains that can be +used for power gating of selected IP blocks for power saving by reduced leakage +current. + +This device tree binding can be used to bind PM domain consumer devices with +their PM domains provided by PM domain providers. A PM domain provider can be +represented by any node in the device tree and can provide one or more PM +domains. A consumer node can refer to the provider by a phandle and a set of +phandle arguments (so called PM domain specifiers) of length specified by the +#power-domain-cells property in the PM domain provider node. + +==PM domain providers== + +Required properties: + - #power-domain-cells : Number of cells in a PM domain specifier; + Typically 0 for nodes representing a single PM domain and 1 for nodes + providing multiple PM domains (e.g. power controllers), but can be any value + as specified by device tree binding documentation of particular provider. + +Example: + + power: power-controller@12340000 { + compatible = "foo,power-controller"; + reg = <0x12340000 0x1000>; + #power-domain-cells = <1>; + }; + +The node above defines a power controller that is a PM domain provider and +expects one cell as its phandle argument. + +==PM domain consumers== + +Required properties: + - power-domains : A phandle and PM domain specifier as defined by bindings of + the power controller specified by phandle. + +Example: + + leaky-device@12350000 { + compatible = "foo,i-leak-current"; + reg = <0x12350000 0x1000>; + power-domains = <&power 0>; + }; + +The node above defines a typical PM domain consumer device, which is located +inside a PM domain with index 0 of a power controller represented by a node +with the label "power". diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index e6a11ca3ce26..a3d41a883d83 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -1933,3 +1934,291 @@ void pm_genpd_init(struct generic_pm_domain *genpd, list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); } + +#ifdef CONFIG_PM_GENERIC_DOMAINS_OF +/* + * Device Tree based PM domain providers. + * + * The code below implements generic device tree based PM domain providers that + * bind device tree nodes with generic PM domains registered in the system. + * + * Any driver that registers generic PM domains and needs to support binding of + * devices to these domains is supposed to register a PM domain provider, which + * maps a PM domain specifier retrieved from the device tree to a PM domain. + * + * Two simple mapping functions have been provided for convenience: + * - __of_genpd_xlate_simple() for 1:1 device tree node to PM domain mapping. + * - __of_genpd_xlate_onecell() for mapping of multiple PM domains per node by + * index. + */ + +/** + * struct of_genpd_provider - PM domain provider registration structure + * @link: Entry in global list of PM domain providers + * @node: Pointer to device tree node of PM domain provider + * @xlate: Provider-specific xlate callback mapping a set of specifier cells + * into a PM domain. + * @data: context pointer to be passed into @xlate callback + */ +struct of_genpd_provider { + struct list_head link; + struct device_node *node; + genpd_xlate_t xlate; + void *data; +}; + +/* List of registered PM domain providers. */ +static LIST_HEAD(of_genpd_providers); +/* Mutex to protect the list above. */ +static DEFINE_MUTEX(of_genpd_mutex); + +/** + * __of_genpd_xlate_simple() - Xlate function for direct node-domain mapping + * @genpdspec: OF phandle args to map into a PM domain + * @data: xlate function private data - pointer to struct generic_pm_domain + * + * This is a generic xlate function that can be used to model PM domains that + * have their own device tree nodes. The private data of xlate function needs + * to be a valid pointer to struct generic_pm_domain. + */ +struct generic_pm_domain *__of_genpd_xlate_simple( + struct of_phandle_args *genpdspec, + void *data) +{ + if (genpdspec->args_count != 0) + return ERR_PTR(-EINVAL); + return data; +} +EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple); + +/** + * __of_genpd_xlate_onecell() - Xlate function using a single index. + * @genpdspec: OF phandle args to map into a PM domain + * @data: xlate function private data - pointer to struct genpd_onecell_data + * + * This is a generic xlate function that can be used to model simple PM domain + * controllers that have one device tree node and provide multiple PM domains. + * A single cell is used as an index into an array of PM domains specified in + * the genpd_onecell_data struct when registering the provider. + */ +struct generic_pm_domain *__of_genpd_xlate_onecell( + struct of_phandle_args *genpdspec, + void *data) +{ + struct genpd_onecell_data *genpd_data = data; + unsigned int idx = genpdspec->args[0]; + + if (genpdspec->args_count != 1) + return ERR_PTR(-EINVAL); + + if (idx >= genpd_data->num_domains) { + pr_err("%s: invalid domain index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + + if (!genpd_data->domains[idx]) + return ERR_PTR(-ENOENT); + + return genpd_data->domains[idx]; +} +EXPORT_SYMBOL_GPL(__of_genpd_xlate_onecell); + +/** + * __of_genpd_add_provider() - Register a PM domain provider for a node + * @np: Device node pointer associated with the PM domain provider. + * @xlate: Callback for decoding PM domain from phandle arguments. + * @data: Context pointer for @xlate callback. + */ +int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, + void *data) +{ + struct of_genpd_provider *cp; + + cp = kzalloc(sizeof(*cp), GFP_KERNEL); + if (!cp) + return -ENOMEM; + + cp->node = of_node_get(np); + cp->data = data; + cp->xlate = xlate; + + mutex_lock(&of_genpd_mutex); + list_add(&cp->link, &of_genpd_providers); + mutex_unlock(&of_genpd_mutex); + pr_debug("Added domain provider from %s\n", np->full_name); + + return 0; +} +EXPORT_SYMBOL_GPL(__of_genpd_add_provider); + +/** + * of_genpd_del_provider() - Remove a previously registered PM domain provider + * @np: Device node pointer associated with the PM domain provider + */ +void of_genpd_del_provider(struct device_node *np) +{ + struct of_genpd_provider *cp; + + mutex_lock(&of_genpd_mutex); + list_for_each_entry(cp, &of_genpd_providers, link) { + if (cp->node == np) { + list_del(&cp->link); + of_node_put(cp->node); + kfree(cp); + break; + } + } + mutex_unlock(&of_genpd_mutex); +} +EXPORT_SYMBOL_GPL(of_genpd_del_provider); + +/** + * of_genpd_get_from_provider() - Look-up PM domain + * @genpdspec: OF phandle args to use for look-up + * + * Looks for a PM domain provider under the node specified by @genpdspec and if + * found, uses xlate function of the provider to map phandle args to a PM + * domain. + * + * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR() + * on failure. + */ +static struct generic_pm_domain *of_genpd_get_from_provider( + struct of_phandle_args *genpdspec) +{ + struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); + struct of_genpd_provider *provider; + + mutex_lock(&of_genpd_mutex); + + /* Check if we have such a provider in our array */ + list_for_each_entry(provider, &of_genpd_providers, link) { + if (provider->node == genpdspec->np) + genpd = provider->xlate(genpdspec, provider->data); + if (!IS_ERR(genpd)) + break; + } + + mutex_unlock(&of_genpd_mutex); + + return genpd; +} + +/** + * genpd_dev_pm_detach - Detach a device from its PM domain. + * @dev: Device to attach. + * @power_off: Currently not used + * + * Try to locate a corresponding generic PM domain, which the device was + * attached to previously. If such is found, the device is detached from it. + */ +static void genpd_dev_pm_detach(struct device *dev, bool power_off) +{ + struct generic_pm_domain *pd = NULL, *gpd; + int ret = 0; + + if (!dev->pm_domain) + return; + + mutex_lock(&gpd_list_lock); + list_for_each_entry(gpd, &gpd_list, gpd_list_node) { + if (&gpd->domain == dev->pm_domain) { + pd = gpd; + break; + } + } + mutex_unlock(&gpd_list_lock); + + if (!pd) + return; + + dev_dbg(dev, "removing from PM domain %s\n", pd->name); + + while (1) { + ret = pm_genpd_remove_device(pd, dev); + if (ret != -EAGAIN) + break; + cond_resched(); + } + + if (ret < 0) { + dev_err(dev, "failed to remove from PM domain %s: %d", + pd->name, ret); + return; + } + + /* Check if PM domain can be powered off after removing this device. */ + genpd_queue_power_off_work(pd); +} + +/** + * genpd_dev_pm_attach - Attach a device to its PM domain using DT. + * @dev: Device to attach. + * + * Parse device's OF node to find a PM domain specifier. If such is found, + * attaches the device to retrieved pm_domain ops. + * + * Both generic and legacy Samsung-specific DT bindings are supported to keep + * backwards compatibility with existing DTBs. + * + * Returns 0 on successfully attached PM domain or negative error code. + */ +int genpd_dev_pm_attach(struct device *dev) +{ + struct of_phandle_args pd_args; + struct generic_pm_domain *pd; + int ret; + + if (!dev->of_node) + return -ENODEV; + + if (dev->pm_domain) + return -EEXIST; + + ret = of_parse_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells", 0, &pd_args); + if (ret < 0) { + if (ret != -ENOENT) + return ret; + + /* + * Try legacy Samsung-specific bindings + * (for backwards compatibility of DT ABI) + */ + pd_args.args_count = 0; + pd_args.np = of_parse_phandle(dev->of_node, + "samsung,power-domain", 0); + if (!pd_args.np) + return -ENOENT; + } + + pd = of_genpd_get_from_provider(&pd_args); + if (IS_ERR(pd)) { + dev_dbg(dev, "%s() failed to find PM domain: %ld\n", + __func__, PTR_ERR(pd)); + of_node_put(dev->of_node); + return PTR_ERR(pd); + } + + dev_dbg(dev, "adding to PM domain %s\n", pd->name); + + while (1) { + ret = pm_genpd_add_device(pd, dev); + if (ret != -EAGAIN) + break; + cond_resched(); + } + + if (ret < 0) { + dev_err(dev, "failed to add to PM domain %s: %d", + pd->name, ret); + of_node_put(dev->of_node); + return ret; + } + + dev->pm_domain->detach = genpd_dev_pm_detach; + + return 0; +} +EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); +#endif diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index aa03586c94a2..292079d8da6b 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -264,4 +264,56 @@ static inline void pm_genpd_syscore_poweroff(struct device *dev) {} static inline void pm_genpd_syscore_poweron(struct device *dev) {} #endif +/* OF PM domain providers */ +struct of_device_id; + +struct genpd_onecell_data { + struct generic_pm_domain **domains; + unsigned int num_domains; +}; + +typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, + void *data); + +#ifdef CONFIG_PM_GENERIC_DOMAINS_OF +int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, + void *data); +void of_genpd_del_provider(struct device_node *np); + +struct generic_pm_domain *__of_genpd_xlate_simple( + struct of_phandle_args *genpdspec, + void *data); +struct generic_pm_domain *__of_genpd_xlate_onecell( + struct of_phandle_args *genpdspec, + void *data); + +int genpd_dev_pm_attach(struct device *dev); +#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */ +static inline int __of_genpd_add_provider(struct device_node *np, + genpd_xlate_t xlate, void *data) +{ + return 0; +} +static inline void of_genpd_del_provider(struct device_node *np) {} + +#define __of_genpd_xlate_simple NULL +#define __of_genpd_xlate_onecell NULL + +static inline int genpd_dev_pm_attach(struct device *dev) +{ + return -ENODEV; +} +#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ + +static inline int of_genpd_add_provider_simple(struct device_node *np, + struct generic_pm_domain *genpd) +{ + return __of_genpd_add_provider(np, __of_genpd_xlate_simple, genpd); +} +static inline int of_genpd_add_provider_onecell(struct device_node *np, + struct genpd_onecell_data *data) +{ + return __of_genpd_add_provider(np, __of_genpd_xlate_onecell, data); +} + #endif /* _LINUX_PM_DOMAIN_H */ diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index e4e4121fa327..897619b11fb2 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -302,6 +302,10 @@ config PM_GENERIC_DOMAINS_RUNTIME def_bool y depends on PM_RUNTIME && PM_GENERIC_DOMAINS +config PM_GENERIC_DOMAINS_OF + def_bool y + depends on PM_GENERIC_DOMAINS && OF && !ARCH_EXYNOS + config CPU_PM bool depends on SUSPEND || CPU_IDLE From 46420dd73b800f87a19af13af5883855cf38cb08 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:37 +0200 Subject: [PATCH 20/32] PM / Domains: Add APIs to attach/detach a PM domain for a device To maintain scalability let's add common methods to attach and detach a PM domain for a device, dev_pm_domain_attach|detach(). Typically dev_pm_domain_attach() shall be invoked from subsystem level code at the probe phase to try to attach a device to its PM domain. The reversed actions may be done a the remove phase and then by invoking dev_pm_domain_detach(). When attachment succeeds, the attach function should assign its corresponding detach function to a new ->detach() callback added in the struct dev_pm_domain. Signed-off-by: Ulf Hansson Tested-by: Philipp Zabel Reviewed-by: Kevin Hilman Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/base/power/common.c | 52 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 11 ++++++++ 2 files changed, 63 insertions(+) diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index df2e5eeaeb05..b0f138806bbc 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include /** * dev_pm_get_subsys_data - Create or refcount power.subsys_data for device. @@ -82,3 +84,53 @@ int dev_pm_put_subsys_data(struct device *dev) return ret; } EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data); + +/** + * dev_pm_domain_attach - Attach a device to its PM domain. + * @dev: Device to attach. + * @power_on: Used to indicate whether we should power on the device. + * + * The @dev may only be attached to a single PM domain. By iterating through + * the available alternatives we try to find a valid PM domain for the device. + * As attachment succeeds, the ->detach() callback in the struct dev_pm_domain + * should be assigned by the corresponding attach function. + * + * This function should typically be invoked from subsystem level code during + * the probe phase. Especially for those that holds devices which requires + * power management through PM domains. + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + * + * Returns 0 on successfully attached PM domain or negative error code. + */ +int dev_pm_domain_attach(struct device *dev, bool power_on) +{ + int ret; + + ret = acpi_dev_pm_attach(dev, power_on); + if (ret) + ret = genpd_dev_pm_attach(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_domain_attach); + +/** + * dev_pm_domain_detach - Detach a device from its PM domain. + * @dev: Device to attach. + * @power_off: Used to indicate whether we should power off the device. + * + * This functions will reverse the actions from dev_pm_domain_attach() and thus + * try to detach the @dev from its PM domain. Typically it should be invoked + * from subsystem level code during the remove phase. + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + */ +void dev_pm_domain_detach(struct device *dev, bool power_off) +{ + if (dev->pm_domain && dev->pm_domain->detach) + dev->pm_domain->detach(dev, power_off); +} +EXPORT_SYMBOL_GPL(dev_pm_domain_detach); diff --git a/include/linux/pm.h b/include/linux/pm.h index 1022ba1eb4de..c4cbf485a5d6 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -622,6 +622,17 @@ struct dev_pm_domain { void (*detach)(struct device *dev, bool power_off); }; +#ifdef CONFIG_PM +extern int dev_pm_domain_attach(struct device *dev, bool power_on); +extern void dev_pm_domain_detach(struct device *dev, bool power_off); +#else +static inline int dev_pm_domain_attach(struct device *dev, bool power_on) +{ + return -ENODEV; +} +static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {} +#endif + /* * The PM_EVENT_ messages are also used by drivers implementing the legacy * suspend framework, based on the ->suspend() and ->resume() callbacks common From cb51841397e8e5714cf82a7f91053f6e1fb80d1f Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:38 +0200 Subject: [PATCH 21/32] drivercore / platform: Convert to dev_pm_domain_attach|detach() Previously only the ACPI PM domain was supported by the platform bus. Let's convert to the common attach/detach functions for PM domains, which currently means we are extending the support to include the generic PM domain as well. Signed-off-by: Ulf Hansson Tested-by: Philipp Zabel Reviewed-by: Kevin Hilman Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/base/platform.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index ab4f4ce02722..904be3dc0908 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -506,11 +506,12 @@ static int platform_drv_probe(struct device *_dev) if (ret < 0) return ret; - acpi_dev_pm_attach(_dev, true); - - ret = drv->probe(dev); - if (ret) - acpi_dev_pm_detach(_dev, true); + ret = dev_pm_domain_attach(_dev, true); + if (ret != -EPROBE_DEFER) { + ret = drv->probe(dev); + if (ret) + dev_pm_domain_detach(_dev, true); + } if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { dev_warn(_dev, "probe deferral not supported\n"); @@ -532,7 +533,7 @@ static int platform_drv_remove(struct device *_dev) int ret; ret = drv->remove(dev); - acpi_dev_pm_detach(_dev, true); + dev_pm_domain_detach(_dev, true); return ret; } @@ -543,7 +544,7 @@ static void platform_drv_shutdown(struct device *_dev) struct platform_device *dev = to_platform_device(_dev); drv->shutdown(dev); - acpi_dev_pm_detach(_dev, true); + dev_pm_domain_detach(_dev, true); } /** From e09b0d4e9b03e08f47ad53e3c509db2cf8f1dc9c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:39 +0200 Subject: [PATCH 22/32] i2c: core: Convert to dev_pm_domain_attach|detach() Previously only the ACPI PM domain was supported by the i2c bus. Let's convert to the common attach/detach functions for PM domains, which currently means we are extending the support to include the generic PM domain as well. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Acked-by: Wolfram Sang Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/i2c/i2c-core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 632057a44615..3cd8f11f1b5f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -279,10 +279,13 @@ static int i2c_device_probe(struct device *dev) if (status < 0) return status; - acpi_dev_pm_attach(&client->dev, true); - status = driver->probe(client, i2c_match_id(driver->id_table, client)); - if (status) - acpi_dev_pm_detach(&client->dev, true); + status = dev_pm_domain_attach(&client->dev, true); + if (status != -EPROBE_DEFER) { + status = driver->probe(client, i2c_match_id(driver->id_table, + client)); + if (status) + dev_pm_domain_detach(&client->dev, true); + } return status; } @@ -302,7 +305,7 @@ static int i2c_device_remove(struct device *dev) status = driver->remove(client); } - acpi_dev_pm_detach(&client->dev, true); + dev_pm_domain_detach(&client->dev, true); return status; } From 397a0253527a578fa036d3438ad4909c65d63166 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:40 +0200 Subject: [PATCH 23/32] mmc: sdio: Convert to dev_pm_domain_attach|detach() Previously only the ACPI PM domain was supported by the sdio bus. Let's convert to the common attach/detach functions for PM domains, which currently means we are extending the support to include the generic PM domain as well. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/mmc/core/sdio_bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 4fa8fef9147f..1df0fc63c17c 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -315,7 +315,7 @@ int sdio_add_func(struct sdio_func *func) ret = device_add(&func->dev); if (ret == 0) { sdio_func_set_present(func); - acpi_dev_pm_attach(&func->dev, false); + dev_pm_domain_attach(&func->dev, false); } return ret; @@ -332,7 +332,7 @@ void sdio_remove_func(struct sdio_func *func) if (!sdio_func_present(func)) return; - acpi_dev_pm_detach(&func->dev, false); + dev_pm_domain_detach(&func->dev, false); device_del(&func->dev); put_device(&func->dev); } From 676e7c257a339b44b8a613be145b22b85cf2ffc4 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:41 +0200 Subject: [PATCH 24/32] spi: core: Convert to dev_pm_domain_attach|detach() Previously only the ACPI PM domain was supported by the spi bus. Let's convert to the common attach/detach functions for PM domains, which currently means we are extending the support to include the generic PM domain as well. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/spi/spi.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ca935df80c88..72a0beb1fafa 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -264,10 +264,12 @@ static int spi_drv_probe(struct device *dev) if (ret) return ret; - acpi_dev_pm_attach(dev, true); - ret = sdrv->probe(to_spi_device(dev)); - if (ret) - acpi_dev_pm_detach(dev, true); + ret = dev_pm_domain_attach(dev, true); + if (ret != -EPROBE_DEFER) { + ret = sdrv->probe(to_spi_device(dev)); + if (ret) + dev_pm_domain_detach(dev, true); + } return ret; } @@ -278,7 +280,7 @@ static int spi_drv_remove(struct device *dev) int ret; ret = sdrv->remove(to_spi_device(dev)); - acpi_dev_pm_detach(dev, true); + dev_pm_domain_detach(dev, true); return ret; } From 207f1a2d294e3781b56d1acecd48aaa3b4b7b2ad Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:42 +0200 Subject: [PATCH 25/32] amba: Add support for attach/detach of PM domains AMBA devices may on some SoCs resides in PM domains. To be able to manage these devices from there, let's try to attach devices to their corresponding PM domain during the probe phase. To reverse these actions at the remove phase, we try to detach the device from its PM domain. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/amba/bus.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 3cf61a127ee5..8f5239377f91 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -182,9 +182,15 @@ static int amba_probe(struct device *dev) int ret; do { + ret = dev_pm_domain_attach(dev, true); + if (ret == -EPROBE_DEFER) + break; + ret = amba_get_enable_pclk(pcdev); - if (ret) + if (ret) { + dev_pm_domain_detach(dev, true); break; + } pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); @@ -199,6 +205,7 @@ static int amba_probe(struct device *dev) pm_runtime_put_noidle(dev); amba_put_disable_pclk(pcdev); + dev_pm_domain_detach(dev, true); } while (0); return ret; @@ -220,6 +227,7 @@ static int amba_remove(struct device *dev) pm_runtime_put_noidle(dev); amba_put_disable_pclk(pcdev); + dev_pm_domain_detach(dev, true); return ret; } From a4a8c2c4962bb655e7152c53a0eb6ca31c47f159 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Fri, 19 Sep 2014 20:27:43 +0200 Subject: [PATCH 26/32] ARM: exynos: Move to generic PM domain DT bindings This patch moves Exynos PM domain code to use the new generic PM domain look-up framework introduced in previous patches, thus also allowing the new code to be compiled with CONFIG_ARCH_EXYNOS. This patch was originally submitted by Tomasz Figa when he was employed by Samsung. Link: http://marc.info/?l=linux-pm&m=139955336002083&w=2 Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- .../bindings/arm/exynos/power_domain.txt | 13 ++-- arch/arm/mach-exynos/pm_domains.c | 78 +------------------ kernel/power/Kconfig | 2 +- 3 files changed, 8 insertions(+), 85 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt index 8b4f7b7fe88b..abde1ea8a119 100644 --- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt +++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt @@ -8,6 +8,8 @@ Required Properties: * samsung,exynos4210-pd - for exynos4210 type power domain. - reg: physical base address of the controller and length of memory mapped region. +- #power-domain-cells: number of cells in power domain specifier; + must be 0. Optional Properties: - clocks: List of clock handles. The parent clocks of the input clocks to the @@ -29,6 +31,7 @@ Example: lcd0: power-domain-lcd0 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C00 0x10>; + #power-domain-cells = <0>; }; mfc_pd: power-domain@10044060 { @@ -37,12 +40,8 @@ Example: clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>, <&clock CLK_MOUT_USER_ACLK333>; clock-names = "oscclk", "pclk0", "clk0"; + #power-domain-cells = <0>; }; -Example of the node using power domain: - - node { - /* ... */ - samsung,power-domain = <&lcd0>; - /* ... */ - }; +See Documentation/devicetree/bindings/power/power_domain.txt for description +of consumer-side bindings. diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index fd76e1b5a471..20f267121b3e 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -105,78 +105,6 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain) return exynos_pd_power(domain, false); } -static void exynos_add_device_to_domain(struct exynos_pm_domain *pd, - struct device *dev) -{ - int ret; - - dev_dbg(dev, "adding to power domain %s\n", pd->pd.name); - - while (1) { - ret = pm_genpd_add_device(&pd->pd, dev); - if (ret != -EAGAIN) - break; - cond_resched(); - } - - pm_genpd_dev_need_restore(dev, true); -} - -static void exynos_remove_device_from_domain(struct device *dev) -{ - struct generic_pm_domain *genpd = dev_to_genpd(dev); - int ret; - - dev_dbg(dev, "removing from power domain %s\n", genpd->name); - - while (1) { - ret = pm_genpd_remove_device(genpd, dev); - if (ret != -EAGAIN) - break; - cond_resched(); - } -} - -static void exynos_read_domain_from_dt(struct device *dev) -{ - struct platform_device *pd_pdev; - struct exynos_pm_domain *pd; - struct device_node *node; - - node = of_parse_phandle(dev->of_node, "samsung,power-domain", 0); - if (!node) - return; - pd_pdev = of_find_device_by_node(node); - if (!pd_pdev) - return; - pd = platform_get_drvdata(pd_pdev); - exynos_add_device_to_domain(pd, dev); -} - -static int exynos_pm_notifier_call(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct device *dev = data; - - switch (event) { - case BUS_NOTIFY_BIND_DRIVER: - if (dev->of_node) - exynos_read_domain_from_dt(dev); - - break; - - case BUS_NOTIFY_UNBOUND_DRIVER: - exynos_remove_device_from_domain(dev); - - break; - } - return NOTIFY_DONE; -} - -static struct notifier_block platform_nb = { - .notifier_call = exynos_pm_notifier_call, -}; - static __init int exynos4_pm_init_power_domain(void) { struct platform_device *pdev; @@ -202,7 +130,6 @@ static __init int exynos4_pm_init_power_domain(void) pd->base = of_iomap(np, 0); pd->pd.power_off = exynos_pd_power_off; pd->pd.power_on = exynos_pd_power_on; - pd->pd.of_node = np; pd->oscclk = clk_get(dev, "oscclk"); if (IS_ERR(pd->oscclk)) @@ -228,15 +155,12 @@ static __init int exynos4_pm_init_power_domain(void) clk_put(pd->oscclk); no_clk: - platform_set_drvdata(pdev, pd); - on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN; pm_genpd_init(&pd->pd, NULL, !on); + of_genpd_add_provider_simple(np, &pd->pd); } - bus_register_notifier(&platform_bus_type, &platform_nb); - return 0; } arch_initcall(exynos4_pm_init_power_domain); diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 897619b11fb2..bbef57f5bdfd 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -304,7 +304,7 @@ config PM_GENERIC_DOMAINS_RUNTIME config PM_GENERIC_DOMAINS_OF def_bool y - depends on PM_GENERIC_DOMAINS && OF && !ARCH_EXYNOS + depends on PM_GENERIC_DOMAINS && OF config CPU_PM bool From 91d66cd27f5fd8a3bca4621a3505c9067925478d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:44 +0200 Subject: [PATCH 27/32] ACPI / PM: Convert acpi_dev_pm_detach() into a static function The ->detach() callback for the PM domain has now been fully adopted, thus there no users left of the acpi_dev_pm_detach() API. This allow us to convert it into a static function. Signed-off-by: Ulf Hansson Reviewed-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/device_pm.c | 69 ++++++++++++++++++++-------------------- include/linux/acpi.h | 2 -- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index eec5ed5be949..bea6896be122 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1040,6 +1040,40 @@ static struct dev_pm_domain acpi_general_pm_domain = { }, }; +/** + * acpi_dev_pm_detach - Remove ACPI power management from the device. + * @dev: Device to take care of. + * @power_off: Whether or not to try to remove power from the device. + * + * Remove the device from the general ACPI PM domain and remove its wakeup + * notifier. If @power_off is set, additionally remove power from the device if + * possible. + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + */ +static void acpi_dev_pm_detach(struct device *dev, bool power_off) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + + if (adev && dev->pm_domain == &acpi_general_pm_domain) { + dev->pm_domain = NULL; + acpi_remove_pm_notifier(adev); + if (power_off) { + /* + * If the device's PM QoS resume latency limit or flags + * have been exposed to user space, they have to be + * hidden at this point, so that they don't affect the + * choice of the low-power state to put the device into. + */ + dev_pm_qos_hide_latency_limit(dev); + dev_pm_qos_hide_flags(dev); + acpi_device_wakeup(adev, ACPI_STATE_S0, false); + acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); + } + } +} + /** * acpi_dev_pm_attach - Prepare device for ACPI power management. * @dev: Device to prepare. @@ -1077,39 +1111,4 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) return 0; } EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); - -/** - * acpi_dev_pm_detach - Remove ACPI power management from the device. - * @dev: Device to take care of. - * @power_off: Whether or not to try to remove power from the device. - * - * Remove the device from the general ACPI PM domain and remove its wakeup - * notifier. If @power_off is set, additionally remove power from the device if - * possible. - * - * Callers must ensure proper synchronization of this function with power - * management callbacks. - */ -void acpi_dev_pm_detach(struct device *dev, bool power_off) -{ - struct acpi_device *adev = ACPI_COMPANION(dev); - - if (adev && dev->pm_domain == &acpi_general_pm_domain) { - dev->pm_domain = NULL; - acpi_remove_pm_notifier(adev); - if (power_off) { - /* - * If the device's PM QoS resume latency limit or flags - * have been exposed to user space, they have to be - * hidden at this point, so that they don't affect the - * choice of the low-power state to put the device into. - */ - dev_pm_qos_hide_latency_limit(dev); - dev_pm_qos_hide_flags(dev); - acpi_device_wakeup(adev, ACPI_STATE_S0, false); - acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); - } - } -} -EXPORT_SYMBOL_GPL(acpi_dev_pm_detach); #endif /* CONFIG_PM */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 807cbc46d73e..b7926bb9b444 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -587,7 +587,6 @@ static inline int acpi_subsys_freeze(struct device *dev) { return 0; } #if defined(CONFIG_ACPI) && defined(CONFIG_PM) struct acpi_device *acpi_dev_pm_get_node(struct device *dev); int acpi_dev_pm_attach(struct device *dev, bool power_on); -void acpi_dev_pm_detach(struct device *dev, bool power_off); #else static inline struct acpi_device *acpi_dev_pm_get_node(struct device *dev) { @@ -597,7 +596,6 @@ static inline int acpi_dev_pm_attach(struct device *dev, bool power_on) { return -ENODEV; } -static inline void acpi_dev_pm_detach(struct device *dev, bool power_off) {} #endif #ifdef CONFIG_ACPI From 2bd5306a8764d9496f3e3d90c4e608c247fcfd31 Mon Sep 17 00:00:00 2001 From: Maciej Matraszek Date: Mon, 15 Sep 2014 13:09:10 +0200 Subject: [PATCH 28/32] PM / Domains: add debugfs listing of struct generic_pm_domain-s Add /sys/kernel/debug/pm_genpd/pm_genpd_summary file, which lists power domains in the system, their statuses and attached devices, resembling /sys/kernel/debug/clk/clk_summary. Currently it is impossible to inspect (from userland) whether a power domain is on or off. And, if it is on, which device blocks it from powering down. This change allows developers working on embedded devices power efficiency to list all necessary information about generic power domains in one place. The content of pm_genpd/pm_genpd_summary file is generated by iterating over all generic power domain in the system, and, for each, over registered devices and over the subdomains, if present. Example output: $ cat /sys/kernel/debug/pm_genpd/pm_genpd_summary domain status slaves /device runtime status ---------------------------------------------------------------------- a4su off a3sg off a3sm on a3sp on /devices/e6600000.pwm suspended /devices/e6c50000.serial active /devices/e6850000.sd suspended /devices/e6bd0000.mmc active a4s on a3sp, a3sm, a3sg /devices/e6900000.irqpin unsupported /devices/e6900004.irqpin unsupported /devices/e6900008.irqpin unsupported /devices/e690000c.irqpin unsupported /devices/e9a00000.ethernet active a3rv off a4r off a3rv /devices/fff20000.i2c suspended a4lc off c5 on a4lc, a4r, a4s, a4su /devices/e6050000.pfc unsupported /devices/e6138000.timer active To enable this feature, compile the kernel with debugfs and CONFIG_PM_ADVANCED_DEBUG enabled. Signed-off-by: Maciej Matraszek Tested-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 157 ++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index a3d41a883d83..cd400575ee0e 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2222,3 +2222,160 @@ int genpd_dev_pm_attach(struct device *dev) } EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); #endif + + +/*** debugfs support ***/ + +#ifdef CONFIG_PM_ADVANCED_DEBUG +#include +#include +#include +#include +#include +#include +static struct dentry *pm_genpd_debugfs_dir; + +/* + * TODO: This function is a slightly modified version of rtpm_status_show + * from sysfs.c, but dependencies between PM_GENERIC_DOMAINS and PM_RUNTIME + * are too loose to generalize it. + */ +#ifdef CONFIG_PM_RUNTIME +static void rtpm_status_str(struct seq_file *s, struct device *dev) +{ + static const char * const status_lookup[] = { + [RPM_ACTIVE] = "active", + [RPM_RESUMING] = "resuming", + [RPM_SUSPENDED] = "suspended", + [RPM_SUSPENDING] = "suspending" + }; + const char *p = ""; + + if (dev->power.runtime_error) + p = "error"; + else if (dev->power.disable_depth) + p = "unsupported"; + else if (dev->power.runtime_status < ARRAY_SIZE(status_lookup)) + p = status_lookup[dev->power.runtime_status]; + else + WARN_ON(1); + + seq_puts(s, p); +} +#else +static void rtpm_status_str(struct seq_file *s, struct device *dev) +{ + seq_puts(s, "active"); +} +#endif + +static int pm_genpd_summary_one(struct seq_file *s, + struct generic_pm_domain *gpd) +{ + static const char * const status_lookup[] = { + [GPD_STATE_ACTIVE] = "on", + [GPD_STATE_WAIT_MASTER] = "wait-master", + [GPD_STATE_BUSY] = "busy", + [GPD_STATE_REPEAT] = "off-in-progress", + [GPD_STATE_POWER_OFF] = "off" + }; + struct pm_domain_data *pm_data; + const char *kobj_path; + struct gpd_link *link; + int ret; + + ret = mutex_lock_interruptible(&gpd->lock); + if (ret) + return -ERESTARTSYS; + + if (WARN_ON(gpd->status >= ARRAY_SIZE(status_lookup))) + goto exit; + seq_printf(s, "%-30s %-15s ", gpd->name, status_lookup[gpd->status]); + + /* + * Modifications on the list require holding locks on both + * master and slave, so we are safe. + * Also gpd->name is immutable. + */ + list_for_each_entry(link, &gpd->master_links, master_node) { + seq_printf(s, "%s", link->slave->name); + if (!list_is_last(&link->master_node, &gpd->master_links)) + seq_puts(s, ", "); + } + + list_for_each_entry(pm_data, &gpd->dev_list, list_node) { + kobj_path = kobject_get_path(&pm_data->dev->kobj, GFP_KERNEL); + if (kobj_path == NULL) + continue; + + seq_printf(s, "\n %-50s ", kobj_path); + rtpm_status_str(s, pm_data->dev); + kfree(kobj_path); + } + + seq_puts(s, "\n"); +exit: + mutex_unlock(&gpd->lock); + + return 0; +} + +static int pm_genpd_summary_show(struct seq_file *s, void *data) +{ + struct generic_pm_domain *gpd; + int ret = 0; + + seq_puts(s, " domain status slaves\n"); + seq_puts(s, " /device runtime status\n"); + seq_puts(s, "----------------------------------------------------------------------\n"); + + ret = mutex_lock_interruptible(&gpd_list_lock); + if (ret) + return -ERESTARTSYS; + + list_for_each_entry(gpd, &gpd_list, gpd_list_node) { + ret = pm_genpd_summary_one(s, gpd); + if (ret) + break; + } + mutex_unlock(&gpd_list_lock); + + return ret; +} + +static int pm_genpd_summary_open(struct inode *inode, struct file *file) +{ + return single_open(file, pm_genpd_summary_show, NULL); +} + +static const struct file_operations pm_genpd_summary_fops = { + .open = pm_genpd_summary_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init pm_genpd_debug_init(void) +{ + struct dentry *d; + + pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL); + + if (!pm_genpd_debugfs_dir) + return -ENOMEM; + + d = debugfs_create_file("pm_genpd_summary", S_IRUGO, + pm_genpd_debugfs_dir, NULL, &pm_genpd_summary_fops); + if (!d) + return -ENOMEM; + + return 0; +} +late_initcall(pm_genpd_debug_init); + +static void __exit pm_genpd_debug_exit(void) +{ + debugfs_remove_recursive(pm_genpd_debugfs_dir); +} +__exitcall(pm_genpd_debug_exit); +#endif /* CONFIG_PM_ADVANCED_DEBUG */ From d79b6fe17aa279c7015a9c4ee88809dad4be9959 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 25 Sep 2014 18:28:28 +0200 Subject: [PATCH 29/32] PM / Domains: Add genpd attach/detach callbacks While a PM domain can enable PM runtime management of its devices' module clocks by setting genpd->dev_ops.stop = pm_clk_suspend; genpd->dev_ops.start = pm_clk_resume; this also requires registering the clocks with the pm_clk subsystem. In the legacy case, this is handled by the platform code, after attaching the device to its PM domain. When the devices are instantiated from DT, devices are attached to their PM domains by generic code, leaving no method for the platform-specific PM domain code to register their clocks. Add two callbacks, allowing a PM domain to perform platform-specific tasks when a device is attached to or detached from a PM domain. Signed-off-by: Geert Uytterhoeven Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 6 ++++++ include/linux/pm_domain.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index cd400575ee0e..2a9f4c5025e3 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1436,6 +1436,9 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, spin_unlock_irq(&dev->power.lock); + if (genpd->attach_dev) + genpd->attach_dev(dev); + mutex_lock(&gpd_data->lock); gpd_data->base.dev = dev; list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); @@ -1528,6 +1531,9 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, genpd->device_count--; genpd->max_off_time_changed = true; + if (genpd->detach_dev) + genpd->detach_dev(dev); + spin_lock_irq(&dev->power.lock); dev->pm_domain = NULL; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 292079d8da6b..9a93e622bdea 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -73,6 +73,8 @@ struct generic_pm_domain { bool cached_power_down_ok; struct device_node *of_node; /* Node in device tree */ struct gpd_cpu_data *cpu_data; + void (*attach_dev)(struct device *dev); + void (*detach_dev)(struct device *dev); }; static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) From 263c589bae9eb404df2c1e8d49ec775bb7b288d4 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 25 Sep 2014 17:49:59 +0200 Subject: [PATCH 30/32] PM / Domains: Remove legacy API for adding devices through DT There are no active clients of the legacy API and we now also have a better way to handle genpd DT support. So let's remove the legacy API. Signed-off-by: Ulf Hansson Acked-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 33 --------------------------------- include/linux/pm_domain.h | 17 ----------------- 2 files changed, 50 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 2a9f4c5025e3..18cc68d058d6 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1456,39 +1456,6 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, return ret; } -/** - * __pm_genpd_of_add_device - Add a device to an I/O PM domain. - * @genpd_node: Device tree node pointer representing a PM domain to which the - * the device is added to. - * @dev: Device to be added. - * @td: Set of PM QoS timing parameters to attach to the device. - */ -int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev, - struct gpd_timing_data *td) -{ - struct generic_pm_domain *genpd = NULL, *gpd; - - dev_dbg(dev, "%s()\n", __func__); - - if (IS_ERR_OR_NULL(genpd_node) || IS_ERR_OR_NULL(dev)) - return -EINVAL; - - mutex_lock(&gpd_list_lock); - list_for_each_entry(gpd, &gpd_list, gpd_list_node) { - if (gpd->of_node == genpd_node) { - genpd = gpd; - break; - } - } - mutex_unlock(&gpd_list_lock); - - if (!genpd) - return -EINVAL; - - return __pm_genpd_add_device(genpd, dev, td); -} - - /** * __pm_genpd_name_add_device - Find I/O PM domain and add a device to it. * @domain_name: Name of the PM domain to add the device to. diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 9a93e622bdea..ed4f4a79c528 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -71,7 +71,6 @@ struct generic_pm_domain { s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ bool max_off_time_changed; bool cached_power_down_ok; - struct device_node *of_node; /* Node in device tree */ struct gpd_cpu_data *cpu_data; void (*attach_dev)(struct device *dev); void (*detach_dev)(struct device *dev); @@ -124,10 +123,6 @@ extern int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, struct gpd_timing_data *td); -extern int __pm_genpd_of_add_device(struct device_node *genpd_node, - struct device *dev, - struct gpd_timing_data *td); - extern int __pm_genpd_name_add_device(const char *domain_name, struct device *dev, struct gpd_timing_data *td); @@ -169,12 +164,6 @@ static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd, { return -ENOSYS; } -static inline int __pm_genpd_of_add_device(struct device_node *genpd_node, - struct device *dev, - struct gpd_timing_data *td) -{ - return -ENOSYS; -} static inline int __pm_genpd_name_add_device(const char *domain_name, struct device *dev, struct gpd_timing_data *td) @@ -240,12 +229,6 @@ static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, return __pm_genpd_add_device(genpd, dev, NULL); } -static inline int pm_genpd_of_add_device(struct device_node *genpd_node, - struct device *dev) -{ - return __pm_genpd_of_add_device(genpd_node, dev, NULL); -} - static inline int pm_genpd_name_add_device(const char *domain_name, struct device *dev) { From f48c767ce8951e30eb716b8ef69142d21aacbd1d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 29 Sep 2014 13:58:47 +0200 Subject: [PATCH 31/32] PM / Domains: Move dev_pm_domain_attach|detach() to pm_domain.h The commit 46420dd73b80 (PM / Domains: Add APIs to attach/detach a PM domain for a device) started using errno values in pm.h header file. It also failed to include the header for these, thus it caused compiler errors. Instead of including the errno header to pm.h, let's move the functions to pm_domain.h, since it's a better match. Fixes: 46420dd73b80 (PM / Domains: Add APIs to attach/detach a PM domain for a device) Signed-off-by: Ulf Hansson Acked-by: Geert Uytterhoeven Acked-by: Wolfram Sang Acked-by: Mark Brown Signed-off-by: Rafael J. Wysocki --- drivers/amba/bus.c | 1 + drivers/base/platform.c | 1 + drivers/i2c/i2c-core.c | 1 + drivers/mmc/core/sdio_bus.c | 1 + drivers/spi/spi.c | 1 + include/linux/pm.h | 11 ----------- include/linux/pm_domain.h | 11 +++++++++++ 7 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 8f5239377f91..47bbdc1b5be3 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 904be3dc0908..b2afc29403f9 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 3cd8f11f1b5f..e61a6c5c3372 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 1df0fc63c17c..65cf7a7e05ea 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 72a0beb1fafa..3907f1493e7d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/include/linux/pm.h b/include/linux/pm.h index c4cbf485a5d6..1022ba1eb4de 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -622,17 +622,6 @@ struct dev_pm_domain { void (*detach)(struct device *dev, bool power_off); }; -#ifdef CONFIG_PM -extern int dev_pm_domain_attach(struct device *dev, bool power_on); -extern void dev_pm_domain_detach(struct device *dev, bool power_off); -#else -static inline int dev_pm_domain_attach(struct device *dev, bool power_on) -{ - return -ENODEV; -} -static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {} -#endif - /* * The PM_EVENT_ messages are also used by drivers implementing the legacy * suspend framework, based on the ->suspend() and ->resume() callbacks common diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index ed4f4a79c528..900474317afc 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -301,4 +301,15 @@ static inline int of_genpd_add_provider_onecell(struct device_node *np, return __of_genpd_add_provider(np, __of_genpd_xlate_onecell, data); } +#ifdef CONFIG_PM +extern int dev_pm_domain_attach(struct device *dev, bool power_on); +extern void dev_pm_domain_detach(struct device *dev, bool power_off); +#else +static inline int dev_pm_domain_attach(struct device *dev, bool power_on) +{ + return -ENODEV; +} +static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {} +#endif + #endif /* _LINUX_PM_DOMAIN_H */ From f39cb1797ec1094b196d3dab44a7ca6060813d38 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 2 Oct 2014 21:12:34 +0200 Subject: [PATCH 32/32] PM / Domains: Rename cpu_data to cpuidle_data The "cpu_data" are defined for some archs and thus conflicting with the "cpu_data" member in the struct gpd_cpu_data. This causes a compiler error for those archs. Let's fix it by rename the member to cpuidle_data. In this context it also seems appropriate to rename the struct to gpd_cpuidle_data to better reflect its use. Fixes: f48c767ce895 (PM / Domains: Move dev_pm_domain_attach|detach() to pm_domain.h) Signed-off-by: Ulf Hansson Acked-by: Geert Uytterhoeven Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 54 ++++++++++++++++++------------------- include/linux/pm_domain.h | 4 +-- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 18cc68d058d6..40bc2f4072cc 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -142,13 +142,13 @@ static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd) { s64 usecs64; - if (!genpd->cpu_data) + if (!genpd->cpuidle_data) return; usecs64 = genpd->power_on_latency_ns; do_div(usecs64, NSEC_PER_USEC); - usecs64 += genpd->cpu_data->saved_exit_latency; - genpd->cpu_data->idle_state->exit_latency = usecs64; + usecs64 += genpd->cpuidle_data->saved_exit_latency; + genpd->cpuidle_data->idle_state->exit_latency = usecs64; } /** @@ -188,9 +188,9 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) return 0; } - if (genpd->cpu_data) { + if (genpd->cpuidle_data) { cpuidle_pause_and_lock(); - genpd->cpu_data->idle_state->disabled = true; + genpd->cpuidle_data->idle_state->disabled = true; cpuidle_resume_and_unlock(); goto out; } @@ -513,17 +513,17 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) } } - if (genpd->cpu_data) { + if (genpd->cpuidle_data) { /* - * If cpu_data is set, cpuidle should turn the domain off when - * the CPU in it is idle. In that case we don't decrement the - * subdomain counts of the master domains, so that power is not - * removed from the current domain prematurely as a result of - * cutting off the masters' power. + * If cpuidle_data is set, cpuidle should turn the domain off + * when the CPU in it is idle. In that case we don't decrement + * the subdomain counts of the master domains, so that power is + * not removed from the current domain prematurely as a result + * of cutting off the masters' power. */ genpd->status = GPD_STATE_POWER_OFF; cpuidle_pause_and_lock(); - genpd->cpu_data->idle_state->disabled = false; + genpd->cpuidle_data->idle_state->disabled = false; cpuidle_resume_and_unlock(); goto out; } @@ -1698,7 +1698,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state) { struct cpuidle_driver *cpuidle_drv; - struct gpd_cpu_data *cpu_data; + struct gpd_cpuidle_data *cpuidle_data; struct cpuidle_state *idle_state; int ret = 0; @@ -1707,12 +1707,12 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state) genpd_acquire_lock(genpd); - if (genpd->cpu_data) { + if (genpd->cpuidle_data) { ret = -EEXIST; goto out; } - cpu_data = kzalloc(sizeof(*cpu_data), GFP_KERNEL); - if (!cpu_data) { + cpuidle_data = kzalloc(sizeof(*cpuidle_data), GFP_KERNEL); + if (!cpuidle_data) { ret = -ENOMEM; goto out; } @@ -1730,9 +1730,9 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state) ret = -EAGAIN; goto err; } - cpu_data->idle_state = idle_state; - cpu_data->saved_exit_latency = idle_state->exit_latency; - genpd->cpu_data = cpu_data; + cpuidle_data->idle_state = idle_state; + cpuidle_data->saved_exit_latency = idle_state->exit_latency; + genpd->cpuidle_data = cpuidle_data; genpd_recalc_cpu_exit_latency(genpd); out: @@ -1743,7 +1743,7 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state) cpuidle_driver_unref(); err_drv: - kfree(cpu_data); + kfree(cpuidle_data); goto out; } @@ -1766,7 +1766,7 @@ int pm_genpd_name_attach_cpuidle(const char *name, int state) */ int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd) { - struct gpd_cpu_data *cpu_data; + struct gpd_cpuidle_data *cpuidle_data; struct cpuidle_state *idle_state; int ret = 0; @@ -1775,20 +1775,20 @@ int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd) genpd_acquire_lock(genpd); - cpu_data = genpd->cpu_data; - if (!cpu_data) { + cpuidle_data = genpd->cpuidle_data; + if (!cpuidle_data) { ret = -ENODEV; goto out; } - idle_state = cpu_data->idle_state; + idle_state = cpuidle_data->idle_state; if (!idle_state->disabled) { ret = -EAGAIN; goto out; } - idle_state->exit_latency = cpu_data->saved_exit_latency; + idle_state->exit_latency = cpuidle_data->saved_exit_latency; cpuidle_driver_unref(); - genpd->cpu_data = NULL; - kfree(cpu_data); + genpd->cpuidle_data = NULL; + kfree(cpuidle_data); out: genpd_release_lock(genpd); diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 900474317afc..73e938b7e937 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -38,7 +38,7 @@ struct gpd_dev_ops { bool (*active_wakeup)(struct device *dev); }; -struct gpd_cpu_data { +struct gpd_cpuidle_data { unsigned int saved_exit_latency; struct cpuidle_state *idle_state; }; @@ -71,7 +71,7 @@ struct generic_pm_domain { s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ bool max_off_time_changed; bool cached_power_down_ok; - struct gpd_cpu_data *cpu_data; + struct gpd_cpuidle_data *cpuidle_data; void (*attach_dev)(struct device *dev); void (*detach_dev)(struct device *dev); };