Skip to content

Commit

Permalink
Merge branches 'acpi-pm' and 'pm-sleep'
Browse files Browse the repository at this point in the history
* acpi-pm:
  platform/x86: surfacepro3: Support for wakeup from suspend-to-idle
  ACPI / PM: Use Low Power S0 Idle on more systems
  ACPI / PM: Make it possible to ignore the system sleep blacklist

* pm-sleep:
  PM / hibernate: Drop unused parameter of enough_swap
  block, scsi: Fix race between SPI domain validation and system suspend
  PM / sleep: Make lock/unlock_system_sleep() available to kernel modules
  PM: hibernate: Do not subtract NR_FILE_MAPPED in minimum_image_size()
  • Loading branch information
Rafael J. Wysocki committed Jan 18, 2018
3 parents 4b67157 + 19351f3 + 8ffdfe3 commit bcaea46
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 38 deletions.
5 changes: 4 additions & 1 deletion Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/kernel/acpi/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
16 changes: 14 additions & 2 deletions drivers/acpi/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -697,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;
Expand Down Expand Up @@ -900,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;
/*
Expand Down
4 changes: 3 additions & 1 deletion drivers/platform/x86/surfacepro3_button.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 14 additions & 2 deletions drivers/scsi/scsi_transport_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <scsi/scsi.h>
#include "scsi_priv.h"
#include <scsi/scsi_device.h>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions include/linux/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
28 changes: 2 additions & 26 deletions include/linux/suspend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
29 changes: 29 additions & 0 deletions kernel/power/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 2 additions & 4 deletions kernel/power/snapshot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions kernel/power/swap.c
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ static int save_image_lzo(struct swap_map_handle *handle,
* 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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit bcaea46

Please sign in to comment.