From 57044031b0cb11325e1034394a4721484f9dc9fe Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 15 Nov 2017 02:16:55 +0100 Subject: ACPI / PM: Make it possible to ignore the system sleep blacklist The ACPI code supporting system transitions to sleep states uses an internal blacklist to apply special handling to some machines reported to behave incorrectly in some ways. However, some entries of that blacklist cover problematic as well as non-problematic systems, so give the users of the latter a chance to ignore the blacklist and run their systems in the default way by adding acpi_sleep=nobl to the kernel command line. For example, that allows the users of Dell XPS13 9360 systems not affected by the issue that caused the blacklist entry for this machine to be added by commit 71630b7a832f (ACPI / PM: Blacklist Low Power S0 Idle _DSM for Dell XPS13 9360) to use suspend-to-idle with the Low Power S0 Idle _DSM interface which in principle should be more energy-efficient than S3 on them. Signed-off-by: Rafael J. Wysocki --- Documentation/admin-guide/kernel-parameters.txt | 5 ++++- arch/x86/kernel/acpi/sleep.c | 2 ++ drivers/acpi/sleep.c | 10 ++++++++++ include/linux/acpi.h | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 6571fbfdb2a1..b125690d5dbc 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -223,7 +223,7 @@ acpi_sleep= [HW,ACPI] Sleep options Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, - old_ordering, nonvs, sci_force_enable } + old_ordering, nonvs, sci_force_enable, nobl } See Documentation/power/video.txt for information on s3_bios and s3_mode. s3_beep is for debugging; it makes the PC's speaker beep @@ -239,6 +239,9 @@ sci_force_enable causes the kernel to set SCI_EN directly on resume from S1/S3 (which is against the ACPI spec, but some broken systems don't work without it). + nobl causes the internal blacklist of systems known to + behave incorrectly in some ways with respect to system + suspend and resume to be ignored (use wisely). acpi_use_timer_override [HW,ACPI] Use timer override. For some broken Nvidia NF5 boards diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 7188aea91549..f1915b744052 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -138,6 +138,8 @@ static int __init acpi_sleep_setup(char *str) acpi_nvs_nosave_s3(); if (strncmp(str, "old_ordering", 12) == 0) acpi_old_suspend_ordering(); + if (strncmp(str, "nobl", 4) == 0) + acpi_sleep_no_blacklist(); str = strchr(str, ','); if (str != NULL) str += strspn(str, ", \t"); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8082871b409a..15cd862a87c2 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -367,10 +367,20 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { {}, }; +static bool ignore_blacklist; + +void __init acpi_sleep_no_blacklist(void) +{ + ignore_blacklist = true; +} + static void __init acpi_sleep_dmi_check(void) { int year; + if (ignore_blacklist) + return; + if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year >= 2012) acpi_nvs_nosave_s3(); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dc1ebfeeb5ec..699655a9618b 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -451,6 +451,7 @@ void __init acpi_no_s4_hw_signature(void); void __init acpi_old_suspend_ordering(void); void __init acpi_nvs_nosave(void); void __init acpi_nvs_nosave_s3(void); +void __init acpi_sleep_no_blacklist(void); #endif /* CONFIG_PM_SLEEP */ struct acpi_osc_context { -- cgit v1.2.3 From bdbc98abb3aa323f6323b11db39c740e6f8fc5b1 Mon Sep 17 00:00:00 2001 From: Rainer Fiebig Date: Fri, 22 Dec 2017 11:13:59 +0100 Subject: PM: hibernate: Do not subtract NR_FILE_MAPPED in minimum_image_size() s2disk/s2both may fail unnecessarily and erratically if NR_FILE_MAPPED is high - for instance when using VMs with VirtualBox and perhaps VMware Player. In those situations s2disk becomes unreliable and therefore unusable. A typical scenario is: user issues a s2disk and it fails. User issues a second s2disk immediately after that and it succeeds. And user wonders why. The problem is caused by minimum_image_size() in snapshot.c. The value it returns is roughly 100% too high because NR_FILE_MAPPED is subtracted in its calculation. Eventually the number of preallocated image pages is falsely too low. This doesn't matter as long as NR_FILE_MAPPED-values are in a normal range or in 32bit-environments as the code allows for allocation of additional pages from highmem. But with the high values generated by VirtualBox-VMs (a 2-GB-VM causes NR_FILE_MAPPED go up by 2 GB) it may lead to failure in 64bit-systems. Not subtracting NR_FILE_MAPPED in minimum_image_size() solves the problem. I've done at least hundreds of successful s2both/s2disk now on an x86_64 system (with and without VirtualBox) which gives me some confidence that this is right. It has turned s2disk/s2both from unusable into 100% reliable. Link: https://bugzilla.kernel.org/show_bug.cgi?id=97201 Signed-off-by: Rainer Fiebig Signed-off-by: Rafael J. Wysocki --- kernel/power/snapshot.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index bce0464524d8..3d37c279c090 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1645,8 +1645,7 @@ static unsigned long free_unnecessary_pages(void) * [number of saveable pages] - [number of pages that can be freed in theory] * * where the second term is the sum of (1) reclaimable slab pages, (2) active - * and (3) inactive anonymous pages, (4) active and (5) inactive file pages, - * minus mapped file pages. + * and (3) inactive anonymous pages, (4) active and (5) inactive file pages. */ static unsigned long minimum_image_size(unsigned long saveable) { @@ -1656,8 +1655,7 @@ static unsigned long minimum_image_size(unsigned long saveable) + global_node_page_state(NR_ACTIVE_ANON) + global_node_page_state(NR_INACTIVE_ANON) + global_node_page_state(NR_ACTIVE_FILE) - + global_node_page_state(NR_INACTIVE_FILE) - - global_node_page_state(NR_FILE_MAPPED); + + global_node_page_state(NR_INACTIVE_FILE); return saveable <= size ? 0 : saveable - size; } -- cgit v1.2.3 From 4bf236a3330e97d275e5848420f7e31948fef07a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 5 Jan 2018 09:19:08 -0800 Subject: PM / sleep: Make lock/unlock_system_sleep() available to kernel modules Since pm_mutex is not exported using lock/unlock_system_sleep() from inside a kernel module causes a "pm_mutex undefined" linker error. Hence move lock/unlock_system_sleep() into kernel/power/main.c and export these. Signed-off-by: Bart Van Assche Signed-off-by: Rafael J. Wysocki --- include/linux/suspend.h | 28 ++-------------------------- kernel/power/main.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index d60b0f5c38d5..cc22a24516d6 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -443,32 +443,8 @@ extern bool pm_save_wakeup_count(unsigned int count); extern void pm_wakep_autosleep_enabled(bool set); extern void pm_print_active_wakeup_sources(void); -static inline void lock_system_sleep(void) -{ - current->flags |= PF_FREEZER_SKIP; - mutex_lock(&pm_mutex); -} - -static inline void unlock_system_sleep(void) -{ - /* - * Don't use freezer_count() because we don't want the call to - * try_to_freeze() here. - * - * Reason: - * Fundamentally, we just don't need it, because freezing condition - * doesn't come into effect until we release the pm_mutex lock, - * since the freezer always works with pm_mutex held. - * - * More importantly, in the case of hibernation, - * unlock_system_sleep() gets called in snapshot_read() and - * snapshot_write() when the freezing condition is still in effect. - * Which means, if we use try_to_freeze() here, it would make them - * enter the refrigerator, thus causing hibernation to lockup. - */ - current->flags &= ~PF_FREEZER_SKIP; - mutex_unlock(&pm_mutex); -} +extern void lock_system_sleep(void); +extern void unlock_system_sleep(void); #else /* !CONFIG_PM_SLEEP */ diff --git a/kernel/power/main.c b/kernel/power/main.c index 3a2ca9066583..705c2366dafe 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -22,6 +22,35 @@ DEFINE_MUTEX(pm_mutex); #ifdef CONFIG_PM_SLEEP +void lock_system_sleep(void) +{ + current->flags |= PF_FREEZER_SKIP; + mutex_lock(&pm_mutex); +} +EXPORT_SYMBOL_GPL(lock_system_sleep); + +void unlock_system_sleep(void) +{ + /* + * Don't use freezer_count() because we don't want the call to + * try_to_freeze() here. + * + * Reason: + * Fundamentally, we just don't need it, because freezing condition + * doesn't come into effect until we release the pm_mutex lock, + * since the freezer always works with pm_mutex held. + * + * More importantly, in the case of hibernation, + * unlock_system_sleep() gets called in snapshot_read() and + * snapshot_write() when the freezing condition is still in effect. + * Which means, if we use try_to_freeze() here, it would make them + * enter the refrigerator, thus causing hibernation to lockup. + */ + current->flags &= ~PF_FREEZER_SKIP; + mutex_unlock(&pm_mutex); +} +EXPORT_SYMBOL_GPL(unlock_system_sleep); + /* Routines for PM-transition notifications */ static BLOCKING_NOTIFIER_HEAD(pm_chain_head); -- cgit v1.2.3 From 203f8c250e2195371d418b1e8466e4caf1a0ed51 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 5 Jan 2018 09:19:09 -0800 Subject: block, scsi: Fix race between SPI domain validation and system suspend Avoid that the following warning is reported when suspending a system that is using the mptspi driver: WARNING: CPU: 0 PID: 4187 at drivers/scsi/scsi_lib.c:2960 scsi_device_quiesce+0x20/0xb0 EIP: scsi_device_quiesce+0x20/0xb0 Call Trace: spi_dv_device+0x65/0x5f0 [scsi_transport_spi] mptspi_dv_device+0x4d/0x170 [mptspi] mptspi_dv_renegotiate_work+0x49/0xc0 [mptspi] process_one_work+0x190/0x2e0 worker_thread+0x37/0x3f0 kthread+0xcb/0x100 ret_from_fork+0x19/0x24 Fixes: 3a0a529971ec (block, scsi: Make SCSI quiesce and resume work reliably) Reported-by: Woody Suwalski Signed-off-by: Bart Van Assche Acked-by: Martin K. Petersen [ rjw : Subject ] Signed-off-by: Rafael J. Wysocki --- drivers/scsi/scsi_transport_spi.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 10ebb213ddb3..871ea582029e 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "scsi_priv.h" #include @@ -1009,11 +1010,20 @@ spi_dv_device(struct scsi_device *sdev) u8 *buffer; const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; + /* + * Because this function and the power management code both call + * scsi_device_quiesce(), it is not safe to perform domain validation + * while suspend or resume is in progress. Hence the + * lock/unlock_system_sleep() calls. + */ + lock_system_sleep(); + if (unlikely(spi_dv_in_progress(starget))) - return; + goto unlock; if (unlikely(scsi_device_get(sdev))) - return; + goto unlock; + spi_dv_in_progress(starget) = 1; buffer = kzalloc(len, GFP_KERNEL); @@ -1049,6 +1059,8 @@ spi_dv_device(struct scsi_device *sdev) out_put: spi_dv_in_progress(starget) = 0; scsi_device_put(sdev); +unlock: + unlock_system_sleep(); } EXPORT_SYMBOL(spi_dv_device); -- cgit v1.2.3 From 29a5a6d7082427371519ae1e186d9e35612801fb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 11 Jan 2018 02:13:58 +0100 Subject: ACPI / PM: Use Low Power S0 Idle on more systems Some systems don't support the ACPI_LPS0_ENTRY and ACPI_LPS0_EXIT functions in their Low Power S0 Idle _DSM, but still expect EC events to be processed in the suspend-to-idle state for power button wakeup (among other things) to work. Surface Pro3 turns out to be one of them. Fortunately, it still provides Low Power S0 Idle _DSM with the screen on/off functions supported, so modify the ACPI suspend-to-idle to use the Low Power S0 Idle code path for all systems supporting the ACPI_LPS0_ENTRY and ACPI_LPS0_EXIT or the ACPI_LPS0_SCREEN_OFF and ACPI_LPS0_SCREEN_ON functions in their Low Power S0 Idle _DSM. Potentially, that will cause more systems to use suspend-to-idle by default, so some future corrections may be necessary if it leads to issues, but let it remain more straightforward for now. Link: https://bugzilla.kernel.org/show_bug.cgi?id=198389#add_comment Reported-by: Valentin Manea Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Tested-by: Valentin Manea --- drivers/acpi/sleep.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 15cd862a87c2..46cde0912762 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -707,7 +707,8 @@ static const struct acpi_device_id lps0_device_ids[] = { #define ACPI_LPS0_ENTRY 5 #define ACPI_LPS0_EXIT 6 -#define ACPI_S2IDLE_FUNC_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT)) +#define ACPI_LPS0_SCREEN_MASK ((1 << ACPI_LPS0_SCREEN_OFF) | (1 << ACPI_LPS0_SCREEN_ON)) +#define ACPI_LPS0_PLATFORM_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT)) static acpi_handle lps0_device_handle; static guid_t lps0_dsm_guid; @@ -910,7 +911,8 @@ static int lps0_device_attach(struct acpi_device *adev, if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { char bitmask = *(char *)out_obj->buffer.pointer; - if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { + if ((bitmask & ACPI_LPS0_PLATFORM_MASK) == ACPI_LPS0_PLATFORM_MASK || + (bitmask & ACPI_LPS0_SCREEN_MASK) == ACPI_LPS0_SCREEN_MASK) { lps0_dsm_func_mask = bitmask; lps0_device_handle = adev->handle; /* -- cgit v1.2.3 From 19351f340765ebef48d07eade8ffb5f6f1118244 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 10 Jan 2018 13:26:35 +0100 Subject: platform/x86: surfacepro3: Support for wakeup from suspend-to-idle Modify surface_button_notify() to make it wake up the system from suspend-to-idle (by reporting "hard" wakeup events while suspended) and add wakeup initialization to surface_button_add() for wakeup events reported by this driver to work at all. Link: https://bugzilla.kernel.org/show_bug.cgi?id=198389 Reported-by: Valentin Manea Signed-off-by: Rafael J. Wysocki Acked-by: Andy Shevchenko Tested-by: Valentin Manea --- drivers/platform/x86/surfacepro3_button.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c index 6505c97705e1..1b491690ce07 100644 --- a/drivers/platform/x86/surfacepro3_button.c +++ b/drivers/platform/x86/surfacepro3_button.c @@ -119,7 +119,7 @@ static void surface_button_notify(struct acpi_device *device, u32 event) if (key_code == KEY_RESERVED) return; if (pressed) - pm_wakeup_event(&device->dev, 0); + pm_wakeup_dev_event(&device->dev, 0, button->suspended); if (button->suspended) return; input_report_key(input, key_code, pressed?1:0); @@ -185,6 +185,8 @@ static int surface_button_add(struct acpi_device *device) error = input_register_device(input); if (error) goto err_free_input; + + device_init_wakeup(&device->dev, true); dev_info(&device->dev, "%s [%s]\n", name, acpi_device_bid(device)); return 0; -- cgit v1.2.3 From 8ffdfe35b8a67e509dee5719807b7f88ed2cda7e Mon Sep 17 00:00:00 2001 From: Kyungsik Lee Date: Tue, 16 Jan 2018 10:19:43 +0900 Subject: PM / hibernate: Drop unused parameter of enough_swap Parameter flags is no longer used, remove it. Signed-off-by: Kyungsik Lee Signed-off-by: Rafael J. Wysocki --- kernel/power/swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 293ead59eccc..a46be1261c09 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -879,7 +879,7 @@ out_clean: * space avaiable from the resume partition. */ -static int enough_swap(unsigned int nr_pages, unsigned int flags) +static int enough_swap(unsigned int nr_pages) { unsigned int free_swap = count_swap_pages(root_swap, 1); unsigned int required; @@ -915,7 +915,7 @@ int swsusp_write(unsigned int flags) return error; } if (flags & SF_NOCOMPRESS_MODE) { - if (!enough_swap(pages, flags)) { + if (!enough_swap(pages)) { pr_err("Not enough free swap\n"); error = -ENOSPC; goto out_finish; -- cgit v1.2.3