From 068765ba7987e73d4381edfe47b70aa121c7155c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Sep 2014 13:47:49 +0200 Subject: PM / sleep: Mechanism for aborting system suspends unconditionally It sometimes may be necessary to abort a system suspend in progress or wake up the system from suspend-to-idle even if the pm_wakeup_event()/pm_stay_awake() mechanism is not enabled. For this purpose, introduce a new global variable pm_abort_suspend and make pm_wakeup_pending() check its value. Also add routines for manipulating that variable. Signed-off-by: Rafael J. Wysocki --- include/linux/suspend.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 519064e0c943..06a9910827c2 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -371,6 +371,8 @@ extern int unregister_pm_notifier(struct notifier_block *nb); extern bool events_check_enabled; extern bool pm_wakeup_pending(void); +extern void pm_system_wakeup(void); +extern void pm_wakeup_clear(void); extern bool pm_get_wakeup_count(unsigned int *count, bool block); extern bool pm_save_wakeup_count(unsigned int count); extern void pm_wakep_autosleep_enabled(bool set); @@ -418,6 +420,8 @@ static inline int unregister_pm_notifier(struct notifier_block *nb) #define pm_notifier(fn, pri) do { (void)(fn); } while (0) static inline bool pm_wakeup_pending(void) { return false; } +static inline void pm_system_wakeup(void) {} +static inline void pm_wakeup_clear(void) {} static inline void lock_system_sleep(void) {} static inline void unlock_system_sleep(void) {} -- cgit v1.3-14-g43fede From cab303be91dc47942bc25de33dc1140123540800 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 28 Aug 2014 11:44:31 +0200 Subject: genirq: Add sanity checks for PM options on shared interrupt lines Account the IRQF_NO_SUSPEND and IRQF_RESUME_EARLY actions on shared interrupt lines and yell loudly if there is a mismatch. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- include/linux/irqdesc.h | 10 ++++++++++ kernel/irq/internals.h | 10 ++++++++++ kernel/irq/manage.c | 4 ++++ kernel/irq/pm.c | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+) (limited to 'include/linux') diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 472c021a2d4f..cb1a31e448ae 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -36,6 +36,11 @@ struct irq_desc; * @threads_oneshot: bitfield to handle shared oneshot threads * @threads_active: number of irqaction threads currently running * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers + * @nr_actions: number of installed actions on this descriptor + * @no_suspend_depth: number of irqactions on a irq descriptor with + * IRQF_NO_SUSPEND set + * @force_resume_depth: number of irqactions on a irq descriptor with + * IRQF_FORCE_RESUME set * @dir: /proc/irq/ procfs entry * @name: flow handler name for /proc/interrupts output */ @@ -68,6 +73,11 @@ struct irq_desc { unsigned long threads_oneshot; atomic_t threads_active; wait_queue_head_t wait_for_threads; +#ifdef CONFIG_PM_SLEEP + unsigned int nr_actions; + unsigned int no_suspend_depth; + unsigned int force_resume_depth; +#endif #ifdef CONFIG_PROC_FS struct proc_dir_entry *dir; #endif diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index af2821178900..c402502a5111 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -194,3 +194,13 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *d __this_cpu_inc(*desc->kstat_irqs); __this_cpu_inc(kstat.irqs_sum); } + +#ifdef CONFIG_PM_SLEEP +void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); +void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action); +#else +static inline void +irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) { } +static inline void +irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) { } +#endif diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index fa564e8db996..0a9104b4608b 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1200,6 +1200,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) new->irq = irq; *old_ptr = new; + irq_pm_install_action(desc, new); + /* Reset broken irq detection when installing new handler */ desc->irq_count = 0; desc->irqs_unhandled = 0; @@ -1318,6 +1320,8 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) /* Found it - now remove it from the list of entries: */ *action_ptr = action->next; + irq_pm_remove_action(desc, action); + /* If this was the last handler, shut down the IRQ line: */ if (!desc->action) { irq_shutdown(desc); diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index b84141dcee5e..1b1b67a73218 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -13,6 +13,42 @@ #include "internals.h" +/* + * Called from __setup_irq() with desc->lock held after @action has + * been installed in the action chain. + */ +void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) +{ + desc->nr_actions++; + + if (action->flags & IRQF_FORCE_RESUME) + desc->force_resume_depth++; + + WARN_ON_ONCE(desc->force_resume_depth && + desc->force_resume_depth != desc->nr_actions); + + if (action->flags & IRQF_NO_SUSPEND) + desc->no_suspend_depth++; + + WARN_ON_ONCE(desc->no_suspend_depth && + desc->no_suspend_depth != desc->nr_actions); +} + +/* + * Called from __free_irq() with desc->lock held after @action has + * been removed from the action chain. + */ +void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) +{ + desc->nr_actions--; + + if (action->flags & IRQF_FORCE_RESUME) + desc->force_resume_depth--; + + if (action->flags & IRQF_NO_SUSPEND) + desc->no_suspend_depth--; +} + static void suspend_device_irq(struct irq_desc *desc, int irq) { if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)) -- cgit v1.3-14-g43fede From b76f16748fa61801b1a1fd3ffb6f25ee228a35e0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 Aug 2014 13:54:09 +0200 Subject: genirq: Mark wakeup sources as armed on suspend This allows us to utilize this information in the irq_may_run() check without adding another conditional to the fast path. Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- include/linux/irq.h | 8 ++++++++ kernel/irq/pm.c | 5 +++++ 2 files changed, 13 insertions(+) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 62af59242ddc..03f48d936f66 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -173,6 +173,7 @@ struct irq_data { * IRQD_IRQ_DISABLED - Disabled state of the interrupt * IRQD_IRQ_MASKED - Masked state of the interrupt * IRQD_IRQ_INPROGRESS - In progress state of the interrupt + * IRQD_WAKEUP_ARMED - Wakeup mode armed */ enum { IRQD_TRIGGER_MASK = 0xf, @@ -186,6 +187,7 @@ enum { IRQD_IRQ_DISABLED = (1 << 16), IRQD_IRQ_MASKED = (1 << 17), IRQD_IRQ_INPROGRESS = (1 << 18), + IRQD_WAKEUP_ARMED = (1 << 19), }; static inline bool irqd_is_setaffinity_pending(struct irq_data *d) @@ -257,6 +259,12 @@ static inline bool irqd_irq_inprogress(struct irq_data *d) return d->state_use_accessors & IRQD_IRQ_INPROGRESS; } +static inline bool irqd_is_wakeup_armed(struct irq_data *d) +{ + return d->state_use_accessors & IRQD_WAKEUP_ARMED; +} + + /* * Functions for chained handlers which can be enabled/disabled by the * standard disable_irq/enable_irq calls. Must be called with diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index cf0ce0163db9..766930eaeed9 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -54,6 +54,9 @@ static bool suspend_device_irq(struct irq_desc *desc, int irq) if (!desc->action || desc->no_suspend_depth) return false; + if (irqd_is_wakeup_set(&desc->irq_data)) + irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED); + desc->istate |= IRQS_SUSPENDED; __disable_irq(desc, irq); @@ -101,6 +104,8 @@ EXPORT_SYMBOL_GPL(suspend_device_irqs); static void resume_irq(struct irq_desc *desc, int irq) { + irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED); + if (desc->istate & IRQS_SUSPENDED) goto resume; -- cgit v1.3-14-g43fede From 9ce7a25849e80cfb264f4995f832b932c1987e1a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 29 Aug 2014 14:00:16 +0200 Subject: genirq: Simplify wakeup mechanism Currently we suspend wakeup interrupts by lazy disabling them and check later whether the interrupt has fired, but that's not sufficient for suspend to idle as there is no way to check that once we transitioned into the CPU idle state. So we change the mechanism in the following way: 1) Leave the wakeup interrupts enabled across suspend 2) Add a check to irq_may_run() which is called at the beginning of each flow handler whether the interrupt is an armed wakeup source. This check is basically free as it just extends the existing check for IRQD_IRQ_INPROGRESS. So no new conditional in the hot path. If the IRQD_WAKEUP_ARMED flag is set, then the interrupt is disabled, marked as pending/suspended and the pm core is notified about the wakeup event. Signed-off-by: Thomas Gleixner [ rjw: syscore.c and put irq_pm_check_wakeup() into pm.c ] Signed-off-by: Rafael J. Wysocki --- drivers/base/syscore.c | 7 +++--- include/linux/interrupt.h | 5 ----- kernel/irq/chip.c | 20 ++++++++++++++++- kernel/irq/internals.h | 2 ++ kernel/irq/pm.c | 55 +++++++++++++++++++++++++---------------------- 5 files changed, 53 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index dbb8350ea8dc..8d98a329f6ea 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include static LIST_HEAD(syscore_ops_list); @@ -54,9 +54,8 @@ int syscore_suspend(void) pr_debug("Checking wakeup interrupts\n"); /* Return error code if there are any wakeup interrupts pending. */ - ret = check_wakeup_irqs(); - if (ret) - return ret; + if (pm_wakeup_pending()) + return -EBUSY; WARN_ONCE(!irqs_disabled(), "Interrupts enabled before system core suspend.\n"); diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 698ad053d064..69517a24bc50 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -193,11 +193,6 @@ extern void irq_wake_thread(unsigned int irq, void *dev_id); /* The following three functions are for the core kernel use only. */ extern void suspend_device_irqs(void); extern void resume_device_irqs(void); -#ifdef CONFIG_PM_SLEEP -extern int check_wakeup_irqs(void); -#else -static inline int check_wakeup_irqs(void) { return 0; } -#endif /** * struct irq_affinity_notify - context for notification of IRQ affinity changes diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 6baf86085571..e7917ff8a486 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -344,8 +344,26 @@ static bool irq_check_poll(struct irq_desc *desc) static bool irq_may_run(struct irq_desc *desc) { - if (!irqd_irq_inprogress(&desc->irq_data)) + unsigned int mask = IRQD_IRQ_INPROGRESS | IRQD_WAKEUP_ARMED; + + /* + * If the interrupt is not in progress and is not an armed + * wakeup interrupt, proceed. + */ + if (!irqd_has_set(&desc->irq_data, mask)) return true; + + /* + * If the interrupt is an armed wakeup source, mark it pending + * and suspended, disable it and notify the pm core about the + * event. + */ + if (irq_pm_check_wakeup(desc)) + return false; + + /* + * Handle a potential concurrent poll on a different core. + */ return irq_check_poll(desc); } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index c402502a5111..4332d766619d 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -196,9 +196,11 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *d } #ifdef CONFIG_PM_SLEEP +bool irq_pm_check_wakeup(struct irq_desc *desc); void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action); #else +static inline bool irq_pm_check_wakeup(struct irq_desc *desc) { return false; } static inline void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) { } static inline void diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 766930eaeed9..3ca532592704 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -9,10 +9,24 @@ #include #include #include +#include #include #include "internals.h" +bool irq_pm_check_wakeup(struct irq_desc *desc) +{ + if (irqd_is_wakeup_armed(&desc->irq_data)) { + irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED); + desc->istate |= IRQS_SUSPENDED | IRQS_PENDING; + desc->depth++; + irq_disable(desc); + pm_system_wakeup(); + return true; + } + return false; +} + /* * Called from __setup_irq() with desc->lock held after @action has * been installed in the action chain. @@ -54,8 +68,16 @@ static bool suspend_device_irq(struct irq_desc *desc, int irq) if (!desc->action || desc->no_suspend_depth) return false; - if (irqd_is_wakeup_set(&desc->irq_data)) + if (irqd_is_wakeup_set(&desc->irq_data)) { irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED); + /* + * We return true here to force the caller to issue + * synchronize_irq(). We need to make sure that the + * IRQD_WAKEUP_ARMED is visible before we return from + * suspend_device_irqs(). + */ + return true; + } desc->istate |= IRQS_SUSPENDED; __disable_irq(desc, irq); @@ -79,9 +101,13 @@ static bool suspend_device_irq(struct irq_desc *desc, int irq) * for this purpose. * * So we disable all interrupts and mark them IRQS_SUSPENDED except - * for those which are unused and those which are marked as not + * for those which are unused, those which are marked as not * suspendable via an interrupt request with the flag IRQF_NO_SUSPEND - * set. + * set and those which are marked as active wakeup sources. + * + * The active wakeup sources are handled by the flow handler entry + * code which checks for the IRQD_WAKEUP_ARMED flag, suspends the + * interrupt and notifies the pm core about the wakeup. */ void suspend_device_irqs(void) { @@ -173,26 +199,3 @@ void resume_device_irqs(void) resume_irqs(false); } EXPORT_SYMBOL_GPL(resume_device_irqs); - -/** - * check_wakeup_irqs - check if any wake-up interrupts are pending - */ -int check_wakeup_irqs(void) -{ - struct irq_desc *desc; - int irq; - - for_each_irq_desc(irq, desc) { - /* - * Only interrupts which are marked as wakeup source - * and have not been disabled before the suspend check - * can abort suspend. - */ - if (irqd_is_wakeup_set(&desc->irq_data)) { - if (desc->depth == 1 && desc->istate & IRQS_PENDING) - return -EBUSY; - } - } - - return 0; -} -- cgit v1.3-14-g43fede From 55e15c949fd05d247a889df0ed0177a676fec665 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:17 +0200 Subject: 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(-) (limited to 'include/linux') 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); -- cgit v1.3-14-g43fede From 67da6d4bf43c4208433ef8f3ee487401b4dc9c74 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:18 +0200 Subject: 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(-) (limited to 'include/linux') 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; -- cgit v1.3-14-g43fede From 1e0407ca54d28db8e5f02e437ff21cc6416c0be8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:19 +0200 Subject: 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(-) (limited to 'include/linux') 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); }; -- cgit v1.3-14-g43fede From c5d79ec2a5715489cff16a0d1cf4fa9108a5509e Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:22 +0200 Subject: 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(-) (limited to 'include/linux') 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); -- cgit v1.3-14-g43fede From d47e6464ae6c96735d4706f5cb0537fe717b6b00 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:24 +0200 Subject: 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(-) (limited to 'include/linux') 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 */ -- cgit v1.3-14-g43fede From d971f0b0eaaf3f2086bf21bbd64f7ea7e2f28459 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:25 +0200 Subject: 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(-) (limited to 'include/linux') 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 -- cgit v1.3-14-g43fede From 0f574d4c3a7a325cbbef28ee738dedca9851e957 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:30 +0200 Subject: 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(-) (limited to 'include/linux') 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 -- cgit v1.3-14-g43fede From ae3c511c2d72161b11e93866203b59a3a37dfac7 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 3 Sep 2014 12:52:31 +0200 Subject: 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(-) (limited to 'include/linux') 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 -- cgit v1.3-14-g43fede From 413fffc3a1db7f270afdf1ecb35c1edc013acc68 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 28 Aug 2014 11:22:23 +0530 Subject: cpufreq: Add support for per-policy driver data Drivers supporting multiple clusters or multiple 'struct cpufreq_policy' instances may need to keep per-policy data. If the core doesn't provide support for that, they might do it in the most unoptimized way: 'per-cpu' data. This patch adds another field in struct cpufreq_policy: 'driver_data'. It isn't accessed by core and is for driver's internal use only. Tested-by: Stephen Boyd Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- include/linux/cpufreq.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 7d1955afa62c..138336b6bb04 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -112,6 +112,9 @@ struct cpufreq_policy { spinlock_t transition_lock; wait_queue_head_t transition_wait; struct task_struct *transition_task; /* Task which is doing the transition */ + + /* For cpufreq driver's internal use */ + void *driver_data; }; /* Only for ACPI */ -- cgit v1.3-14-g43fede From c3099a5294f2c7266234e8ea35cbffc20a41aa9a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:34 +0200 Subject: 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(+) (limited to 'include/linux') 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); }; /* -- cgit v1.3-14-g43fede From aa42240ab2544a8bcb2efb400193826f57f3175e Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Fri, 19 Sep 2014 20:27:36 +0200 Subject: 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 --- .../devicetree/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 (limited to 'include/linux') 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 -- cgit v1.3-14-g43fede From 46420dd73b800f87a19af13af5883855cf38cb08 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:37 +0200 Subject: 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(+) (limited to 'include/linux') 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 -- cgit v1.3-14-g43fede From 91d66cd27f5fd8a3bca4621a3505c9067925478d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 19 Sep 2014 20:27:44 +0200 Subject: 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(-) (limited to 'include/linux') 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 -- cgit v1.3-14-g43fede From d79b6fe17aa279c7015a9c4ee88809dad4be9959 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 25 Sep 2014 18:28:28 +0200 Subject: 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(+) (limited to 'include/linux') 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) -- cgit v1.3-14-g43fede From 263c589bae9eb404df2c1e8d49ec775bb7b288d4 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 25 Sep 2014 17:49:59 +0200 Subject: 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(-) (limited to 'include/linux') 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) { -- cgit v1.3-14-g43fede From f48c767ce8951e30eb716b8ef69142d21aacbd1d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 29 Sep 2014 13:58:47 +0200 Subject: 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(-) (limited to 'include/linux') 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 */ -- cgit v1.3-14-g43fede From 2a8a8ce651d3a88fdf83e2ed15633c8d19292108 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Sep 2014 02:21:34 +0200 Subject: PM / sleep: Export dpm_suspend_late/noirq() and dpm_resume_early/noirq() Subsequent change sets will add platform-related operations between dpm_suspend_late() and dpm_suspend_noirq() as well as between dpm_resume_noirq() and dpm_resume_early() in suspend_enter(), so export these functions for suspend_enter() to be able to call them separately and split the invocations of dpm_suspend_end() and dpm_resume_start() in there accordingly. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 8 ++++---- include/linux/pm.h | 4 ++++ kernel/power/suspend.c | 14 +++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index b67d9aef9fe4..44973196d3fd 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -540,7 +540,7 @@ static void async_resume_noirq(void *data, async_cookie_t cookie) * Call the "noirq" resume handlers for all devices in dpm_noirq_list and * enable device drivers to receive interrupts. */ -static void dpm_resume_noirq(pm_message_t state) +void dpm_resume_noirq(pm_message_t state) { struct device *dev; ktime_t starttime = ktime_get(); @@ -662,7 +662,7 @@ static void async_resume_early(void *data, async_cookie_t cookie) * dpm_resume_early - Execute "early resume" callbacks for all devices. * @state: PM transition of the system being carried out. */ -static void dpm_resume_early(pm_message_t state) +void dpm_resume_early(pm_message_t state) { struct device *dev; ktime_t starttime = ktime_get(); @@ -1093,7 +1093,7 @@ static int device_suspend_noirq(struct device *dev) * Prevent device drivers from receiving interrupts and call the "noirq" suspend * handlers for all non-sysdev devices. */ -static int dpm_suspend_noirq(pm_message_t state) +int dpm_suspend_noirq(pm_message_t state) { ktime_t starttime = ktime_get(); int error = 0; @@ -1232,7 +1232,7 @@ static int device_suspend_late(struct device *dev) * dpm_suspend_late - Execute "late suspend" callbacks for all devices. * @state: PM transition of the system being carried out. */ -static int dpm_suspend_late(pm_message_t state) +int dpm_suspend_late(pm_message_t state) { ktime_t starttime = ktime_get(); int error = 0; diff --git a/include/linux/pm.h b/include/linux/pm.h index 72c0fe098a27..e1c00b7ee913 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -679,12 +679,16 @@ struct dev_pm_domain { extern void device_pm_lock(void); extern void dpm_resume_start(pm_message_t state); extern void dpm_resume_end(pm_message_t state); +extern void dpm_resume_noirq(pm_message_t state); +extern void dpm_resume_early(pm_message_t state); extern void dpm_resume(pm_message_t state); extern void dpm_complete(pm_message_t state); extern void device_pm_unlock(void); extern int dpm_suspend_end(pm_message_t state); extern int dpm_suspend_start(pm_message_t state); +extern int dpm_suspend_noirq(pm_message_t state); +extern int dpm_suspend_late(pm_message_t state); extern int dpm_suspend(pm_message_t state); extern int dpm_prepare(pm_message_t state); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index e837dd6783c6..58ae98b7dc2b 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -265,11 +265,16 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (error) goto Platform_finish; - error = dpm_suspend_end(PMSG_SUSPEND); + error = dpm_suspend_late(PMSG_SUSPEND); if (error) { - printk(KERN_ERR "PM: Some devices failed to power down\n"); + printk(KERN_ERR "PM: late suspend of devices failed\n"); goto Platform_finish; } + error = dpm_suspend_noirq(PMSG_SUSPEND); + if (error) { + printk(KERN_ERR "PM: noirq suspend of devices failed\n"); + goto Devices_early_resume; + } error = platform_suspend_prepare_late(state); if (error) goto Platform_wake; @@ -319,7 +324,10 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) Platform_wake: platform_suspend_wake(state); - dpm_resume_start(PMSG_RESUME); + dpm_resume_noirq(PMSG_RESUME); + + Devices_early_resume: + dpm_resume_early(PMSG_RESUME); Platform_finish: platform_suspend_finish(state); -- cgit v1.3-14-g43fede From a8d46b9e4e487301affe84fa53de40b890898604 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Sep 2014 02:29:01 +0200 Subject: ACPI / sleep: Rework the handling of ACPI GPE wakeup from suspend-to-idle The ACPI GPE wakeup from suspend-to-idle is currently based on using the IRQF_NO_SUSPEND flag for the ACPI SCI, but that is problematic for a couple of reasons. First, in principle the ACPI SCI may be shared and IRQF_NO_SUSPEND does not really work well with shared interrupts. Second, it may require the ACPI subsystem to special-case the handling of device notifications depending on whether or not they are received during suspend-to-idle in some places which would lead to fragile code. Finally, it's better the handle ACPI wakeup interrupts consistently with wakeup interrupts from other sources. For this reason, remove the IRQF_NO_SUSPEND flag from the ACPI SCI and use enable_irq_wake()/disable_irq_wake() with it instead, which requires two additional platform hooks to be added to struct platform_freeze_ops. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 2 +- drivers/acpi/sleep.c | 16 ++++++++++++++++ include/linux/suspend.h | 2 ++ kernel/power/suspend.c | 21 ++++++++++++++++++++- 4 files changed, 39 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 3abe9b223ba7..5ca29b5af8d1 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -825,7 +825,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, acpi_irq_handler = handler; acpi_irq_context = context; - if (request_irq(irq, acpi_irq, IRQF_SHARED | IRQF_NO_SUSPEND, "acpi", acpi_irq)) { + if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); acpi_irq_handler = NULL; return AE_NOT_ACQUIRED; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 54da4a3fe65e..05a31b573fc3 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -626,6 +627,19 @@ static int acpi_freeze_begin(void) return 0; } +static int acpi_freeze_prepare(void) +{ + acpi_enable_all_wakeup_gpes(); + enable_irq_wake(acpi_gbl_FADT.sci_interrupt); + return 0; +} + +static void acpi_freeze_restore(void) +{ + disable_irq_wake(acpi_gbl_FADT.sci_interrupt); + acpi_enable_all_runtime_gpes(); +} + static void acpi_freeze_end(void) { acpi_scan_lock_release(); @@ -633,6 +647,8 @@ static void acpi_freeze_end(void) static const struct platform_freeze_ops acpi_freeze_ops = { .begin = acpi_freeze_begin, + .prepare = acpi_freeze_prepare, + .restore = acpi_freeze_restore, .end = acpi_freeze_end, }; diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 06a9910827c2..3388c1b6f7d8 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -189,6 +189,8 @@ struct platform_suspend_ops { struct platform_freeze_ops { int (*begin)(void); + int (*prepare)(void); + void (*restore)(void); void (*end)(void); }; diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index a25e768d92b5..4ca9a33ff620 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -144,6 +144,12 @@ static int platform_suspend_prepare(suspend_state_t state) suspend_ops->prepare() : 0; } +static int platform_suspend_prepare_late(suspend_state_t state) +{ + return state == PM_SUSPEND_FREEZE && freeze_ops->prepare ? + freeze_ops->prepare() : 0; +} + static int platform_suspend_prepare_noirq(suspend_state_t state) { return state != PM_SUSPEND_FREEZE && suspend_ops->prepare_late ? @@ -156,6 +162,12 @@ static void platform_resume_noirq(suspend_state_t state) suspend_ops->wake(); } +static void platform_resume_early(suspend_state_t state) +{ + if (state == PM_SUSPEND_FREEZE && freeze_ops->restore) + freeze_ops->restore(); +} + static void platform_resume_finish(suspend_state_t state) { if (state != PM_SUSPEND_FREEZE && suspend_ops->finish) @@ -270,10 +282,14 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) printk(KERN_ERR "PM: late suspend of devices failed\n"); goto Platform_finish; } + error = platform_suspend_prepare_late(state); + if (error) + goto Devices_early_resume; + error = dpm_suspend_noirq(PMSG_SUSPEND); if (error) { printk(KERN_ERR "PM: noirq suspend of devices failed\n"); - goto Devices_early_resume; + goto Platform_early_resume; } error = platform_suspend_prepare_noirq(state); if (error) @@ -326,6 +342,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) platform_resume_noirq(state); dpm_resume_noirq(PMSG_RESUME); + Platform_early_resume: + platform_resume_early(state); + Devices_early_resume: dpm_resume_early(PMSG_RESUME); -- cgit v1.3-14-g43fede From f39cb1797ec1094b196d3dab44a7ca6060813d38 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 2 Oct 2014 21:12:34 +0200 Subject: 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(-) (limited to 'include/linux') 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); }; -- cgit v1.3-14-g43fede