From bd8c9ba3b1e2037af5af4e48aea1087212838179 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 17 Jul 2017 17:19:25 -0700 Subject: [PATCH 01/18] PM / suspend: Export pm_suspend_target_state Have the core suspend/resume framework store the system-wide suspend state (suspend_state_t) we are about to enter, and expose it to drivers via pm_suspend_target_state in order to retrieve that. The state is assigned in suspend_devices_and_enter(). This is useful for platform specific drivers that may need to take a slightly different suspend/resume path based on the system's suspend/resume state being entered. Signed-off-by: Florian Fainelli Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki --- include/linux/suspend.h | 1 + kernel/power/suspend.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 0b1cf32edfd7..2159f6841768 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -427,6 +427,7 @@ extern int unregister_pm_notifier(struct notifier_block *nb); /* drivers/base/power/wakeup.c */ extern bool events_check_enabled; extern unsigned int pm_wakeup_irq; +extern suspend_state_t pm_suspend_target_state; extern bool pm_wakeup_pending(void); extern void pm_system_wakeup(void); diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 3ecf275d7e44..d0c0b96c2383 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -47,6 +47,8 @@ const char *mem_sleep_states[PM_SUSPEND_MAX]; suspend_state_t mem_sleep_current = PM_SUSPEND_FREEZE; static suspend_state_t mem_sleep_default = PM_SUSPEND_MEM; +suspend_state_t pm_suspend_target_state; +EXPORT_SYMBOL_GPL(pm_suspend_target_state); unsigned int pm_suspend_global_flags; EXPORT_SYMBOL_GPL(pm_suspend_global_flags); @@ -456,6 +458,8 @@ int suspend_devices_and_enter(suspend_state_t state) if (!sleep_state_supported(state)) return -ENOSYS; + pm_suspend_target_state = state; + error = platform_suspend_begin(state); if (error) goto Close; @@ -485,6 +489,7 @@ int suspend_devices_and_enter(suspend_state_t state) Close: platform_resume_end(state); + pm_suspend_target_state = PM_SUSPEND_ON; return error; Recover_platform: From 8d8b2441db9647890251538f60b75a4e45fdef8d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 19 Jul 2017 02:38:44 +0200 Subject: [PATCH 02/18] PM / sleep: Do not print debug messages by default Debug messages from the system suspend/hibernation infrastructure can fill up the entire kernel log buffer in some cases and anyway they are only useful for debugging. They depend on CONFIG_PM_DEBUG, but that is set as a rule as some generally useful diagnostic facilities depend on it too. For this reason, avoid printing those messages by default, but make it possible to turn them on as needed with the help of a new sysfs attribute under /sys/power/. Signed-off-by: Rafael J. Wysocki --- Documentation/ABI/testing/sysfs-power | 12 +++++++ drivers/base/power/main.c | 12 +++---- include/linux/suspend.h | 6 ++++ kernel/power/hibernate.c | 24 ++++++------- kernel/power/main.c | 52 +++++++++++++++++++++++++++ kernel/power/suspend.c | 10 +++--- 6 files changed, 91 insertions(+), 25 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index f523e5a3ac33..713cab1d5f12 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -273,3 +273,15 @@ Description: This output is useful for system wakeup diagnostics of spurious wakeup interrupts. + +What: /sys/power/pm_debug_messages +Date: July 2017 +Contact: Rafael J. Wysocki +Description: + The /sys/power/pm_debug_messages file controls the printing + of debug messages from the system suspend/hiberbation + infrastructure to the kernel log. + + Writing a "1" to this file enables the debug messages and + writing a "0" (default) to it disables them. Reads from + this file return the current value. diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index c99f8730de82..4f5fc212d684 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -418,7 +418,6 @@ static void pm_dev_err(struct device *dev, pm_message_t state, const char *info, dev_name(dev), pm_verb(state.event), info, error); } -#ifdef CONFIG_PM_DEBUG static void dpm_show_time(ktime_t starttime, pm_message_t state, const char *info) { @@ -432,14 +431,11 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, usecs = usecs64; if (usecs == 0) usecs = 1; - pr_info("PM: %s%s%s of devices complete after %ld.%03ld msecs\n", - info ?: "", info ? " " : "", pm_verb(state.event), - usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); + + pm_pr_dbg("%s%s%s of devices complete after %ld.%03ld msecs\n", + info ?: "", info ? " " : "", pm_verb(state.event), + usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); } -#else -static inline void dpm_show_time(ktime_t starttime, pm_message_t state, - const char *info) {} -#endif /* CONFIG_PM_DEBUG */ static int dpm_run_callback(pm_callback_t cb, struct device *dev, pm_message_t state, const char *info) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 2159f6841768..707e4cdf21c2 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -492,8 +492,14 @@ static inline void unlock_system_sleep(void) {} #ifdef CONFIG_PM_SLEEP_DEBUG extern bool pm_print_times_enabled; +extern __printf(1, 2) void pm_pr_dbg(const char *fmt, ...); #else #define pm_print_times_enabled (false) + +#include + +#define pm_pr_dbg(fmt, ...) \ + no_printk(KERN_DEBUG fmt, ##__VA_ARGS__) #endif #ifdef CONFIG_PM_AUTOSLEEP diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index e1914c7b85b1..e19ee179d211 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -651,7 +651,7 @@ static int load_image_and_restore(void) int error; unsigned int flags; - pr_debug("Loading hibernation image.\n"); + pm_pr_dbg("Loading hibernation image.\n"); lock_device_hotplug(); error = create_basic_memory_bitmaps(); @@ -681,7 +681,7 @@ int hibernate(void) bool snapshot_test = false; if (!hibernation_available()) { - pr_debug("Hibernation not available.\n"); + pm_pr_dbg("Hibernation not available.\n"); return -EPERM; } @@ -727,7 +727,7 @@ int hibernate(void) else flags |= SF_CRC32_MODE; - pr_debug("Writing image.\n"); + pm_pr_dbg("Writing image.\n"); error = swsusp_write(flags); swsusp_free(); if (!error) { @@ -739,7 +739,7 @@ int hibernate(void) in_suspend = 0; pm_restore_gfp_mask(); } else { - pr_debug("Image restored successfully.\n"); + pm_pr_dbg("Image restored successfully.\n"); } Free_bitmaps: @@ -747,7 +747,7 @@ int hibernate(void) Thaw: unlock_device_hotplug(); if (snapshot_test) { - pr_debug("Checking hibernation image\n"); + pm_pr_dbg("Checking hibernation image\n"); error = swsusp_check(); if (!error) error = load_image_and_restore(); @@ -811,7 +811,7 @@ static int software_resume(void) goto Unlock; } - pr_debug("Checking hibernation image partition %s\n", resume_file); + pm_pr_dbg("Checking hibernation image partition %s\n", resume_file); if (resume_delay) { pr_info("Waiting %dsec before reading resume device ...\n", @@ -853,10 +853,10 @@ static int software_resume(void) } Check_image: - pr_debug("Hibernation image partition %d:%d present\n", + pm_pr_dbg("Hibernation image partition %d:%d present\n", MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device)); - pr_debug("Looking for hibernation image.\n"); + pm_pr_dbg("Looking for hibernation image.\n"); error = swsusp_check(); if (error) goto Unlock; @@ -875,7 +875,7 @@ static int software_resume(void) goto Close_Finish; } - pr_debug("Preparing processes for restore.\n"); + pm_pr_dbg("Preparing processes for restore.\n"); error = freeze_processes(); if (error) goto Close_Finish; @@ -888,7 +888,7 @@ static int software_resume(void) /* For success case, the suspend path will release the lock */ Unlock: mutex_unlock(&pm_mutex); - pr_debug("Hibernation image not present or could not be loaded.\n"); + pm_pr_dbg("Hibernation image not present or could not be loaded.\n"); return error; Close_Finish: swsusp_close(FMODE_READ); @@ -1012,8 +1012,8 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, error = -EINVAL; if (!error) - pr_debug("Hibernation mode set to '%s'\n", - hibernation_modes[mode]); + pm_pr_dbg("Hibernation mode set to '%s'\n", + hibernation_modes[mode]); unlock_system_sleep(); return error ? error : n; } diff --git a/kernel/power/main.c b/kernel/power/main.c index 42bd800a6755..5ce00902c7e3 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -361,6 +361,57 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj, power_attr_ro(pm_wakeup_irq); +static bool pm_debug_messages_on __read_mostly; + +static ssize_t pm_debug_messages_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", pm_debug_messages_on); +} + +static ssize_t pm_debug_messages_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (kstrtoul(buf, 10, &val)) + return -EINVAL; + + if (val > 1) + return -EINVAL; + + pm_debug_messages_on = !!val; + return n; +} + +power_attr(pm_debug_messages); + +/** + * pm_pr_dbg - Print a suspend debug message to the kernel log. + * @fmt: Message format. + * + * The message will be emitted if enabled through the pm_debug_messages + * sysfs attribute. + */ +void pm_pr_dbg(const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + if (!pm_debug_messages_on) + return; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + printk(KERN_DEBUG "PM: %pV", &vaf); + + va_end(args); +} + #else /* !CONFIG_PM_SLEEP_DEBUG */ static inline void pm_print_times_init(void) {} #endif /* CONFIG_PM_SLEEP_DEBUG */ @@ -697,6 +748,7 @@ static struct attribute * g[] = { #ifdef CONFIG_PM_SLEEP_DEBUG &pm_print_times_attr.attr, &pm_wakeup_irq_attr.attr, + &pm_debug_messages_attr.attr, #endif #endif #ifdef CONFIG_FREEZER diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index d0c0b96c2383..4f10773322fa 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -106,7 +106,7 @@ static void freeze_enter(void) static void s2idle_loop(void) { - pr_debug("PM: suspend-to-idle\n"); + pm_pr_dbg("suspend-to-idle\n"); do { freeze_enter(); @@ -124,7 +124,7 @@ static void s2idle_loop(void) pm_wakeup_clear(false); } while (!dpm_suspend_noirq(PMSG_SUSPEND)); - pr_debug("PM: resume from suspend-to-idle\n"); + pm_pr_dbg("resume from suspend-to-idle\n"); } void freeze_wake(void) @@ -547,7 +547,7 @@ static int enter_state(suspend_state_t state) trace_suspend_resume(TPS("sync_filesystems"), 0, false); #endif - pr_debug("PM: Preparing system for sleep (%s)\n", pm_states[state]); + pm_pr_dbg("Preparing system for sleep (%s)\n", pm_states[state]); pm_suspend_clear_flags(); error = suspend_prepare(state); if (error) @@ -557,13 +557,13 @@ static int enter_state(suspend_state_t state) goto Finish; trace_suspend_resume(TPS("suspend_enter"), state, false); - pr_debug("PM: Suspending system (%s)\n", pm_states[state]); + pm_pr_dbg("Suspending system (%s)\n", pm_states[state]); pm_restrict_gfp_mask(); error = suspend_devices_and_enter(state); pm_restore_gfp_mask(); Finish: - pr_debug("PM: Finishing wakeup.\n"); + pm_pr_dbg("Finishing wakeup.\n"); suspend_finish(); Unlock: mutex_unlock(&pm_mutex); From 8915aa2042f85ecf86d4a202ef6d04bf06f05cca Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 20 Jul 2017 03:38:07 +0200 Subject: [PATCH 03/18] PM / sleep: Mark suspend/hibernation start and finish Regardless of whether or not debug messages from the core system suspend/hibernation code are enabled, it is useful to know when system-wide transitions start and finish (or fail), so print "info" messages at these points. Signed-off-by: Rafael J. Wysocki Acked-by: Mark Salyzyn --- kernel/power/hibernate.c | 5 +++++ kernel/power/suspend.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index e19ee179d211..a5c36e9c56a6 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -692,6 +692,7 @@ int hibernate(void) goto Unlock; } + pr_info("hibernation entry\n"); pm_prepare_console(); error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls); if (error) { @@ -762,6 +763,8 @@ int hibernate(void) atomic_inc(&snapshot_device_available); Unlock: unlock_system_sleep(); + pr_info("hibernation exit\n"); + return error; } @@ -868,6 +871,7 @@ static int software_resume(void) goto Unlock; } + pr_info("resume from hibernation\n"); pm_prepare_console(); error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls); if (error) { @@ -884,6 +888,7 @@ static int software_resume(void) Finish: __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL); pm_restore_console(); + pr_info("resume from hibernation failed (%d)\n", error); atomic_inc(&snapshot_device_available); /* For success case, the suspend path will release the lock */ Unlock: diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 4f10773322fa..18cdb1596d27 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -584,6 +584,7 @@ int pm_suspend(suspend_state_t state) if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) return -EINVAL; + pr_info("PM: suspend entry (%s)\n", pm_states[state]); error = enter_state(state); if (error) { suspend_stats.fail++; @@ -591,6 +592,7 @@ int pm_suspend(suspend_state_t state) } else { suspend_stats.success++; } + pr_info("PM: suspend exit\n"); return error; } EXPORT_SYMBOL(pm_suspend); From cb08e0353c249a27aed10c6f60a13871ae449d33 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 23 Jul 2017 00:03:43 +0200 Subject: [PATCH 04/18] PM / timekeeping: Print debug messages when requested The messages printed by tk_debug_account_sleep_time() are basically useful for system sleep debugging, so print them only when the other debug messages from the core suspend/hibernate code are enabled. While at it, make it clear that the messages from tk_debug_account_sleep_time() are about timekeeping suspend duration, because in general timekeeping may be suspeded and resumed for multiple times during one system suspend-resume cycle. Signed-off-by: Rafael J. Wysocki --- include/linux/suspend.h | 10 ++++++++-- kernel/power/main.c | 10 +++++++--- kernel/time/timekeeping_debug.c | 5 +++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 707e4cdf21c2..97e394feabdb 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -492,16 +492,22 @@ static inline void unlock_system_sleep(void) {} #ifdef CONFIG_PM_SLEEP_DEBUG extern bool pm_print_times_enabled; -extern __printf(1, 2) void pm_pr_dbg(const char *fmt, ...); +extern __printf(2, 3) void __pm_pr_dbg(bool defer, const char *fmt, ...); #else #define pm_print_times_enabled (false) #include -#define pm_pr_dbg(fmt, ...) \ +#define __pm_pr_dbg(defer, fmt, ...) \ no_printk(KERN_DEBUG fmt, ##__VA_ARGS__) #endif +#define pm_pr_dbg(fmt, ...) \ + __pm_pr_dbg(false, fmt, ##__VA_ARGS__) + +#define pm_deferred_pr_dbg(fmt, ...) \ + __pm_pr_dbg(true, fmt, ##__VA_ARGS__) + #ifdef CONFIG_PM_AUTOSLEEP /* kernel/power/autosleep.c */ diff --git a/kernel/power/main.c b/kernel/power/main.c index 5ce00902c7e3..b7876eaf83f3 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -388,13 +388,14 @@ static ssize_t pm_debug_messages_store(struct kobject *kobj, power_attr(pm_debug_messages); /** - * pm_pr_dbg - Print a suspend debug message to the kernel log. + * __pm_pr_dbg - Print a suspend debug message to the kernel log. + * @defer: Whether or not to use printk_deferred() to print the message. * @fmt: Message format. * * The message will be emitted if enabled through the pm_debug_messages * sysfs attribute. */ -void pm_pr_dbg(const char *fmt, ...) +void __pm_pr_dbg(bool defer, const char *fmt, ...) { struct va_format vaf; va_list args; @@ -407,7 +408,10 @@ void pm_pr_dbg(const char *fmt, ...) vaf.fmt = fmt; vaf.va = &args; - printk(KERN_DEBUG "PM: %pV", &vaf); + if (defer) + printk_deferred(KERN_DEBUG "PM: %pV", &vaf); + else + printk(KERN_DEBUG "PM: %pV", &vaf); va_end(args); } diff --git a/kernel/time/timekeeping_debug.c b/kernel/time/timekeeping_debug.c index 38bc4d2208e8..0754cadfa9e6 100644 --- a/kernel/time/timekeeping_debug.c +++ b/kernel/time/timekeeping_debug.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "timekeeping_internal.h" @@ -75,7 +76,7 @@ void tk_debug_account_sleep_time(struct timespec64 *t) int bin = min(fls(t->tv_sec), NUM_BINS-1); sleep_time_bin[bin]++; - printk_deferred(KERN_INFO "Suspended for %lld.%03lu seconds\n", - (s64)t->tv_sec, t->tv_nsec / NSEC_PER_MSEC); + pm_deferred_pr_dbg("Timekeeping suspended for %lld.%03lu seconds\n", + (s64)t->tv_sec, t->tv_nsec / NSEC_PER_MSEC); } From 8e6bcd9f7eac47104ce6c5d82c554c9b244b38e1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 02:07:54 +0200 Subject: [PATCH 05/18] PM / s2idle: Rearrange the main suspend-to-idle loop As a preparation for subsequent changes, rearrange the core suspend-to-idle code by moving the initial invocation of dpm_suspend_noirq() into s2idle_loop(). This also causes debug messages from that code to appear in a less confusing order. Signed-off-by: Rafael J. Wysocki --- kernel/power/power.h | 4 ++++ kernel/power/suspend.c | 26 +++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/kernel/power/power.h b/kernel/power/power.h index 7fdc40d31b7d..6e3ac6a73d65 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -245,7 +245,11 @@ enum { #define TEST_FIRST TEST_NONE #define TEST_MAX (__TEST_AFTER_LAST - 1) +#ifdef CONFIG_PM_DEBUG extern int pm_test_level; +#else +#define pm_test_level (TEST_NONE) +#endif #ifdef CONFIG_SUSPEND_FREEZER static inline int suspend_freeze_processes(void) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 18cdb1596d27..0c61713b6e5c 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -108,7 +108,13 @@ static void s2idle_loop(void) { pm_pr_dbg("suspend-to-idle\n"); - do { + while (!dpm_suspend_noirq(PMSG_SUSPEND)) { + /* + * Suspend-to-idle equals + * frozen processes + suspended devices + idle processors. + * Thus freeze_enter() should be called right after + * all devices have been suspended. + */ freeze_enter(); if (freeze_ops && freeze_ops->wake) @@ -122,7 +128,7 @@ static void s2idle_loop(void) break; pm_wakeup_clear(false); - } while (!dpm_suspend_noirq(PMSG_SUSPEND)); + } pm_pr_dbg("resume from suspend-to-idle\n"); } @@ -379,6 +385,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (error) goto Devices_early_resume; + if (state == PM_SUSPEND_FREEZE && pm_test_level != TEST_PLATFORM) { + s2idle_loop(); + goto Platform_early_resume; + } + error = dpm_suspend_noirq(PMSG_SUSPEND); if (error) { pr_err("PM: noirq suspend of devices failed\n"); @@ -391,17 +402,6 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (suspend_test(TEST_PLATFORM)) goto Platform_wake; - /* - * PM_SUSPEND_FREEZE equals - * frozen processes + suspended devices + idle processors. - * Thus we should invoke freeze_enter() soon after - * all the devices are suspended. - */ - if (state == PM_SUSPEND_FREEZE) { - s2idle_loop(); - goto Platform_early_resume; - } - error = disable_nonboot_cpus(); if (error || suspend_test(TEST_CPUS)) goto Enable_cpus; From 786f41fb6b008ea4341355b99083a38853a5311d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 02:09:22 +0200 Subject: [PATCH 06/18] PM / core: Split dpm_suspend_noirq() and dpm_resume_noirq() Put the device interrupts disabling and enabling as well as cpuidle_pause() and cpuidle_resume() called during the "noirq" stages of system suspend into separate functions to allow the core suspend-to-idle code to be optimized (later). The only functional difference this makes is that debug facilities and diagnostic tools will not include the above operations into the "noirq" device suspend/resume duration measurements. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 67 +++++++++++++++++++++++++++------------ include/linux/pm.h | 4 +++ 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 4f5fc212d684..9b194e9f49a9 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -598,14 +598,7 @@ static void async_resume_noirq(void *data, async_cookie_t cookie) put_device(dev); } -/** - * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. - * @state: PM transition of the system being carried out. - * - * Call the "noirq" resume handlers for all devices in dpm_noirq_list and - * enable device drivers to receive interrupts. - */ -void dpm_resume_noirq(pm_message_t state) +void dpm_noirq_resume_devices(pm_message_t state) { struct device *dev; ktime_t starttime = ktime_get(); @@ -651,10 +644,27 @@ void dpm_resume_noirq(pm_message_t state) mutex_unlock(&dpm_list_mtx); async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); + trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); +} + +void dpm_noirq_end(void) +{ resume_device_irqs(); device_wakeup_disarm_wake_irqs(); cpuidle_resume(); - trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); +} + +/** + * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. + * @state: PM transition of the system being carried out. + * + * Invoke the "noirq" resume callbacks for all devices in dpm_noirq_list and + * allow device drivers' interrupt handlers to be called. + */ +void dpm_resume_noirq(pm_message_t state) +{ + dpm_noirq_resume_devices(state); + dpm_noirq_end(); } /** @@ -1154,22 +1164,19 @@ static int device_suspend_noirq(struct device *dev) return __device_suspend_noirq(dev, pm_transition, false); } -/** - * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. - * @state: PM transition of the system being carried out. - * - * Prevent device drivers from receiving interrupts and call the "noirq" suspend - * handlers for all non-sysdev devices. - */ -int dpm_suspend_noirq(pm_message_t state) +void dpm_noirq_begin(void) +{ + cpuidle_pause(); + device_wakeup_arm_wake_irqs(); + suspend_device_irqs(); +} + +int dpm_noirq_suspend_devices(pm_message_t state) { ktime_t starttime = ktime_get(); int error = 0; trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true); - cpuidle_pause(); - device_wakeup_arm_wake_irqs(); - suspend_device_irqs(); mutex_lock(&dpm_list_mtx); pm_transition = state; async_error = 0; @@ -1204,7 +1211,6 @@ int dpm_suspend_noirq(pm_message_t state) if (error) { suspend_stats.failed_suspend_noirq++; dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); - dpm_resume_noirq(resume_event(state)); } else { dpm_show_time(starttime, state, "noirq"); } @@ -1212,6 +1218,25 @@ int dpm_suspend_noirq(pm_message_t state) return error; } +/** + * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. + * @state: PM transition of the system being carried out. + * + * Prevent device drivers' interrupt handlers from being called and invoke + * "noirq" suspend callbacks for all non-sysdev devices. + */ +int dpm_suspend_noirq(pm_message_t state) +{ + int ret; + + dpm_noirq_begin(); + ret = dpm_noirq_suspend_devices(state); + if (ret) + dpm_resume_noirq(resume_event(state)); + + return ret; +} + /** * device_suspend_late - Execute a "late suspend" callback for given device. * @dev: Device to handle. diff --git a/include/linux/pm.h b/include/linux/pm.h index b8b4df09fd8f..47ded8aa8a5d 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -689,6 +689,8 @@ 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_noirq_resume_devices(pm_message_t state); +extern void dpm_noirq_end(void); 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); @@ -697,6 +699,8 @@ 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 void dpm_noirq_begin(void); +extern int dpm_noirq_suspend_devices(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); From 48059c095bafc2ba23da1b3fa26b6ba142cb854f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 02:10:22 +0200 Subject: [PATCH 07/18] PM / core: Add error argument to dpm_show_time() Make the core device suspend/resume code also call dpm_show_time() on failures and add an error argument to this function so that the message printed by it can reflect the success or failure condition. This makes the debug messages in question look less confusing in the failing cases. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9b194e9f49a9..f64e5b819e5c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -418,7 +418,7 @@ static void pm_dev_err(struct device *dev, pm_message_t state, const char *info, dev_name(dev), pm_verb(state.event), info, error); } -static void dpm_show_time(ktime_t starttime, pm_message_t state, +static void dpm_show_time(ktime_t starttime, pm_message_t state, int error, const char *info) { ktime_t calltime; @@ -432,8 +432,9 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, if (usecs == 0) usecs = 1; - pm_pr_dbg("%s%s%s of devices complete after %ld.%03ld msecs\n", + pm_pr_dbg("%s%s%s of devices %s after %ld.%03ld msecs\n", info ?: "", info ? " " : "", pm_verb(state.event), + error ? "aborted" : "complete", usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); } @@ -643,7 +644,7 @@ void dpm_noirq_resume_devices(pm_message_t state) } mutex_unlock(&dpm_list_mtx); async_synchronize_full(); - dpm_show_time(starttime, state, "noirq"); + dpm_show_time(starttime, state, 0, "noirq"); trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); } @@ -782,7 +783,7 @@ void dpm_resume_early(pm_message_t state) } mutex_unlock(&dpm_list_mtx); async_synchronize_full(); - dpm_show_time(starttime, state, "early"); + dpm_show_time(starttime, state, 0, "early"); trace_suspend_resume(TPS("dpm_resume_early"), state.event, false); } @@ -954,7 +955,7 @@ void dpm_resume(pm_message_t state) } mutex_unlock(&dpm_list_mtx); async_synchronize_full(); - dpm_show_time(starttime, state, NULL); + dpm_show_time(starttime, state, 0, NULL); cpufreq_resume(); trace_suspend_resume(TPS("dpm_resume"), state.event, false); @@ -1211,9 +1212,8 @@ int dpm_noirq_suspend_devices(pm_message_t state) if (error) { suspend_stats.failed_suspend_noirq++; dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); - } else { - dpm_show_time(starttime, state, "noirq"); } + dpm_show_time(starttime, state, error, "noirq"); trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, false); return error; } @@ -1371,9 +1371,8 @@ int dpm_suspend_late(pm_message_t state) suspend_stats.failed_suspend_late++; dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_resume_early(resume_event(state)); - } else { - dpm_show_time(starttime, state, "late"); } + dpm_show_time(starttime, state, error, "late"); trace_suspend_resume(TPS("dpm_suspend_late"), state.event, false); return error; } @@ -1639,8 +1638,8 @@ int dpm_suspend(pm_message_t state) if (error) { suspend_stats.failed_suspend++; dpm_save_failed_step(SUSPEND_SUSPEND); - } else - dpm_show_time(starttime, state, NULL); + } + dpm_show_time(starttime, state, error, NULL); trace_suspend_resume(TPS("dpm_suspend"), state.event, false); return error; } From 9a3ebe3523cc8297301d5d95332536ad123856bf Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 02:12:10 +0200 Subject: [PATCH 08/18] PM / sleep: Check pm_wakeup_pending() in __device_suspend_noirq() Restore the pm_wakeup_pending() check in __device_suspend_noirq() removed by commit eed4d47efe95 (ACPI / sleep: Ignore spurious SCI wakeups from suspend-to-idle) as that allows the function to return earlier if there's a wakeup event pending already (so that it may spend less time on carrying out operations that will be reversed shortly anyway) and rework the main suspend-to-idle loop to take that optimization into account. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 5 +++++ kernel/power/suspend.c | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index f64e5b819e5c..ea1732ed7a9d 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1105,6 +1105,11 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (async_error) goto Complete; + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } + if (dev->power.syscore || dev->power.direct_complete) goto Complete; diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 0c61713b6e5c..5cf232795318 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -108,19 +108,32 @@ static void s2idle_loop(void) { pm_pr_dbg("suspend-to-idle\n"); - while (!dpm_suspend_noirq(PMSG_SUSPEND)) { + for (;;) { + int error; + + dpm_noirq_begin(); + /* * Suspend-to-idle equals * frozen processes + suspended devices + idle processors. * Thus freeze_enter() should be called right after * all devices have been suspended. */ - freeze_enter(); + error = dpm_noirq_suspend_devices(PMSG_SUSPEND); + if (!error) + freeze_enter(); + + dpm_noirq_resume_devices(PMSG_RESUME); + if (error && (error != -EBUSY || !pm_wakeup_pending())) { + dpm_noirq_end(); + break; + } if (freeze_ops && freeze_ops->wake) freeze_ops->wake(); - dpm_resume_noirq(PMSG_RESUME); + dpm_noirq_end(); + if (freeze_ops && freeze_ops->sync) freeze_ops->sync(); From e516a1db43cea397cf63d395534236d9869f0310 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 14:44:02 +0200 Subject: [PATCH 09/18] PM / sleep: Put pm_test under CONFIG_PM_SLEEP_DEBUG The pm_test sysfs attribute is under CONFIG_PM_DEBUG, but it doesn't make sense to provide it if CONFIG_PM_SLEEP is unset, so put it under CONFIG_PM_SLEEP_DEBUG instead. Signed-off-by: Rafael J. Wysocki --- kernel/power/main.c | 8 +++----- kernel/power/power.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/kernel/power/main.c b/kernel/power/main.c index b7876eaf83f3..3074ea4cec0a 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -150,7 +150,7 @@ static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr power_attr(mem_sleep); #endif /* CONFIG_SUSPEND */ -#ifdef CONFIG_PM_DEBUG +#ifdef CONFIG_PM_SLEEP_DEBUG int pm_test_level = TEST_NONE; static const char * const pm_tests[__TEST_AFTER_LAST] = { @@ -211,7 +211,7 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, } power_attr(pm_test); -#endif /* CONFIG_PM_DEBUG */ +#endif /* CONFIG_PM_SLEEP_DEBUG */ #ifdef CONFIG_DEBUG_FS static char *suspend_step_name(enum suspend_stat_step step) @@ -746,10 +746,8 @@ static struct attribute * g[] = { &wake_lock_attr.attr, &wake_unlock_attr.attr, #endif -#ifdef CONFIG_PM_DEBUG - &pm_test_attr.attr, -#endif #ifdef CONFIG_PM_SLEEP_DEBUG + &pm_test_attr.attr, &pm_print_times_attr.attr, &pm_wakeup_irq_attr.attr, &pm_debug_messages_attr.attr, diff --git a/kernel/power/power.h b/kernel/power/power.h index 6e3ac6a73d65..268c1b0afc28 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -245,7 +245,7 @@ enum { #define TEST_FIRST TEST_NONE #define TEST_MAX (__TEST_AFTER_LAST - 1) -#ifdef CONFIG_PM_DEBUG +#ifdef CONFIG_PM_SLEEP_DEBUG extern int pm_test_level; #else #define pm_test_level (TEST_NONE) From bebcdae3ec13b2171ff91594787ab37b3fdb3306 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 14:49:51 +0200 Subject: [PATCH 10/18] PM / suspend: Use mem_sleep_labels[] strings in messages Some messages in suspend.c currently print state names from pm_states[], but that may be confusing if the mem_sleep sysfs attribute is changed to anything different from "mem", because in those cases the messages will say either "freeze" or "standby" after writing "mem" to /sys/power/state. To avoid the confusion, use mem_sleep_labels[] strings in those messages instead. Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- kernel/power/suspend.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 5cf232795318..a3d270e2e313 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -560,7 +560,7 @@ static int enter_state(suspend_state_t state) trace_suspend_resume(TPS("sync_filesystems"), 0, false); #endif - pm_pr_dbg("Preparing system for sleep (%s)\n", pm_states[state]); + pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]); pm_suspend_clear_flags(); error = suspend_prepare(state); if (error) @@ -570,7 +570,7 @@ static int enter_state(suspend_state_t state) goto Finish; trace_suspend_resume(TPS("suspend_enter"), state, false); - pm_pr_dbg("Suspending system (%s)\n", pm_states[state]); + pm_pr_dbg("Suspending system (%s)\n", mem_sleep_labels[state]); pm_restrict_gfp_mask(); error = suspend_devices_and_enter(state); pm_restore_gfp_mask(); @@ -597,7 +597,7 @@ int pm_suspend(suspend_state_t state) if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) return -EINVAL; - pr_info("PM: suspend entry (%s)\n", pm_states[state]); + pr_info("PM: suspend entry (%s)\n", mem_sleep_labels[state]); error = enter_state(state); if (error) { suspend_stats.fail++; From 142bce74fd141913b2127970a9bd90f33c5b7653 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 21 Jul 2017 14:50:48 +0200 Subject: [PATCH 11/18] PM / suspend: Define pr_fmt() in suspend.c Define a common prefix ("PM:") for messages printed by the code in kernel/power/suspend.c. Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko --- kernel/power/suspend.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index a3d270e2e313..4bce46ddc2cd 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -8,6 +8,8 @@ * This file is released under the GPLv2. */ +#define pr_fmt(fmt) "PM: " fmt + #include #include #include @@ -391,7 +393,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) error = dpm_suspend_late(PMSG_SUSPEND); if (error) { - pr_err("PM: late suspend of devices failed\n"); + pr_err("late suspend of devices failed\n"); goto Platform_finish; } error = platform_suspend_prepare_late(state); @@ -405,7 +407,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) error = dpm_suspend_noirq(PMSG_SUSPEND); if (error) { - pr_err("PM: noirq suspend of devices failed\n"); + pr_err("noirq suspend of devices failed\n"); goto Platform_early_resume; } error = platform_suspend_prepare_noirq(state); @@ -481,7 +483,7 @@ int suspend_devices_and_enter(suspend_state_t state) suspend_test_start(); error = dpm_suspend_start(PMSG_SUSPEND); if (error) { - pr_err("PM: Some devices failed to suspend, or early wake event detected\n"); + pr_err("Some devices failed to suspend, or early wake event detected\n"); goto Recover_platform; } suspend_test_finish("suspend devices"); @@ -539,7 +541,7 @@ static int enter_state(suspend_state_t state) if (state == PM_SUSPEND_FREEZE) { #ifdef CONFIG_PM_DEBUG if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) { - pr_warn("PM: Unsupported test mode for suspend to idle, please choose none/freezer/devices/platform.\n"); + pr_warn("Unsupported test mode for suspend to idle, please choose none/freezer/devices/platform.\n"); return -EAGAIN; } #endif @@ -554,7 +556,7 @@ static int enter_state(suspend_state_t state) #ifndef CONFIG_SUSPEND_SKIP_SYNC trace_suspend_resume(TPS("sync_filesystems"), 0, true); - pr_info("PM: Syncing filesystems ... "); + pr_info("Syncing filesystems ... "); sys_sync(); pr_cont("done.\n"); trace_suspend_resume(TPS("sync_filesystems"), 0, false); @@ -597,7 +599,7 @@ int pm_suspend(suspend_state_t state) if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) return -EINVAL; - pr_info("PM: suspend entry (%s)\n", mem_sleep_labels[state]); + pr_info("suspend entry (%s)\n", mem_sleep_labels[state]); error = enter_state(state); if (error) { suspend_stats.fail++; @@ -605,7 +607,7 @@ int pm_suspend(suspend_state_t state) } else { suspend_stats.success++; } - pr_info("PM: suspend exit\n"); + pr_info("suspend exit\n"); return error; } EXPORT_SYMBOL(pm_suspend); From 635173a17b0323c28a39fb06fa36d876035cd2b9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 28 Jul 2017 02:06:36 +0200 Subject: [PATCH 12/18] platform/x86: intel-hid: Wake up Dell Latitude 7275 from suspend-to-idle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Dell Latitude 7275 the 5-button array is not exposed in the ACPI tables, but still notifies are sent to the Intel HID device object (device ID INT33D5) in response to power button actions while suspended to idle. However, they are currently ignored as the intel-hid driver is not prepared to take care of them. As a result, power button wakeup from suspend-to-idle doesn't work on this platform, but suspend-to-idle is the only reliable suspend variant on it (the S3 implementation in the platform firmware turns out to be broken), so it would be good to handle it properly. For this reason, add an upfront check against the power button press event (0xCE) to notify_handler() in the wakeup mode which allows it to catch the power button wakeup notification on the affected platform (even though priv->array is NULL on it) and should not change the behavior on platforms with priv->array present (because priv->array contains the event in question in those cases). Link: https://bugzilla.kernel.org/show_bug.cgi?id=196115 Tested-by: Jérôme de Bretagne Signed-off-by: Rafael J. Wysocki Acked-by: Andy Shevchenko Acked-By: Mario Limonciello --- drivers/platform/x86/intel-hid.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index 8519e0f97bdd..a782c78e7c63 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -203,15 +203,26 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) acpi_status status; if (priv->wakeup_mode) { + /* + * Needed for wakeup from suspend-to-idle to work on some + * platforms that don't expose the 5-button array, but still + * send notifies with the power button event code to this + * device object on power button actions while suspended. + */ + if (event == 0xce) + goto wakeup; + /* Wake up on 5-button array events only. */ if (event == 0xc0 || !priv->array) return; - if (sparse_keymap_entry_from_scancode(priv->array, event)) - pm_wakeup_hard_event(&device->dev); - else + if (!sparse_keymap_entry_from_scancode(priv->array, event)) { dev_info(&device->dev, "unknown event 0x%x\n", event); + return; + } +wakeup: + pm_wakeup_hard_event(&device->dev); return; } From e870c6c87cf9484090d28f2a68aa29e008960c93 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 31 Jul 2017 23:43:18 +0200 Subject: [PATCH 13/18] ACPI / PM: Prefer suspend-to-idle over S3 on some systems Modify the ACPI system sleep support setup code to select suspend-to-idle as the default system sleep state if (1) the ACPI_FADT_LOW_POWER_S0 flag is set in the FADT and (2) the Low Power Idle S0 _DSM interface has been discovered and (3) the default sleep state was not selected from the kernel command line. The main motivation for this change is that systems where the (1) and (2) conditions are met typically ship with OSes that don't exercise the S3 path in the platform firmware which remains untested and turns out to be non-functional at least in some cases. Signed-off-by: Rafael J. Wysocki Tested-by: Mario Limonciello --- Documentation/power/states.txt | 4 +++- drivers/acpi/sleep.c | 6 ++++++ include/linux/suspend.h | 3 +++ kernel/power/power.h | 1 - kernel/power/suspend.c | 4 ++-- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Documentation/power/states.txt b/Documentation/power/states.txt index bc4548245a24..205e45ad7c65 100644 --- a/Documentation/power/states.txt +++ b/Documentation/power/states.txt @@ -35,7 +35,9 @@ only one way to cause the system to go into the Suspend-To-RAM state (write The default suspend mode (ie. the one to be used without writing anything into /sys/power/mem_sleep) is either "deep" (if Suspend-To-RAM is supported) or "s2idle", but it can be overridden by the value of the "mem_sleep_default" -parameter in the kernel command line. +parameter in the kernel command line. On some ACPI-based systems, depending on +the information in the FADT, the default may be "s2idle" even if Suspend-To-RAM +is supported. The properties of all of the sleep states are described below. diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index be17664736b2..b363283dfcd9 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -714,6 +714,12 @@ static int lps0_device_attach(struct acpi_device *adev, if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { lps0_dsm_func_mask = bitmask; lps0_device_handle = adev->handle; + /* + * Use suspend-to-idle by default if the default + * suspend mode was not set from the command line. + */ + if (mem_sleep_default > PM_SUSPEND_MEM) + mem_sleep_current = PM_SUSPEND_FREEZE; } acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 97e394feabdb..8c3b0b1e6786 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -196,6 +196,9 @@ struct platform_freeze_ops { }; #ifdef CONFIG_SUSPEND +extern suspend_state_t mem_sleep_current; +extern suspend_state_t mem_sleep_default; + /** * suspend_set_ops - set platform dependent suspend operations * @ops: The new suspend operations to set. diff --git a/kernel/power/power.h b/kernel/power/power.h index 268c1b0afc28..1d2d761e3c25 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -192,7 +192,6 @@ extern void swsusp_show_speed(ktime_t, ktime_t, unsigned int, char *); extern const char * const pm_labels[]; extern const char *pm_states[]; extern const char *mem_sleep_states[]; -extern suspend_state_t mem_sleep_current; extern int suspend_devices_and_enter(suspend_state_t state); #else /* !CONFIG_SUSPEND */ diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 4bce46ddc2cd..0639d3a79852 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -48,7 +48,7 @@ static const char * const mem_sleep_labels[] = { const char *mem_sleep_states[PM_SUSPEND_MAX]; suspend_state_t mem_sleep_current = PM_SUSPEND_FREEZE; -static suspend_state_t mem_sleep_default = PM_SUSPEND_MEM; +suspend_state_t mem_sleep_default = PM_SUSPEND_MAX; suspend_state_t pm_suspend_target_state; EXPORT_SYMBOL_GPL(pm_suspend_target_state); @@ -216,7 +216,7 @@ void suspend_set_ops(const struct platform_suspend_ops *ops) } if (valid_state(PM_SUSPEND_MEM)) { mem_sleep_states[PM_SUSPEND_MEM] = mem_sleep_labels[PM_SUSPEND_MEM]; - if (mem_sleep_default == PM_SUSPEND_MEM) + if (mem_sleep_default >= PM_SUSPEND_MEM) mem_sleep_current = PM_SUSPEND_MEM; } From 690cbb90a709c1b9389c6cb8e1978e77553ce0fb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:13:07 +0200 Subject: [PATCH 14/18] PM / s2idle: Rename PM_SUSPEND_FREEZE to PM_SUSPEND_TO_IDLE To make it clear that the symbol in question refers to suspend-to-idle, rename it from PM_SUSPEND_FREEZE to PM_SUSPEND_TO_IDLE. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 2 +- drivers/regulator/of_regulator.c | 2 +- include/linux/suspend.h | 4 +-- kernel/power/suspend.c | 44 ++++++++++++++++---------------- kernel/power/suspend_test.c | 4 +-- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index b363283dfcd9..a0a6fd10fb5f 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -719,7 +719,7 @@ static int lps0_device_attach(struct acpi_device *adev, * suspend mode was not set from the command line. */ if (mem_sleep_default > PM_SUSPEND_MEM) - mem_sleep_current = PM_SUSPEND_FREEZE; + mem_sleep_current = PM_SUSPEND_TO_IDLE; } acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 96bf75458da5..860480ecf2be 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -150,7 +150,7 @@ static void of_get_regulation_constraints(struct device_node *np, suspend_state = &constraints->state_disk; break; case PM_SUSPEND_ON: - case PM_SUSPEND_FREEZE: + case PM_SUSPEND_TO_IDLE: case PM_SUSPEND_STANDBY: default: continue; diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 8c3b0b1e6786..d43654be0097 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -33,10 +33,10 @@ static inline void pm_restore_console(void) typedef int __bitwise suspend_state_t; #define PM_SUSPEND_ON ((__force suspend_state_t) 0) -#define PM_SUSPEND_FREEZE ((__force suspend_state_t) 1) +#define PM_SUSPEND_TO_IDLE ((__force suspend_state_t) 1) #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2) #define PM_SUSPEND_MEM ((__force suspend_state_t) 3) -#define PM_SUSPEND_MIN PM_SUSPEND_FREEZE +#define PM_SUSPEND_MIN PM_SUSPEND_TO_IDLE #define PM_SUSPEND_MAX ((__force suspend_state_t) 4) enum suspend_stat_step { diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 0639d3a79852..6333078a438b 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -35,19 +35,19 @@ #include "power.h" const char * const pm_labels[] = { - [PM_SUSPEND_FREEZE] = "freeze", + [PM_SUSPEND_TO_IDLE] = "freeze", [PM_SUSPEND_STANDBY] = "standby", [PM_SUSPEND_MEM] = "mem", }; const char *pm_states[PM_SUSPEND_MAX]; static const char * const mem_sleep_labels[] = { - [PM_SUSPEND_FREEZE] = "s2idle", + [PM_SUSPEND_TO_IDLE] = "s2idle", [PM_SUSPEND_STANDBY] = "shallow", [PM_SUSPEND_MEM] = "deep", }; const char *mem_sleep_states[PM_SUSPEND_MAX]; -suspend_state_t mem_sleep_current = PM_SUSPEND_FREEZE; +suspend_state_t mem_sleep_current = PM_SUSPEND_TO_IDLE; suspend_state_t mem_sleep_default = PM_SUSPEND_MAX; suspend_state_t pm_suspend_target_state; EXPORT_SYMBOL_GPL(pm_suspend_target_state); @@ -76,7 +76,7 @@ static void freeze_begin(void) static void freeze_enter(void) { - trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, true); + trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, true); spin_lock_irq(&suspend_freeze_lock); if (pm_wakeup_pending()) @@ -103,7 +103,7 @@ static void freeze_enter(void) suspend_freeze_state = FREEZE_STATE_NONE; spin_unlock_irq(&suspend_freeze_lock); - trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, false); + trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, false); } static void s2idle_loop(void) @@ -175,19 +175,19 @@ void __init pm_states_init(void) { /* "mem" and "freeze" are always present in /sys/power/state. */ pm_states[PM_SUSPEND_MEM] = pm_labels[PM_SUSPEND_MEM]; - pm_states[PM_SUSPEND_FREEZE] = pm_labels[PM_SUSPEND_FREEZE]; + pm_states[PM_SUSPEND_TO_IDLE] = pm_labels[PM_SUSPEND_TO_IDLE]; /* * Suspend-to-idle should be supported even without any suspend_ops, * initialize mem_sleep_states[] accordingly here. */ - mem_sleep_states[PM_SUSPEND_FREEZE] = mem_sleep_labels[PM_SUSPEND_FREEZE]; + mem_sleep_states[PM_SUSPEND_TO_IDLE] = mem_sleep_labels[PM_SUSPEND_TO_IDLE]; } static int __init mem_sleep_default_setup(char *str) { suspend_state_t state; - for (state = PM_SUSPEND_FREEZE; state <= PM_SUSPEND_MEM; state++) + for (state = PM_SUSPEND_TO_IDLE; state <= PM_SUSPEND_MEM; state++) if (mem_sleep_labels[state] && !strcmp(str, mem_sleep_labels[state])) { mem_sleep_default = state; @@ -239,48 +239,48 @@ EXPORT_SYMBOL_GPL(suspend_valid_only_mem); static bool sleep_state_supported(suspend_state_t state) { - return state == PM_SUSPEND_FREEZE || (suspend_ops && suspend_ops->enter); + return state == PM_SUSPEND_TO_IDLE || (suspend_ops && suspend_ops->enter); } static int platform_suspend_prepare(suspend_state_t state) { - return state != PM_SUSPEND_FREEZE && suspend_ops->prepare ? + return state != PM_SUSPEND_TO_IDLE && suspend_ops->prepare ? suspend_ops->prepare() : 0; } static int platform_suspend_prepare_late(suspend_state_t state) { - return state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->prepare ? + return state == PM_SUSPEND_TO_IDLE && freeze_ops && 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 ? + return state != PM_SUSPEND_TO_IDLE && suspend_ops->prepare_late ? suspend_ops->prepare_late() : 0; } static void platform_resume_noirq(suspend_state_t state) { - if (state != PM_SUSPEND_FREEZE && suspend_ops->wake) + if (state != PM_SUSPEND_TO_IDLE && suspend_ops->wake) suspend_ops->wake(); } static void platform_resume_early(suspend_state_t state) { - if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->restore) + if (state == PM_SUSPEND_TO_IDLE && freeze_ops && freeze_ops->restore) freeze_ops->restore(); } static void platform_resume_finish(suspend_state_t state) { - if (state != PM_SUSPEND_FREEZE && suspend_ops->finish) + if (state != PM_SUSPEND_TO_IDLE && suspend_ops->finish) suspend_ops->finish(); } static int platform_suspend_begin(suspend_state_t state) { - if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->begin) + if (state == PM_SUSPEND_TO_IDLE && freeze_ops && freeze_ops->begin) return freeze_ops->begin(); else if (suspend_ops && suspend_ops->begin) return suspend_ops->begin(state); @@ -290,7 +290,7 @@ static int platform_suspend_begin(suspend_state_t state) static void platform_resume_end(suspend_state_t state) { - if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->end) + if (state == PM_SUSPEND_TO_IDLE && freeze_ops && freeze_ops->end) freeze_ops->end(); else if (suspend_ops && suspend_ops->end) suspend_ops->end(); @@ -298,13 +298,13 @@ static void platform_resume_end(suspend_state_t state) static void platform_recover(suspend_state_t state) { - if (state != PM_SUSPEND_FREEZE && suspend_ops->recover) + if (state != PM_SUSPEND_TO_IDLE && suspend_ops->recover) suspend_ops->recover(); } static bool platform_suspend_again(suspend_state_t state) { - return state != PM_SUSPEND_FREEZE && suspend_ops->suspend_again ? + return state != PM_SUSPEND_TO_IDLE && suspend_ops->suspend_again ? suspend_ops->suspend_again() : false; } @@ -400,7 +400,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (error) goto Devices_early_resume; - if (state == PM_SUSPEND_FREEZE && pm_test_level != TEST_PLATFORM) { + if (state == PM_SUSPEND_TO_IDLE && pm_test_level != TEST_PLATFORM) { s2idle_loop(); goto Platform_early_resume; } @@ -538,7 +538,7 @@ static int enter_state(suspend_state_t state) int error; trace_suspend_resume(TPS("suspend_enter"), state, true); - if (state == PM_SUSPEND_FREEZE) { + if (state == PM_SUSPEND_TO_IDLE) { #ifdef CONFIG_PM_DEBUG if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) { pr_warn("Unsupported test mode for suspend to idle, please choose none/freezer/devices/platform.\n"); @@ -551,7 +551,7 @@ static int enter_state(suspend_state_t state) if (!mutex_trylock(&pm_mutex)) return -EBUSY; - if (state == PM_SUSPEND_FREEZE) + if (state == PM_SUSPEND_TO_IDLE) freeze_begin(); #ifndef CONFIG_SUSPEND_SKIP_SYNC diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c index 5db217051232..6a897e8b2a88 100644 --- a/kernel/power/suspend_test.c +++ b/kernel/power/suspend_test.c @@ -104,9 +104,9 @@ repeat: printk(info_test, pm_states[state]); status = pm_suspend(state); if (status < 0) - state = PM_SUSPEND_FREEZE; + state = PM_SUSPEND_TO_IDLE; } - if (state == PM_SUSPEND_FREEZE) { + if (state == PM_SUSPEND_TO_IDLE) { printk(info_test, pm_states[state]); status = pm_suspend(state); } From f02f4f9d826590f1ef1b087374d3e3cfb7949eac Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:13:56 +0200 Subject: [PATCH 15/18] PM / s2idle: Rename freeze_state enum and related items Rename the freeze_state enum representing the suspend-to-idle state machine states to s2idle_states and rename the related variables and functions accordingly. Signed-off-by: Rafael J. Wysocki --- drivers/base/power/wakeup.c | 2 +- include/linux/suspend.h | 20 ++++++++-------- kernel/power/suspend.c | 48 ++++++++++++++++++------------------- kernel/sched/idle.c | 6 ++--- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 144e6d8fafc8..34aebf3e460b 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -863,7 +863,7 @@ bool pm_wakeup_pending(void) void pm_system_wakeup(void) { atomic_inc(&pm_abort_suspend); - freeze_wake(); + s2idle_wake(); } EXPORT_SYMBOL_GPL(pm_system_wakeup); diff --git a/include/linux/suspend.h b/include/linux/suspend.h index d43654be0097..feb43dfbf7bc 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -237,22 +237,22 @@ static inline bool pm_resume_via_firmware(void) } /* Suspend-to-idle state machnine. */ -enum freeze_state { - FREEZE_STATE_NONE, /* Not suspended/suspending. */ - FREEZE_STATE_ENTER, /* Enter suspend-to-idle. */ - FREEZE_STATE_WAKE, /* Wake up from suspend-to-idle. */ +enum s2idle_states { + S2IDLE_STATE_NONE, /* Not suspended/suspending. */ + S2IDLE_STATE_ENTER, /* Enter suspend-to-idle. */ + S2IDLE_STATE_WAKE, /* Wake up from suspend-to-idle. */ }; -extern enum freeze_state __read_mostly suspend_freeze_state; +extern enum s2idle_states __read_mostly s2idle_state; -static inline bool idle_should_freeze(void) +static inline bool idle_should_enter_s2idle(void) { - return unlikely(suspend_freeze_state == FREEZE_STATE_ENTER); + return unlikely(s2idle_state == S2IDLE_STATE_ENTER); } extern void __init pm_states_init(void); extern void freeze_set_ops(const struct platform_freeze_ops *ops); -extern void freeze_wake(void); +extern void s2idle_wake(void); /** * arch_suspend_disable_irqs - disable IRQs for suspend @@ -284,10 +284,10 @@ static inline bool pm_resume_via_firmware(void) { return false; } static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } -static inline bool idle_should_freeze(void) { return false; } +static inline bool idle_should_enter_s2idle(void) { return false; } static inline void __init pm_states_init(void) {} static inline void freeze_set_ops(const struct platform_freeze_ops *ops) {} -static inline void freeze_wake(void) {} +static inline void s2idle_wake(void) {} #endif /* !CONFIG_SUSPEND */ /* struct pbe is used for creating lists of pages that should be restored diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 6333078a438b..ae9b579c2533 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -57,10 +57,10 @@ EXPORT_SYMBOL_GPL(pm_suspend_global_flags); static const struct platform_suspend_ops *suspend_ops; static const struct platform_freeze_ops *freeze_ops; -static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head); +static DECLARE_WAIT_QUEUE_HEAD(s2idle_wait_head); -enum freeze_state __read_mostly suspend_freeze_state; -static DEFINE_SPINLOCK(suspend_freeze_lock); +enum s2idle_states __read_mostly s2idle_state; +static DEFINE_SPINLOCK(s2idle_lock); void freeze_set_ops(const struct platform_freeze_ops *ops) { @@ -69,21 +69,21 @@ void freeze_set_ops(const struct platform_freeze_ops *ops) unlock_system_sleep(); } -static void freeze_begin(void) +static void s2idle_begin(void) { - suspend_freeze_state = FREEZE_STATE_NONE; + s2idle_state = S2IDLE_STATE_NONE; } -static void freeze_enter(void) +static void s2idle_enter(void) { trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, true); - spin_lock_irq(&suspend_freeze_lock); + spin_lock_irq(&s2idle_lock); if (pm_wakeup_pending()) goto out; - suspend_freeze_state = FREEZE_STATE_ENTER; - spin_unlock_irq(&suspend_freeze_lock); + s2idle_state = S2IDLE_STATE_ENTER; + spin_unlock_irq(&s2idle_lock); get_online_cpus(); cpuidle_resume(); @@ -91,17 +91,17 @@ static void freeze_enter(void) /* Push all the CPUs into the idle loop. */ wake_up_all_idle_cpus(); /* Make the current CPU wait so it can enter the idle loop too. */ - wait_event(suspend_freeze_wait_head, - suspend_freeze_state == FREEZE_STATE_WAKE); + wait_event(s2idle_wait_head, + s2idle_state == S2IDLE_STATE_WAKE); cpuidle_pause(); put_online_cpus(); - spin_lock_irq(&suspend_freeze_lock); + spin_lock_irq(&s2idle_lock); out: - suspend_freeze_state = FREEZE_STATE_NONE; - spin_unlock_irq(&suspend_freeze_lock); + s2idle_state = S2IDLE_STATE_NONE; + spin_unlock_irq(&s2idle_lock); trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, false); } @@ -118,12 +118,12 @@ static void s2idle_loop(void) /* * Suspend-to-idle equals * frozen processes + suspended devices + idle processors. - * Thus freeze_enter() should be called right after + * Thus s2idle_enter() should be called right after * all devices have been suspended. */ error = dpm_noirq_suspend_devices(PMSG_SUSPEND); if (!error) - freeze_enter(); + s2idle_enter(); dpm_noirq_resume_devices(PMSG_RESUME); if (error && (error != -EBUSY || !pm_wakeup_pending())) { @@ -148,18 +148,18 @@ static void s2idle_loop(void) pm_pr_dbg("resume from suspend-to-idle\n"); } -void freeze_wake(void) +void s2idle_wake(void) { unsigned long flags; - spin_lock_irqsave(&suspend_freeze_lock, flags); - if (suspend_freeze_state > FREEZE_STATE_NONE) { - suspend_freeze_state = FREEZE_STATE_WAKE; - wake_up(&suspend_freeze_wait_head); + spin_lock_irqsave(&s2idle_lock, flags); + if (s2idle_state > S2IDLE_STATE_NONE) { + s2idle_state = S2IDLE_STATE_WAKE; + wake_up(&s2idle_wait_head); } - spin_unlock_irqrestore(&suspend_freeze_lock, flags); + spin_unlock_irqrestore(&s2idle_lock, flags); } -EXPORT_SYMBOL_GPL(freeze_wake); +EXPORT_SYMBOL_GPL(s2idle_wake); static bool valid_state(suspend_state_t state) { @@ -552,7 +552,7 @@ static int enter_state(suspend_state_t state) return -EBUSY; if (state == PM_SUSPEND_TO_IDLE) - freeze_begin(); + s2idle_begin(); #ifndef CONFIG_SUSPEND_SKIP_SYNC trace_suspend_resume(TPS("sync_filesystems"), 0, true); diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 6c23e30c0e5c..2ea4b7b23044 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -158,7 +158,7 @@ static void cpuidle_idle_call(void) } /* - * Suspend-to-idle ("freeze") is a system state in which all user space + * Suspend-to-idle ("s2idle") is a system state in which all user space * has been frozen, all I/O devices have been suspended and the only * activity happens here and in iterrupts (if any). In that case bypass * the cpuidle governor and go stratight for the deepest idle state @@ -167,8 +167,8 @@ static void cpuidle_idle_call(void) * until a proper wakeup interrupt happens. */ - if (idle_should_freeze() || dev->use_deepest_state) { - if (idle_should_freeze()) { + if (idle_should_enter_s2idle() || dev->use_deepest_state) { + if (idle_should_enter_s2idle()) { entered_state = cpuidle_enter_freeze(drv, dev); if (entered_state > 0) { local_irq_enable(); From 28ba086ed30fb3fb714598aa029b894c3754fa7b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:14:45 +0200 Subject: [PATCH 16/18] PM / s2idle: Rename ->enter_freeze to ->enter_s2idle Rename the ->enter_freeze cpuidle driver callback to ->enter_s2idle to make it clear that it is used for entering suspend-to-idle and rename the related functions, variables and so on accordingly. Signed-off-by: Rafael J. Wysocki --- arch/arm/mach-tegra/cpuidle-tegra114.c | 4 +- drivers/acpi/processor_idle.c | 6 +- drivers/cpuidle/cpuidle.c | 18 +-- drivers/cpuidle/dt_idle_states.c | 4 +- drivers/idle/intel_idle.c | 180 ++++++++++++------------- include/linux/cpuidle.h | 8 +- kernel/sched/idle.c | 2 +- 7 files changed, 111 insertions(+), 111 deletions(-) diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index d3aa9be16621..e3fbcfedf845 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -60,7 +60,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, return index; } -static void tegra114_idle_enter_freeze(struct cpuidle_device *dev, +static void tegra114_idle_enter_s2idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { @@ -77,7 +77,7 @@ static struct cpuidle_driver tegra_idle_driver = { #ifdef CONFIG_PM_SLEEP [1] = { .enter = tegra114_idle_power_down, - .enter_freeze = tegra114_idle_enter_freeze, + .enter_s2idle = tegra114_idle_enter_s2idle, .exit_latency = 500, .target_residency = 1000, .flags = CPUIDLE_FLAG_TIMER_STOP, diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 5c8aa9cf62d7..a9eb9d654b7a 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -789,7 +789,7 @@ static int acpi_idle_enter(struct cpuidle_device *dev, return index; } -static void acpi_idle_enter_freeze(struct cpuidle_device *dev, +static void acpi_idle_enter_s2idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); @@ -867,14 +867,14 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) drv->safe_state_index = count; } /* - * Halt-induced C1 is not good for ->enter_freeze, because it + * Halt-induced C1 is not good for ->enter_s2idle, because it * re-enables interrupts on exit. Moreover, C1 is generally not * particularly interesting from the suspend-to-idle angle, so * avoid C1 and the situations in which we may need to fall back * to it altogether. */ if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr)) - state->enter_freeze = acpi_idle_enter_freeze; + state->enter_s2idle = acpi_idle_enter_s2idle; count++; if (count == CPUIDLE_STATE_MAX) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 60bb64f4329d..484cc8909d5c 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -77,7 +77,7 @@ static int find_deepest_state(struct cpuidle_driver *drv, struct cpuidle_device *dev, unsigned int max_latency, unsigned int forbidden_flags, - bool freeze) + bool s2idle) { unsigned int latency_req = 0; int i, ret = 0; @@ -89,7 +89,7 @@ static int find_deepest_state(struct cpuidle_driver *drv, if (s->disabled || su->disable || s->exit_latency <= latency_req || s->exit_latency > max_latency || (s->flags & forbidden_flags) - || (freeze && !s->enter_freeze)) + || (s2idle && !s->enter_s2idle)) continue; latency_req = s->exit_latency; @@ -128,7 +128,7 @@ int cpuidle_find_deepest_state(struct cpuidle_driver *drv, } #ifdef CONFIG_SUSPEND -static void enter_freeze_proper(struct cpuidle_driver *drv, +static void enter_s2idle_proper(struct cpuidle_driver *drv, struct cpuidle_device *dev, int index) { /* @@ -143,7 +143,7 @@ static void enter_freeze_proper(struct cpuidle_driver *drv, * suspended is generally unsafe. */ stop_critical_timings(); - drv->states[index].enter_freeze(dev, drv, index); + drv->states[index].enter_s2idle(dev, drv, index); WARN_ON(!irqs_disabled()); /* * timekeeping_resume() that will be called by tick_unfreeze() for the @@ -155,25 +155,25 @@ static void enter_freeze_proper(struct cpuidle_driver *drv, } /** - * cpuidle_enter_freeze - Enter an idle state suitable for suspend-to-idle. + * cpuidle_enter_s2idle - Enter an idle state suitable for suspend-to-idle. * @drv: cpuidle driver for the given CPU. * @dev: cpuidle device for the given CPU. * - * If there are states with the ->enter_freeze callback, find the deepest of + * If there are states with the ->enter_s2idle callback, find the deepest of * them and enter it with frozen tick. */ -int cpuidle_enter_freeze(struct cpuidle_driver *drv, struct cpuidle_device *dev) +int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev) { int index; /* - * Find the deepest state with ->enter_freeze present, which guarantees + * Find the deepest state with ->enter_s2idle present, which guarantees * that interrupts won't be enabled when it exits and allows the tick to * be frozen safely. */ index = find_deepest_state(drv, dev, UINT_MAX, 0, true); if (index > 0) - enter_freeze_proper(drv, dev, index); + enter_s2idle_proper(drv, dev, index); return index; } diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index ae8eb0359889..5ba9fab64e7d 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -41,9 +41,9 @@ static int init_state_node(struct cpuidle_state *idle_state, /* * Since this is not a "coupled" state, it's safe to assume interrupts * won't be enabled when it exits allowing the tick to be frozen - * safely. So enter() can be also enter_freeze() callback. + * safely. So enter() can be also enter_s2idle() callback. */ - idle_state->enter_freeze = match_id->data; + idle_state->enter_s2idle = match_id->data; err = of_property_read_u32(state_node, "wakeup-latency-us", &idle_state->exit_latency); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index c2ae819a871c..474cc4330613 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -97,7 +97,7 @@ static const struct idle_cpu *icpu; static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; static int intel_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); -static void intel_idle_freeze(struct cpuidle_device *dev, +static void intel_idle_s2idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); static struct cpuidle_state *cpuidle_state_table; @@ -132,7 +132,7 @@ static struct cpuidle_state nehalem_cstates[] = { .exit_latency = 3, .target_residency = 6, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -140,7 +140,7 @@ static struct cpuidle_state nehalem_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -148,7 +148,7 @@ static struct cpuidle_state nehalem_cstates[] = { .exit_latency = 20, .target_residency = 80, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -156,7 +156,7 @@ static struct cpuidle_state nehalem_cstates[] = { .exit_latency = 200, .target_residency = 800, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -169,7 +169,7 @@ static struct cpuidle_state snb_cstates[] = { .exit_latency = 2, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -177,7 +177,7 @@ static struct cpuidle_state snb_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -185,7 +185,7 @@ static struct cpuidle_state snb_cstates[] = { .exit_latency = 80, .target_residency = 211, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -193,7 +193,7 @@ static struct cpuidle_state snb_cstates[] = { .exit_latency = 104, .target_residency = 345, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", .desc = "MWAIT 0x30", @@ -201,7 +201,7 @@ static struct cpuidle_state snb_cstates[] = { .exit_latency = 109, .target_residency = 345, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -214,7 +214,7 @@ static struct cpuidle_state byt_cstates[] = { .exit_latency = 1, .target_residency = 1, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6N", .desc = "MWAIT 0x58", @@ -222,7 +222,7 @@ static struct cpuidle_state byt_cstates[] = { .exit_latency = 300, .target_residency = 275, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6S", .desc = "MWAIT 0x52", @@ -230,7 +230,7 @@ static struct cpuidle_state byt_cstates[] = { .exit_latency = 500, .target_residency = 560, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", .desc = "MWAIT 0x60", @@ -238,7 +238,7 @@ static struct cpuidle_state byt_cstates[] = { .exit_latency = 1200, .target_residency = 4000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7S", .desc = "MWAIT 0x64", @@ -246,7 +246,7 @@ static struct cpuidle_state byt_cstates[] = { .exit_latency = 10000, .target_residency = 20000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -259,7 +259,7 @@ static struct cpuidle_state cht_cstates[] = { .exit_latency = 1, .target_residency = 1, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6N", .desc = "MWAIT 0x58", @@ -267,7 +267,7 @@ static struct cpuidle_state cht_cstates[] = { .exit_latency = 80, .target_residency = 275, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6S", .desc = "MWAIT 0x52", @@ -275,7 +275,7 @@ static struct cpuidle_state cht_cstates[] = { .exit_latency = 200, .target_residency = 560, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", .desc = "MWAIT 0x60", @@ -283,7 +283,7 @@ static struct cpuidle_state cht_cstates[] = { .exit_latency = 1200, .target_residency = 4000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7S", .desc = "MWAIT 0x64", @@ -291,7 +291,7 @@ static struct cpuidle_state cht_cstates[] = { .exit_latency = 10000, .target_residency = 20000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -304,7 +304,7 @@ static struct cpuidle_state ivb_cstates[] = { .exit_latency = 1, .target_residency = 1, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -312,7 +312,7 @@ static struct cpuidle_state ivb_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -320,7 +320,7 @@ static struct cpuidle_state ivb_cstates[] = { .exit_latency = 59, .target_residency = 156, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -328,7 +328,7 @@ static struct cpuidle_state ivb_cstates[] = { .exit_latency = 80, .target_residency = 300, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", .desc = "MWAIT 0x30", @@ -336,7 +336,7 @@ static struct cpuidle_state ivb_cstates[] = { .exit_latency = 87, .target_residency = 300, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -349,7 +349,7 @@ static struct cpuidle_state ivt_cstates[] = { .exit_latency = 1, .target_residency = 1, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -357,7 +357,7 @@ static struct cpuidle_state ivt_cstates[] = { .exit_latency = 10, .target_residency = 80, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -365,7 +365,7 @@ static struct cpuidle_state ivt_cstates[] = { .exit_latency = 59, .target_residency = 156, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -373,7 +373,7 @@ static struct cpuidle_state ivt_cstates[] = { .exit_latency = 82, .target_residency = 300, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -386,7 +386,7 @@ static struct cpuidle_state ivt_cstates_4s[] = { .exit_latency = 1, .target_residency = 1, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -394,7 +394,7 @@ static struct cpuidle_state ivt_cstates_4s[] = { .exit_latency = 10, .target_residency = 250, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -402,7 +402,7 @@ static struct cpuidle_state ivt_cstates_4s[] = { .exit_latency = 59, .target_residency = 300, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -410,7 +410,7 @@ static struct cpuidle_state ivt_cstates_4s[] = { .exit_latency = 84, .target_residency = 400, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -423,7 +423,7 @@ static struct cpuidle_state ivt_cstates_8s[] = { .exit_latency = 1, .target_residency = 1, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -431,7 +431,7 @@ static struct cpuidle_state ivt_cstates_8s[] = { .exit_latency = 10, .target_residency = 500, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -439,7 +439,7 @@ static struct cpuidle_state ivt_cstates_8s[] = { .exit_latency = 59, .target_residency = 600, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -447,7 +447,7 @@ static struct cpuidle_state ivt_cstates_8s[] = { .exit_latency = 88, .target_residency = 700, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -460,7 +460,7 @@ static struct cpuidle_state hsw_cstates[] = { .exit_latency = 2, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -468,7 +468,7 @@ static struct cpuidle_state hsw_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -476,7 +476,7 @@ static struct cpuidle_state hsw_cstates[] = { .exit_latency = 33, .target_residency = 100, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -484,7 +484,7 @@ static struct cpuidle_state hsw_cstates[] = { .exit_latency = 133, .target_residency = 400, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7s", .desc = "MWAIT 0x32", @@ -492,7 +492,7 @@ static struct cpuidle_state hsw_cstates[] = { .exit_latency = 166, .target_residency = 500, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", .desc = "MWAIT 0x40", @@ -500,7 +500,7 @@ static struct cpuidle_state hsw_cstates[] = { .exit_latency = 300, .target_residency = 900, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", .desc = "MWAIT 0x50", @@ -508,7 +508,7 @@ static struct cpuidle_state hsw_cstates[] = { .exit_latency = 600, .target_residency = 1800, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", .desc = "MWAIT 0x60", @@ -516,7 +516,7 @@ static struct cpuidle_state hsw_cstates[] = { .exit_latency = 2600, .target_residency = 7700, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -528,7 +528,7 @@ static struct cpuidle_state bdw_cstates[] = { .exit_latency = 2, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -536,7 +536,7 @@ static struct cpuidle_state bdw_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -544,7 +544,7 @@ static struct cpuidle_state bdw_cstates[] = { .exit_latency = 40, .target_residency = 100, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -552,7 +552,7 @@ static struct cpuidle_state bdw_cstates[] = { .exit_latency = 133, .target_residency = 400, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7s", .desc = "MWAIT 0x32", @@ -560,7 +560,7 @@ static struct cpuidle_state bdw_cstates[] = { .exit_latency = 166, .target_residency = 500, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", .desc = "MWAIT 0x40", @@ -568,7 +568,7 @@ static struct cpuidle_state bdw_cstates[] = { .exit_latency = 300, .target_residency = 900, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", .desc = "MWAIT 0x50", @@ -576,7 +576,7 @@ static struct cpuidle_state bdw_cstates[] = { .exit_latency = 600, .target_residency = 1800, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", .desc = "MWAIT 0x60", @@ -584,7 +584,7 @@ static struct cpuidle_state bdw_cstates[] = { .exit_latency = 2600, .target_residency = 7700, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -597,7 +597,7 @@ static struct cpuidle_state skl_cstates[] = { .exit_latency = 2, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -605,7 +605,7 @@ static struct cpuidle_state skl_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C3", .desc = "MWAIT 0x10", @@ -613,7 +613,7 @@ static struct cpuidle_state skl_cstates[] = { .exit_latency = 70, .target_residency = 100, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -621,7 +621,7 @@ static struct cpuidle_state skl_cstates[] = { .exit_latency = 85, .target_residency = 200, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7s", .desc = "MWAIT 0x33", @@ -629,7 +629,7 @@ static struct cpuidle_state skl_cstates[] = { .exit_latency = 124, .target_residency = 800, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", .desc = "MWAIT 0x40", @@ -637,7 +637,7 @@ static struct cpuidle_state skl_cstates[] = { .exit_latency = 200, .target_residency = 800, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", .desc = "MWAIT 0x50", @@ -645,7 +645,7 @@ static struct cpuidle_state skl_cstates[] = { .exit_latency = 480, .target_residency = 5000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", .desc = "MWAIT 0x60", @@ -653,7 +653,7 @@ static struct cpuidle_state skl_cstates[] = { .exit_latency = 890, .target_residency = 5000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -666,7 +666,7 @@ static struct cpuidle_state skx_cstates[] = { .exit_latency = 2, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -674,7 +674,7 @@ static struct cpuidle_state skx_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -682,7 +682,7 @@ static struct cpuidle_state skx_cstates[] = { .exit_latency = 133, .target_residency = 600, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -695,7 +695,7 @@ static struct cpuidle_state atom_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C2", .desc = "MWAIT 0x10", @@ -703,7 +703,7 @@ static struct cpuidle_state atom_cstates[] = { .exit_latency = 20, .target_residency = 80, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C4", .desc = "MWAIT 0x30", @@ -711,7 +711,7 @@ static struct cpuidle_state atom_cstates[] = { .exit_latency = 100, .target_residency = 400, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x52", @@ -719,7 +719,7 @@ static struct cpuidle_state atom_cstates[] = { .exit_latency = 140, .target_residency = 560, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -731,7 +731,7 @@ static struct cpuidle_state tangier_cstates[] = { .exit_latency = 1, .target_residency = 4, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C4", .desc = "MWAIT 0x30", @@ -739,7 +739,7 @@ static struct cpuidle_state tangier_cstates[] = { .exit_latency = 100, .target_residency = 400, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x52", @@ -747,7 +747,7 @@ static struct cpuidle_state tangier_cstates[] = { .exit_latency = 140, .target_residency = 560, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7", .desc = "MWAIT 0x60", @@ -755,7 +755,7 @@ static struct cpuidle_state tangier_cstates[] = { .exit_latency = 1200, .target_residency = 4000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", .desc = "MWAIT 0x64", @@ -763,7 +763,7 @@ static struct cpuidle_state tangier_cstates[] = { .exit_latency = 10000, .target_residency = 20000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -775,7 +775,7 @@ static struct cpuidle_state avn_cstates[] = { .exit_latency = 2, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x51", @@ -783,7 +783,7 @@ static struct cpuidle_state avn_cstates[] = { .exit_latency = 15, .target_residency = 45, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -795,7 +795,7 @@ static struct cpuidle_state knl_cstates[] = { .exit_latency = 1, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze }, + .enter_s2idle = intel_idle_s2idle }, { .name = "C6", .desc = "MWAIT 0x10", @@ -803,7 +803,7 @@ static struct cpuidle_state knl_cstates[] = { .exit_latency = 120, .target_residency = 500, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze }, + .enter_s2idle = intel_idle_s2idle }, { .enter = NULL } }; @@ -816,7 +816,7 @@ static struct cpuidle_state bxt_cstates[] = { .exit_latency = 2, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -824,7 +824,7 @@ static struct cpuidle_state bxt_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -832,7 +832,7 @@ static struct cpuidle_state bxt_cstates[] = { .exit_latency = 133, .target_residency = 133, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C7s", .desc = "MWAIT 0x31", @@ -840,7 +840,7 @@ static struct cpuidle_state bxt_cstates[] = { .exit_latency = 155, .target_residency = 155, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C8", .desc = "MWAIT 0x40", @@ -848,7 +848,7 @@ static struct cpuidle_state bxt_cstates[] = { .exit_latency = 1000, .target_residency = 1000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C9", .desc = "MWAIT 0x50", @@ -856,7 +856,7 @@ static struct cpuidle_state bxt_cstates[] = { .exit_latency = 2000, .target_residency = 2000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C10", .desc = "MWAIT 0x60", @@ -864,7 +864,7 @@ static struct cpuidle_state bxt_cstates[] = { .exit_latency = 10000, .target_residency = 10000, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -877,7 +877,7 @@ static struct cpuidle_state dnv_cstates[] = { .exit_latency = 2, .target_residency = 2, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C1E", .desc = "MWAIT 0x01", @@ -885,7 +885,7 @@ static struct cpuidle_state dnv_cstates[] = { .exit_latency = 10, .target_residency = 20, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .name = "C6", .desc = "MWAIT 0x20", @@ -893,7 +893,7 @@ static struct cpuidle_state dnv_cstates[] = { .exit_latency = 50, .target_residency = 500, .enter = &intel_idle, - .enter_freeze = intel_idle_freeze, }, + .enter_s2idle = intel_idle_s2idle, }, { .enter = NULL } }; @@ -936,12 +936,12 @@ static __cpuidle int intel_idle(struct cpuidle_device *dev, } /** - * intel_idle_freeze - simplified "enter" callback routine for suspend-to-idle + * intel_idle_s2idle - simplified "enter" callback routine for suspend-to-idle * @dev: cpuidle_device * @drv: cpuidle driver * @index: state index */ -static void intel_idle_freeze(struct cpuidle_device *dev, +static void intel_idle_s2idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { unsigned long ecx = 1; /* break on interrupt flag */ @@ -1337,7 +1337,7 @@ static void __init intel_idle_cpuidle_driver_init(void) int num_substates, mwait_hint, mwait_cstate; if ((cpuidle_state_table[cstate].enter == NULL) && - (cpuidle_state_table[cstate].enter_freeze == NULL)) + (cpuidle_state_table[cstate].enter_s2idle == NULL)) break; if (cstate + 1 > max_cstate) { diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index fc1e5d7fc1c7..f0e2e9223e66 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -52,11 +52,11 @@ struct cpuidle_state { int (*enter_dead) (struct cpuidle_device *dev, int index); /* - * CPUs execute ->enter_freeze with the local tick or entire timekeeping + * CPUs execute ->enter_s2idle with the local tick or entire timekeeping * suspended, so it must not re-enable interrupts at any point (even * temporarily) or attempt to change states of clock event devices. */ - void (*enter_freeze) (struct cpuidle_device *dev, + void (*enter_s2idle) (struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); }; @@ -197,14 +197,14 @@ static inline struct cpuidle_device *cpuidle_get_device(void) {return NULL; } #ifdef CONFIG_CPU_IDLE extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv, struct cpuidle_device *dev); -extern int cpuidle_enter_freeze(struct cpuidle_driver *drv, +extern int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev); extern void cpuidle_use_deepest_state(bool enable); #else static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv, struct cpuidle_device *dev) {return -ENODEV; } -static inline int cpuidle_enter_freeze(struct cpuidle_driver *drv, +static inline int cpuidle_enter_s2idle(struct cpuidle_driver *drv, struct cpuidle_device *dev) {return -ENODEV; } static inline void cpuidle_use_deepest_state(bool enable) diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 2ea4b7b23044..257f4f0b4532 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -169,7 +169,7 @@ static void cpuidle_idle_call(void) if (idle_should_enter_s2idle() || dev->use_deepest_state) { if (idle_should_enter_s2idle()) { - entered_state = cpuidle_enter_freeze(drv, dev); + entered_state = cpuidle_enter_s2idle(drv, dev); if (entered_state > 0) { local_irq_enable(); goto exit_idle; From 23d5855f4774f4f7c246a67057ecacc904696d8a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2017 00:15:30 +0200 Subject: [PATCH 17/18] PM / s2idle: Rename platform operations structure Rename struct platform_freeze_ops to platform_s2idle_ops to make it clear that the callbacks in it are used during suspend-to-idle suspend/resume transitions and rename the related functions, variables and so on accordingly. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 28 ++++++++++++++-------------- include/linux/suspend.h | 6 +++--- kernel/power/suspend.c | 30 +++++++++++++++--------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index a0a6fd10fb5f..f7a8abbeac6e 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -737,14 +737,14 @@ static struct acpi_scan_handler lps0_handler = { .attach = lps0_device_attach, }; -static int acpi_freeze_begin(void) +static int acpi_s2idle_begin(void) { acpi_scan_lock_acquire(); s2idle_in_progress = true; return 0; } -static int acpi_freeze_prepare(void) +static int acpi_s2idle_prepare(void) { if (lps0_device_handle) { acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); @@ -764,7 +764,7 @@ static int acpi_freeze_prepare(void) return 0; } -static void acpi_freeze_wake(void) +static void acpi_s2idle_wake(void) { /* * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means @@ -778,7 +778,7 @@ static void acpi_freeze_wake(void) } } -static void acpi_freeze_sync(void) +static void acpi_s2idle_sync(void) { /* * Process all pending events in case there are any wakeup ones. @@ -791,7 +791,7 @@ static void acpi_freeze_sync(void) s2idle_wakeup = false; } -static void acpi_freeze_restore(void) +static void acpi_s2idle_restore(void) { if (acpi_sci_irq_valid()) disable_irq_wake(acpi_sci_irq); @@ -804,19 +804,19 @@ static void acpi_freeze_restore(void) } } -static void acpi_freeze_end(void) +static void acpi_s2idle_end(void) { s2idle_in_progress = false; acpi_scan_lock_release(); } -static const struct platform_freeze_ops acpi_freeze_ops = { - .begin = acpi_freeze_begin, - .prepare = acpi_freeze_prepare, - .wake = acpi_freeze_wake, - .sync = acpi_freeze_sync, - .restore = acpi_freeze_restore, - .end = acpi_freeze_end, +static const struct platform_s2idle_ops acpi_s2idle_ops = { + .begin = acpi_s2idle_begin, + .prepare = acpi_s2idle_prepare, + .wake = acpi_s2idle_wake, + .sync = acpi_s2idle_sync, + .restore = acpi_s2idle_restore, + .end = acpi_s2idle_end, }; static void acpi_sleep_suspend_setup(void) @@ -831,7 +831,7 @@ static void acpi_sleep_suspend_setup(void) &acpi_suspend_ops_old : &acpi_suspend_ops); acpi_scan_add_handler(&lps0_handler); - freeze_set_ops(&acpi_freeze_ops); + s2idle_set_ops(&acpi_s2idle_ops); } #else /* !CONFIG_SUSPEND */ diff --git a/include/linux/suspend.h b/include/linux/suspend.h index feb43dfbf7bc..0d41daf7e89d 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -186,7 +186,7 @@ struct platform_suspend_ops { void (*recover)(void); }; -struct platform_freeze_ops { +struct platform_s2idle_ops { int (*begin)(void); int (*prepare)(void); void (*wake)(void); @@ -251,7 +251,7 @@ static inline bool idle_should_enter_s2idle(void) } extern void __init pm_states_init(void); -extern void freeze_set_ops(const struct platform_freeze_ops *ops); +extern void s2idle_set_ops(const struct platform_s2idle_ops *ops); extern void s2idle_wake(void); /** @@ -286,7 +286,7 @@ static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } static inline bool idle_should_enter_s2idle(void) { return false; } static inline void __init pm_states_init(void) {} -static inline void freeze_set_ops(const struct platform_freeze_ops *ops) {} +static inline void s2idle_set_ops(const struct platform_s2idle_ops *ops) {} static inline void s2idle_wake(void) {} #endif /* !CONFIG_SUSPEND */ diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index ae9b579c2533..3e2b4f519009 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -56,16 +56,16 @@ unsigned int pm_suspend_global_flags; EXPORT_SYMBOL_GPL(pm_suspend_global_flags); static const struct platform_suspend_ops *suspend_ops; -static const struct platform_freeze_ops *freeze_ops; +static const struct platform_s2idle_ops *s2idle_ops; static DECLARE_WAIT_QUEUE_HEAD(s2idle_wait_head); enum s2idle_states __read_mostly s2idle_state; static DEFINE_SPINLOCK(s2idle_lock); -void freeze_set_ops(const struct platform_freeze_ops *ops) +void s2idle_set_ops(const struct platform_s2idle_ops *ops) { lock_system_sleep(); - freeze_ops = ops; + s2idle_ops = ops; unlock_system_sleep(); } @@ -131,13 +131,13 @@ static void s2idle_loop(void) break; } - if (freeze_ops && freeze_ops->wake) - freeze_ops->wake(); + if (s2idle_ops && s2idle_ops->wake) + s2idle_ops->wake(); dpm_noirq_end(); - if (freeze_ops && freeze_ops->sync) - freeze_ops->sync(); + if (s2idle_ops && s2idle_ops->sync) + s2idle_ops->sync(); if (pm_wakeup_pending()) break; @@ -250,8 +250,8 @@ static int platform_suspend_prepare(suspend_state_t state) static int platform_suspend_prepare_late(suspend_state_t state) { - return state == PM_SUSPEND_TO_IDLE && freeze_ops && freeze_ops->prepare ? - freeze_ops->prepare() : 0; + return state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->prepare ? + s2idle_ops->prepare() : 0; } static int platform_suspend_prepare_noirq(suspend_state_t state) @@ -268,8 +268,8 @@ static void platform_resume_noirq(suspend_state_t state) static void platform_resume_early(suspend_state_t state) { - if (state == PM_SUSPEND_TO_IDLE && freeze_ops && freeze_ops->restore) - freeze_ops->restore(); + if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->restore) + s2idle_ops->restore(); } static void platform_resume_finish(suspend_state_t state) @@ -280,8 +280,8 @@ static void platform_resume_finish(suspend_state_t state) static int platform_suspend_begin(suspend_state_t state) { - if (state == PM_SUSPEND_TO_IDLE && freeze_ops && freeze_ops->begin) - return freeze_ops->begin(); + if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->begin) + return s2idle_ops->begin(); else if (suspend_ops && suspend_ops->begin) return suspend_ops->begin(state); else @@ -290,8 +290,8 @@ static int platform_suspend_begin(suspend_state_t state) static void platform_resume_end(suspend_state_t state) { - if (state == PM_SUSPEND_TO_IDLE && freeze_ops && freeze_ops->end) - freeze_ops->end(); + if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->end) + s2idle_ops->end(); else if (suspend_ops && suspend_ops->end) suspend_ops->end(); } From 726fb6b4f2a82a14a906f39bdabac4863b87c01a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 15 Aug 2017 18:16:59 -0700 Subject: [PATCH 18/18] ACPI / PM: Check low power idle constraints for debug only For SoC to achieve its lowest power platform idle state a set of hardware preconditions must be met. These preconditions or constraints can be obtained by issuing a device specific method (_DSM) with function "1". Refer to the document provided in the link below. Here during initialization (from attach() callback of LPS0 device), invoke function 1 to get the device constraints. Each enabled constraint is stored in a table. The devices in this table are used to check whether they were in required minimum state, while entering suspend. This check is done from platform freeze wake() callback, only when /sys/power/pm_debug_messages attribute is non zero. If any constraint is not met and device is ACPI power managed then it prints the device information to kernel logs. Also if debug is enabled in acpi/sleep.c, the constraint table and state of each device on wake is dumped in kernel logs. Since pm_debug_messages_on setting is used as condition to check constraints outside kernel/power/main.c, pm_debug_messages_on is changed to a global variable. Link: http://www.uefi.org/sites/default/files/resources/Intel_ACPI_Low_Power_S0_Idle.pdf Signed-off-by: Srinivas Pandruvada Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 168 ++++++++++++++++++++++++++++++++++++++++ include/linux/suspend.h | 2 + kernel/power/main.c | 2 +- 3 files changed, 171 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index f7a8abbeac6e..61b2e9f17c4e 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -669,6 +669,7 @@ static const struct acpi_device_id lps0_device_ids[] = { #define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" +#define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1 #define ACPI_LPS0_SCREEN_OFF 3 #define ACPI_LPS0_SCREEN_ON 4 #define ACPI_LPS0_ENTRY 5 @@ -680,6 +681,166 @@ static acpi_handle lps0_device_handle; static guid_t lps0_dsm_guid; static char lps0_dsm_func_mask; +/* Device constraint entry structure */ +struct lpi_device_info { + char *name; + int enabled; + union acpi_object *package; +}; + +/* Constraint package structure */ +struct lpi_device_constraint { + int uid; + int min_dstate; + int function_states; +}; + +struct lpi_constraints { + acpi_handle handle; + int min_dstate; +}; + +static struct lpi_constraints *lpi_constraints_table; +static int lpi_constraints_table_size; + +static void lpi_device_get_constraints(void) +{ + union acpi_object *out_obj; + int i; + + out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid, + 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS, + NULL, ACPI_TYPE_PACKAGE); + + acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n", + out_obj ? "successful" : "failed"); + + if (!out_obj) + return; + + lpi_constraints_table = kcalloc(out_obj->package.count, + sizeof(*lpi_constraints_table), + GFP_KERNEL); + if (!lpi_constraints_table) + goto free_acpi_buffer; + + acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n"); + + for (i = 0; i < out_obj->package.count; i++) { + struct lpi_constraints *constraint; + acpi_status status; + union acpi_object *package = &out_obj->package.elements[i]; + struct lpi_device_info info = { }; + int package_count = 0, j; + + if (!package) + continue; + + for (j = 0; j < package->package.count; ++j) { + union acpi_object *element = + &(package->package.elements[j]); + + switch (element->type) { + case ACPI_TYPE_INTEGER: + info.enabled = element->integer.value; + break; + case ACPI_TYPE_STRING: + info.name = element->string.pointer; + break; + case ACPI_TYPE_PACKAGE: + package_count = element->package.count; + info.package = element->package.elements; + break; + } + } + + if (!info.enabled || !info.package || !info.name) + continue; + + constraint = &lpi_constraints_table[lpi_constraints_table_size]; + + status = acpi_get_handle(NULL, info.name, &constraint->handle); + if (ACPI_FAILURE(status)) + continue; + + acpi_handle_debug(lps0_device_handle, + "index:%d Name:%s\n", i, info.name); + + constraint->min_dstate = -1; + + for (j = 0; j < package_count; ++j) { + union acpi_object *info_obj = &info.package[j]; + union acpi_object *cnstr_pkg; + union acpi_object *obj; + struct lpi_device_constraint dev_info; + + switch (info_obj->type) { + case ACPI_TYPE_INTEGER: + /* version */ + break; + case ACPI_TYPE_PACKAGE: + if (info_obj->package.count < 2) + break; + + cnstr_pkg = info_obj->package.elements; + obj = &cnstr_pkg[0]; + dev_info.uid = obj->integer.value; + obj = &cnstr_pkg[1]; + dev_info.min_dstate = obj->integer.value; + + acpi_handle_debug(lps0_device_handle, + "uid:%d min_dstate:%s\n", + dev_info.uid, + acpi_power_state_string(dev_info.min_dstate)); + + constraint->min_dstate = dev_info.min_dstate; + break; + } + } + + if (constraint->min_dstate < 0) { + acpi_handle_debug(lps0_device_handle, + "Incomplete constraint defined\n"); + continue; + } + + lpi_constraints_table_size++; + } + + acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n"); + +free_acpi_buffer: + ACPI_FREE(out_obj); +} + +static void lpi_check_constraints(void) +{ + int i; + + for (i = 0; i < lpi_constraints_table_size; ++i) { + struct acpi_device *adev; + + if (acpi_bus_get_device(lpi_constraints_table[i].handle, &adev)) + continue; + + acpi_handle_debug(adev->handle, + "LPI: required min power state:%s current power state:%s\n", + acpi_power_state_string(lpi_constraints_table[i].min_dstate), + acpi_power_state_string(adev->power.state)); + + if (!adev->flags.power_manageable) { + acpi_handle_info(adev->handle, "LPI: Device not power manageble\n"); + continue; + } + + if (adev->power.state < lpi_constraints_table[i].min_dstate) + acpi_handle_info(adev->handle, + "LPI: Constraint not met; min power state:%s current power state:%s\n", + acpi_power_state_string(lpi_constraints_table[i].min_dstate), + acpi_power_state_string(adev->power.state)); + } +} + static void acpi_sleep_run_lps0_dsm(unsigned int func) { union acpi_object *out_obj; @@ -729,6 +890,9 @@ static int lps0_device_attach(struct acpi_device *adev, "_DSM function 0 evaluation failed\n"); } ACPI_FREE(out_obj); + + lpi_device_get_constraints(); + return 0; } @@ -766,6 +930,10 @@ static int acpi_s2idle_prepare(void) static void acpi_s2idle_wake(void) { + + if (pm_debug_messages_on) + lpi_check_constraints(); + /* * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means * that the SCI has triggered while suspended, so cancel the wakeup in diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 0d41daf7e89d..d10b7980799d 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -495,9 +495,11 @@ static inline void unlock_system_sleep(void) {} #ifdef CONFIG_PM_SLEEP_DEBUG extern bool pm_print_times_enabled; +extern bool pm_debug_messages_on; extern __printf(2, 3) void __pm_pr_dbg(bool defer, const char *fmt, ...); #else #define pm_print_times_enabled (false) +#define pm_debug_messages_on (false) #include diff --git a/kernel/power/main.c b/kernel/power/main.c index 3074ea4cec0a..3a2ca9066583 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -361,7 +361,7 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj, power_attr_ro(pm_wakeup_irq); -static bool pm_debug_messages_on __read_mostly; +bool pm_debug_messages_on __read_mostly; static ssize_t pm_debug_messages_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)