Skip to content

Commit

Permalink
Merge branch 'acpi-pm'
Browse files Browse the repository at this point in the history
* acpi-pm:
  PM / core: Drop run_wake flag from struct dev_pm_info
  PCI / PM: Simplify device wakeup settings code
  PCI / PM: Drop pme_interrupt flag from struct pci_dev
  ACPI / PM: Consolidate device wakeup settings code
  ACPI / PM: Drop run_wake from struct acpi_device_wakeup_flags
  ACPI / sleep: EC-based wakeup from suspend-to-idle on recent systems
  platform: x86: intel-hid: Wake up the system from suspend-to-idle
  platform: x86: intel-vbtn: Wake up the system from suspend-to-idle
  ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle
  platform/x86: Add driver for ACPI INT0002 Virtual GPIO device
  PCI / PM: Restore PME Enable if skipping wakeup setup
  PM / sleep: Print timing information if debug is enabled
  ACPI / PM: Clean up device wakeup enable/disable code
  ACPI / PM: Change log level of wakeup-related message
  USB / PCI / PM: Allow the PCI core to do the resume cleanup
  ACPI / PM: Run wakeup notify handlers synchronously

Conflicts:
	drivers/base/power/main.c
  • Loading branch information
Rafael J. Wysocki committed Jul 3, 2017
2 parents 9a5f2c8 + de3ef1e commit 8f8e5c3
Showing 35 changed files with 669 additions and 301 deletions.
7 changes: 2 additions & 5 deletions Documentation/power/runtime_pm.txt
Original file line number Diff line number Diff line change
@@ -105,9 +105,9 @@ knows what to do to handle the device).

In particular, if the driver requires remote wakeup capability (i.e. hardware
mechanism allowing the device to request a change of its power state, such as
PCI PME) for proper functioning and device_run_wake() returns 'false' for the
PCI PME) for proper functioning and device_can_wakeup() returns 'false' for the
device, then ->runtime_suspend() should return -EBUSY. On the other hand, if
device_run_wake() returns 'true' for the device and the device is put into a
device_can_wakeup() returns 'true' for the device and the device is put into a
low-power state during the execution of the suspend callback, it is expected
that remote wakeup will be enabled for the device. Generally, remote wakeup
should be enabled for all input devices put into low-power states at run time.
@@ -253,9 +253,6 @@ defined in include/linux/pm.h:
being executed for that device and it is not practical to wait for the
suspend to complete; means "start a resume as soon as you've suspended"

unsigned int run_wake;
- set if the device is capable of generating runtime wake-up events

enum rpm_status runtime_status;
- the runtime PM status of the device; this field's initial value is
RPM_SUSPENDED, which means that each device is initially regarded by the
2 changes: 1 addition & 1 deletion drivers/acpi/battery.c
Original file line number Diff line number Diff line change
@@ -782,7 +782,7 @@ static int acpi_battery_update(struct acpi_battery *battery, bool resume)
if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
(test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
(battery->capacity_now <= battery->alarm)))
pm_wakeup_event(&battery->device->dev, 0);
acpi_pm_wakeup_event(&battery->device->dev);

return result;
}
5 changes: 3 additions & 2 deletions drivers/acpi/button.c
Original file line number Diff line number Diff line change
@@ -217,7 +217,7 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state)
}

if (state)
pm_wakeup_event(&device->dev, 0);
acpi_pm_wakeup_event(&device->dev);

ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
if (ret == NOTIFY_DONE)
@@ -402,7 +402,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
} else {
int keycode;

pm_wakeup_event(&device->dev, 0);
acpi_pm_wakeup_event(&device->dev);
if (button->suspended)
break;

@@ -534,6 +534,7 @@ static int acpi_button_add(struct acpi_device *device)
lid_device = device;
}

device_init_wakeup(&device->dev, true);
printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
return 0;

102 changes: 42 additions & 60 deletions drivers/acpi/device_pm.c
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
#include <linux/pm_qos.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/suspend.h>

#include "internal.h"

@@ -385,6 +386,12 @@ EXPORT_SYMBOL(acpi_bus_power_manageable);
#ifdef CONFIG_PM
static DEFINE_MUTEX(acpi_pm_notifier_lock);

void acpi_pm_wakeup_event(struct device *dev)
{
pm_wakeup_dev_event(dev, 0, acpi_s2idle_wakeup());
}
EXPORT_SYMBOL_GPL(acpi_pm_wakeup_event);

static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
{
struct acpi_device *adev;
@@ -399,9 +406,9 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
mutex_lock(&acpi_pm_notifier_lock);

if (adev->wakeup.flags.notifier_present) {
__pm_wakeup_event(adev->wakeup.ws, 0);
if (adev->wakeup.context.work.func)
queue_pm_work(&adev->wakeup.context.work);
pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup());
if (adev->wakeup.context.func)
adev->wakeup.context.func(&adev->wakeup.context);
}

mutex_unlock(&acpi_pm_notifier_lock);
@@ -413,19 +420,19 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
* acpi_add_pm_notifier - Register PM notify handler for given ACPI device.
* @adev: ACPI device to add the notify handler for.
* @dev: Device to generate a wakeup event for while handling the notification.
* @work_func: Work function to execute when handling the notification.
* @func: Work function to execute when handling the notification.
*
* NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
* PM wakeup events. For example, wakeup events may be generated for bridges
* if one of the devices below the bridge is signaling wakeup, even if the
* bridge itself doesn't have a wakeup GPE associated with it.
*/
acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
void (*work_func)(struct work_struct *work))
void (*func)(struct acpi_device_wakeup_context *context))
{
acpi_status status = AE_ALREADY_EXISTS;

if (!dev && !work_func)
if (!dev && !func)
return AE_BAD_PARAMETER;

mutex_lock(&acpi_pm_notifier_lock);
@@ -435,8 +442,7 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,

adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev));
adev->wakeup.context.dev = dev;
if (work_func)
INIT_WORK(&adev->wakeup.context.work, work_func);
adev->wakeup.context.func = func;

status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY,
acpi_pm_notify_handler, NULL);
@@ -469,10 +475,7 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
if (ACPI_FAILURE(status))
goto out;

if (adev->wakeup.context.work.func) {
cancel_work_sync(&adev->wakeup.context.work);
adev->wakeup.context.work.func = NULL;
}
adev->wakeup.context.func = NULL;
adev->wakeup.context.dev = NULL;
wakeup_source_unregister(adev->wakeup.ws);

@@ -493,6 +496,13 @@ bool acpi_bus_can_wakeup(acpi_handle handle)
}
EXPORT_SYMBOL(acpi_bus_can_wakeup);

bool acpi_pm_device_can_wakeup(struct device *dev)
{
struct acpi_device *adev = ACPI_COMPANION(dev);

return adev ? acpi_device_can_wakeup(adev) : false;
}

/**
* acpi_dev_pm_get_state - Get preferred power state of ACPI device.
* @dev: Device whose preferred target power state to return.
@@ -658,16 +668,15 @@ EXPORT_SYMBOL(acpi_pm_device_sleep_state);

/**
* acpi_pm_notify_work_func - ACPI devices wakeup notification work function.
* @work: Work item to handle.
* @context: Device wakeup context.
*/
static void acpi_pm_notify_work_func(struct work_struct *work)
static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context)
{
struct device *dev;
struct device *dev = context->dev;

dev = container_of(work, struct acpi_device_wakeup_context, work)->dev;
if (dev) {
pm_wakeup_event(dev, 0);
pm_runtime_resume(dev);
pm_request_resume(dev);
}
}

@@ -693,80 +702,53 @@ static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
acpi_status res;
int error;

if (adev->wakeup.flags.enabled)
return 0;

error = acpi_enable_wakeup_device_power(adev, target_state);
if (error)
return error;

if (adev->wakeup.flags.enabled)
return 0;

res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
if (ACPI_SUCCESS(res)) {
adev->wakeup.flags.enabled = 1;
} else {
if (ACPI_FAILURE(res)) {
acpi_disable_wakeup_device_power(adev);
return -EIO;
}
} else {
if (adev->wakeup.flags.enabled) {
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
adev->wakeup.flags.enabled = 0;
}
adev->wakeup.flags.enabled = 1;
} else if (adev->wakeup.flags.enabled) {
acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
acpi_disable_wakeup_device_power(adev);
adev->wakeup.flags.enabled = 0;
}
return 0;
}

/**
* acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable the platform to wake up.
* acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable to generate wakeup events.
* @enable: Whether to enable or disable the wakeup functionality.
*/
int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
{
struct acpi_device *adev;

if (!device_run_wake(phys_dev))
return -EINVAL;

adev = ACPI_COMPANION(phys_dev);
if (!adev) {
dev_dbg(phys_dev, "ACPI companion missing in %s!\n", __func__);
return -ENODEV;
}

return acpi_device_wakeup(adev, ACPI_STATE_S0, enable);
}
EXPORT_SYMBOL(acpi_pm_device_run_wake);

#ifdef CONFIG_PM_SLEEP
/**
* acpi_pm_device_sleep_wake - Enable or disable device to wake up the system.
* @dev: Device to enable/desible to wake up the system from sleep states.
* @enable: Whether to enable or disable @dev to wake up the system.
*/
int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
int acpi_pm_set_device_wakeup(struct device *dev, bool enable)
{
struct acpi_device *adev;
int error;

if (!device_can_wakeup(dev))
return -EINVAL;

adev = ACPI_COMPANION(dev);
if (!adev) {
dev_dbg(dev, "ACPI companion missing in %s!\n", __func__);
return -ENODEV;
}

if (!acpi_device_can_wakeup(adev))
return -EINVAL;

error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
if (!error)
dev_info(dev, "System wakeup %s by ACPI\n",
enable ? "enabled" : "disabled");
dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled");

return error;
}
#endif /* CONFIG_PM_SLEEP */
EXPORT_SYMBOL(acpi_pm_set_device_wakeup);

/**
* acpi_dev_pm_low_power - Put ACPI device into a low-power state.
2 changes: 1 addition & 1 deletion drivers/acpi/ec.c
Original file line number Diff line number Diff line change
@@ -1835,7 +1835,7 @@ static int acpi_ec_suspend(struct device *dev)
struct acpi_ec *ec =
acpi_driver_data(to_acpi_device(dev));

if (ec_freeze_events)
if (acpi_sleep_no_ec_events() && ec_freeze_events)
acpi_ec_disable_event(ec);
return 0;
}
4 changes: 4 additions & 0 deletions drivers/acpi/internal.h
Original file line number Diff line number Diff line change
@@ -198,8 +198,12 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
Suspend/Resume
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT
extern bool acpi_s2idle_wakeup(void);
extern bool acpi_sleep_no_ec_events(void);
extern int acpi_sleep_init(void);
#else
static inline bool acpi_s2idle_wakeup(void) { return false; }
static inline bool acpi_sleep_no_ec_events(void) { return true; }
static inline int acpi_sleep_init(void) { return -ENXIO; }
#endif

5 changes: 2 additions & 3 deletions drivers/acpi/pci_root.c
Original file line number Diff line number Diff line change
@@ -608,8 +608,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
pcie_no_aspm();

pci_acpi_add_bus_pm_notifier(device);
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
device_set_wakeup_capable(root->bus->bridge, device->wakeup.flags.valid);

if (hotadd) {
pcibios_resource_survey_bus(root->bus);
@@ -649,7 +648,7 @@ static void acpi_pci_root_remove(struct acpi_device *device)
pci_stop_root_bus(root->bus);

pci_ioapic_remove(root);
device_set_run_wake(root->bus->bridge, false);
device_set_wakeup_capable(root->bus->bridge, false);
pci_acpi_remove_bus_pm_notifier(device);

pci_remove_root_bus(root->bus);
4 changes: 2 additions & 2 deletions drivers/acpi/proc.c
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)

if (!dev->physical_node_count) {
seq_printf(seq, "%c%-8s\n",
dev->wakeup.flags.run_wake ? '*' : ' ',
dev->wakeup.flags.valid ? '*' : ' ',
device_may_wakeup(&dev->dev) ?
"enabled" : "disabled");
} else {
@@ -58,7 +58,7 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "\t\t");

seq_printf(seq, "%c%-8s %s:%s\n",
dev->wakeup.flags.run_wake ? '*' : ' ',
dev->wakeup.flags.valid ? '*' : ' ',
(device_may_wakeup(&dev->dev) ||
device_may_wakeup(ldev)) ?
"enabled" : "disabled",
23 changes: 8 additions & 15 deletions drivers/acpi/scan.c
Original file line number Diff line number Diff line change
@@ -835,7 +835,7 @@ static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
return err;
}

static void acpi_wakeup_gpe_init(struct acpi_device *device)
static bool acpi_wakeup_gpe_init(struct acpi_device *device)
{
static const struct acpi_device_id button_device_ids[] = {
{"PNP0C0C", 0},
@@ -845,31 +845,24 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device)
};
struct acpi_device_wakeup *wakeup = &device->wakeup;
acpi_status status;
acpi_event_status event_status;

wakeup->flags.notifier_present = 0;

/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids)) {
wakeup->flags.run_wake = 1;
if (!acpi_match_device_ids(device, &button_device_ids[1])) {
/* Do not use Lid/sleep button for S5 wakeup */
if (wakeup->sleep_state == ACPI_STATE_S5)
wakeup->sleep_state = ACPI_STATE_S4;
}
acpi_mark_gpe_for_wake(wakeup->gpe_device, wakeup->gpe_number);
device_set_wakeup_capable(&device->dev, true);
return;
return true;
}

acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device,
wakeup->gpe_number);
status = acpi_get_gpe_status(wakeup->gpe_device, wakeup->gpe_number,
&event_status);
if (ACPI_FAILURE(status))
return;

wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HAS_HANDLER);
status = acpi_setup_gpe_for_wake(device->handle, wakeup->gpe_device,
wakeup->gpe_number);
return ACPI_SUCCESS(status);
}

static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
@@ -887,10 +880,10 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
return;
}

device->wakeup.flags.valid = 1;
device->wakeup.flags.valid = acpi_wakeup_gpe_init(device);
device->wakeup.prepare_count = 0;
acpi_wakeup_gpe_init(device);
/* Call _PSW/_DSW object to disable its ability to wake the sleeping
/*
* Call _PSW/_DSW object to disable its ability to wake the sleeping
* system for the ACPI device with the _PRW object.
* The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
* So it is necessary to call _DSW object first. Only when it is not
Loading

0 comments on commit 8f8e5c3

Please sign in to comment.