Merge branch 'acpi-pm'

* 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
This commit is contained in:
Rafael J. Wysocki
2017-07-03 14:23:09 +02:00
35 changed files with 669 additions and 301 deletions
+2 -5
View File
@@ -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
+1 -1
View File
@@ -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;
}
+3 -2
View File
@@ -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;
+42 -60
View File
@@ -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,7 +420,7 @@ 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
@@ -421,11 +428,11 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
* 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.
+1 -1
View File
@@ -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
View File
@@ -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
+2 -3
View File
@@ -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);
+2 -2
View File
@@ -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",
+8 -15
View File
@@ -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,13 +845,11 @@ 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)
@@ -859,17 +857,12 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device)
}
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
+147 -5
View File
@@ -650,38 +650,165 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
.recover = acpi_pm_finish,
};
static bool s2idle_in_progress;
static bool s2idle_wakeup;
/*
* On platforms supporting the Low Power S0 Idle interface there is an ACPI
* device object with the PNP0D80 compatible device ID (System Power Management
* Controller) and a specific _DSM method under it. That method, if present,
* can be used to indicate to the platform that the OS is transitioning into a
* low-power state in which certain types of activity are not desirable or that
* it is leaving such a state, which allows the platform to adjust its operation
* mode accordingly.
*/
static const struct acpi_device_id lps0_device_ids[] = {
{"PNP0D80", },
{"", },
};
#define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
#define ACPI_LPS0_SCREEN_OFF 3
#define ACPI_LPS0_SCREEN_ON 4
#define ACPI_LPS0_ENTRY 5
#define ACPI_LPS0_EXIT 6
#define ACPI_S2IDLE_FUNC_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT))
static acpi_handle lps0_device_handle;
static guid_t lps0_dsm_guid;
static char lps0_dsm_func_mask;
static void acpi_sleep_run_lps0_dsm(unsigned int func)
{
union acpi_object *out_obj;
if (!(lps0_dsm_func_mask & (1 << func)))
return;
out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, 1, func, NULL);
ACPI_FREE(out_obj);
acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n",
func, out_obj ? "successful" : "failed");
}
static int lps0_device_attach(struct acpi_device *adev,
const struct acpi_device_id *not_used)
{
union acpi_object *out_obj;
if (lps0_device_handle)
return 0;
if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
return 0;
guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid);
/* Check if the _DSM is present and as expected. */
out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL);
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) {
lps0_dsm_func_mask = bitmask;
lps0_device_handle = adev->handle;
}
acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
bitmask);
} else {
acpi_handle_debug(adev->handle,
"_DSM function 0 evaluation failed\n");
}
ACPI_FREE(out_obj);
return 0;
}
static struct acpi_scan_handler lps0_handler = {
.ids = lps0_device_ids,
.attach = lps0_device_attach,
};
static int acpi_freeze_begin(void)
{
acpi_scan_lock_acquire();
s2idle_in_progress = true;
return 0;
}
static int acpi_freeze_prepare(void)
{
acpi_enable_wakeup_devices(ACPI_STATE_S0);
acpi_enable_all_wakeup_gpes();
acpi_os_wait_events_complete();
if (lps0_device_handle) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
} else {
/*
* The configuration of GPEs is changed here to avoid spurious
* wakeups, but that should not be necessary if this is a
* "low-power S0" platform and the low-power S0 _DSM is present.
*/
acpi_enable_all_wakeup_gpes();
acpi_os_wait_events_complete();
}
if (acpi_sci_irq_valid())
enable_irq_wake(acpi_sci_irq);
return 0;
}
static void acpi_freeze_wake(void)
{
/*
* 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
* case it has not been a wakeup event (the GPEs will be checked later).
*/
if (acpi_sci_irq_valid() &&
!irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) {
pm_system_cancel_wakeup();
s2idle_wakeup = true;
}
}
static void acpi_freeze_sync(void)
{
/*
* Process all pending events in case there are any wakeup ones.
*
* The EC driver uses the system workqueue, so that one needs to be
* flushed too.
*/
acpi_os_wait_events_complete();
flush_scheduled_work();
s2idle_wakeup = false;
}
static void acpi_freeze_restore(void)
{
acpi_disable_wakeup_devices(ACPI_STATE_S0);
if (acpi_sci_irq_valid())
disable_irq_wake(acpi_sci_irq);
acpi_enable_all_runtime_gpes();
if (lps0_device_handle) {
acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
} else {
acpi_enable_all_runtime_gpes();
}
}
static void acpi_freeze_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,
};
@@ -696,13 +823,28 @@ static void acpi_sleep_suspend_setup(void)
suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops);
acpi_scan_add_handler(&lps0_handler);
freeze_set_ops(&acpi_freeze_ops);
}
#else /* !CONFIG_SUSPEND */
#define s2idle_in_progress (false)
#define s2idle_wakeup (false)
#define lps0_device_handle (NULL)
static inline void acpi_sleep_suspend_setup(void) {}
#endif /* !CONFIG_SUSPEND */
bool acpi_s2idle_wakeup(void)
{
return s2idle_wakeup;
}
bool acpi_sleep_no_ec_events(void)
{
return !s2idle_in_progress || !lps0_device_handle;
}
#ifdef CONFIG_PM_SLEEP
static u32 saved_bm_rld;
+3 -6
View File
@@ -174,8 +174,7 @@ void zpodd_enable_run_wake(struct ata_device *dev)
sdev_disable_disk_events(dev->sdev);
zpodd->powered_off = true;
device_set_run_wake(&dev->tdev, true);
acpi_pm_device_run_wake(&dev->tdev, true);
acpi_pm_set_device_wakeup(&dev->tdev, true);
}
/* Disable runtime wake capability if it is enabled */
@@ -183,10 +182,8 @@ void zpodd_disable_run_wake(struct ata_device *dev)
{
struct zpodd *zpodd = dev->zpodd;
if (zpodd->powered_off) {
acpi_pm_device_run_wake(&dev->tdev, false);
device_set_run_wake(&dev->tdev, false);
}
if (zpodd->powered_off)
acpi_pm_set_device_wakeup(&dev->tdev, false);
}
/*
+5 -5
View File
@@ -418,6 +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);
}
#ifdef CONFIG_PM_DEBUG
static void dpm_show_time(ktime_t starttime, pm_message_t state,
const char *info)
{
@@ -435,6 +436,10 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state,
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)
@@ -1093,11 +1098,6 @@ 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;
+12 -6
View File
@@ -28,8 +28,8 @@ bool events_check_enabled __read_mostly;
/* First wakeup IRQ seen by the kernel in the last cycle. */
unsigned int pm_wakeup_irq __read_mostly;
/* If set and the system is suspending, terminate the suspend. */
static bool pm_abort_suspend __read_mostly;
/* If greater than 0 and the system is suspending, terminate the suspend. */
static atomic_t pm_abort_suspend __read_mostly;
/*
* Combined counters of registered wakeup events and wakeup events in progress.
@@ -857,20 +857,26 @@ bool pm_wakeup_pending(void)
pm_print_active_wakeup_sources();
}
return ret || pm_abort_suspend;
return ret || atomic_read(&pm_abort_suspend) > 0;
}
void pm_system_wakeup(void)
{
pm_abort_suspend = true;
atomic_inc(&pm_abort_suspend);
freeze_wake();
}
EXPORT_SYMBOL_GPL(pm_system_wakeup);
void pm_wakeup_clear(void)
void pm_system_cancel_wakeup(void)
{
atomic_dec(&pm_abort_suspend);
}
void pm_wakeup_clear(bool reset)
{
pm_abort_suspend = false;
pm_wakeup_irq = 0;
if (reset)
atomic_set(&pm_abort_suspend, 0);
}
void pm_system_irq_wakeup(unsigned int irq_number)
+22 -68
View File
@@ -394,29 +394,26 @@ bool pciehp_is_native(struct pci_dev *pdev)
/**
* pci_acpi_wake_bus - Root bus wakeup notification fork function.
* @work: Work item to handle.
* @context: Device wakeup context.
*/
static void pci_acpi_wake_bus(struct work_struct *work)
static void pci_acpi_wake_bus(struct acpi_device_wakeup_context *context)
{
struct acpi_device *adev;
struct acpi_pci_root *root;
adev = container_of(work, struct acpi_device, wakeup.context.work);
adev = container_of(context, struct acpi_device, wakeup.context);
root = acpi_driver_data(adev);
pci_pme_wakeup_bus(root->bus);
}
/**
* pci_acpi_wake_dev - PCI device wakeup notification work function.
* @handle: ACPI handle of a device the notification is for.
* @work: Work item to handle.
* @context: Device wakeup context.
*/
static void pci_acpi_wake_dev(struct work_struct *work)
static void pci_acpi_wake_dev(struct acpi_device_wakeup_context *context)
{
struct acpi_device_wakeup_context *context;
struct pci_dev *pci_dev;
context = container_of(work, struct acpi_device_wakeup_context, work);
pci_dev = to_pci_dev(context->dev);
if (pci_dev->pme_poll)
@@ -424,7 +421,7 @@ static void pci_acpi_wake_dev(struct work_struct *work)
if (pci_dev->current_state == PCI_D3cold) {
pci_wakeup_event(pci_dev);
pm_runtime_resume(&pci_dev->dev);
pm_request_resume(&pci_dev->dev);
return;
}
@@ -433,7 +430,7 @@ static void pci_acpi_wake_dev(struct work_struct *work)
pci_check_pme_status(pci_dev);
pci_wakeup_event(pci_dev);
pm_runtime_resume(&pci_dev->dev);
pm_request_resume(&pci_dev->dev);
pci_pme_wakeup_bus(pci_dev->subordinate);
}
@@ -572,67 +569,29 @@ static pci_power_t acpi_pci_get_power_state(struct pci_dev *dev)
return state_conv[state];
}
static bool acpi_pci_can_wakeup(struct pci_dev *dev)
{
struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
return adev ? acpi_device_can_wakeup(adev) : false;
}
static void acpi_pci_propagate_wakeup_enable(struct pci_bus *bus, bool enable)
static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable)
{
while (bus->parent) {
if (!acpi_pm_device_sleep_wake(&bus->self->dev, enable))
return;
if (acpi_pm_device_can_wakeup(&bus->self->dev))
return acpi_pm_set_device_wakeup(&bus->self->dev, enable);
bus = bus->parent;
}
/* We have reached the root bus. */
if (bus->bridge)
acpi_pm_device_sleep_wake(bus->bridge, enable);
}
static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)
{
if (acpi_pci_can_wakeup(dev))
return acpi_pm_device_sleep_wake(&dev->dev, enable);
acpi_pci_propagate_wakeup_enable(dev->bus, enable);
return 0;
}
static void acpi_pci_propagate_run_wake(struct pci_bus *bus, bool enable)
{
while (bus->parent) {
struct pci_dev *bridge = bus->self;
if (bridge->pme_interrupt)
return;
if (!acpi_pm_device_run_wake(&bridge->dev, enable))
return;
bus = bus->parent;
if (bus->bridge) {
if (acpi_pm_device_can_wakeup(bus->bridge))
return acpi_pm_set_device_wakeup(bus->bridge, enable);
}
/* We have reached the root bus. */
if (bus->bridge)
acpi_pm_device_run_wake(bus->bridge, enable);
return 0;
}
static int acpi_pci_run_wake(struct pci_dev *dev, bool enable)
static int acpi_pci_wakeup(struct pci_dev *dev, bool enable)
{
/*
* Per PCI Express Base Specification Revision 2.0 section
* 5.3.3.2 Link Wakeup, platform support is needed for D3cold
* waking up to power on the main link even if there is PME
* support for D3cold
*/
if (dev->pme_interrupt && !dev->runtime_d3cold)
return 0;
if (acpi_pm_device_can_wakeup(&dev->dev))
return acpi_pm_set_device_wakeup(&dev->dev, enable);
if (!acpi_pm_device_run_wake(&dev->dev, enable))
return 0;
acpi_pci_propagate_run_wake(dev->bus, enable);
return 0;
return acpi_pci_propagate_wakeup(dev->bus, enable);
}
static bool acpi_pci_need_resume(struct pci_dev *dev)
@@ -656,8 +615,7 @@ static const struct pci_platform_pm_ops acpi_pci_platform_pm = {
.set_state = acpi_pci_set_power_state,
.get_state = acpi_pci_get_power_state,
.choose_state = acpi_pci_choose_state,
.sleep_wake = acpi_pci_sleep_wake,
.run_wake = acpi_pci_run_wake,
.set_wakeup = acpi_pci_wakeup,
.need_resume = acpi_pci_need_resume,
};
@@ -780,9 +738,7 @@ static void pci_acpi_setup(struct device *dev)
return;
device_set_wakeup_capable(dev, true);
acpi_pci_sleep_wake(pci_dev, false);
if (adev->wakeup.flags.run_wake)
device_set_run_wake(dev, true);
acpi_pci_wakeup(pci_dev, false);
}
static void pci_acpi_cleanup(struct device *dev)
@@ -793,10 +749,8 @@ static void pci_acpi_cleanup(struct device *dev)
return;
pci_acpi_remove_pm_notifier(adev);
if (adev->wakeup.flags.valid) {
if (adev->wakeup.flags.valid)
device_set_wakeup_capable(dev, false);
device_set_run_wake(dev, false);
}
}
static bool pci_acpi_bus_match(struct device *dev)
+1 -1
View File
@@ -1216,7 +1216,7 @@ static int pci_pm_runtime_resume(struct device *dev)
pci_restore_standard_config(pci_dev);
pci_fixup_device(pci_fixup_resume_early, pci_dev);
__pci_enable_wake(pci_dev, PCI_D0, true, false);
pci_enable_wake(pci_dev, PCI_D0, false);
pci_fixup_device(pci_fixup_resume, pci_dev);
rc = pm->runtime_resume(dev);
+2 -8
View File
@@ -39,12 +39,7 @@ static pci_power_t mid_pci_choose_state(struct pci_dev *pdev)
return PCI_D3hot;
}
static int mid_pci_sleep_wake(struct pci_dev *dev, bool enable)
{
return 0;
}
static int mid_pci_run_wake(struct pci_dev *dev, bool enable)
static int mid_pci_wakeup(struct pci_dev *dev, bool enable)
{
return 0;
}
@@ -59,8 +54,7 @@ static const struct pci_platform_pm_ops mid_pci_platform_pm = {
.set_state = mid_pci_set_power_state,
.get_state = mid_pci_get_power_state,
.choose_state = mid_pci_choose_state,
.sleep_wake = mid_pci_sleep_wake,
.run_wake = mid_pci_run_wake,
.set_wakeup = mid_pci_wakeup,
.need_resume = mid_pci_need_resume,
};
+37 -31
View File
@@ -574,8 +574,7 @@ static const struct pci_platform_pm_ops *pci_platform_pm;
int pci_set_platform_pm(const struct pci_platform_pm_ops *ops)
{
if (!ops->is_manageable || !ops->set_state || !ops->get_state ||
!ops->choose_state || !ops->sleep_wake || !ops->run_wake ||
!ops->need_resume)
!ops->choose_state || !ops->set_wakeup || !ops->need_resume)
return -EINVAL;
pci_platform_pm = ops;
return 0;
@@ -603,16 +602,10 @@ static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
pci_platform_pm->choose_state(dev) : PCI_POWER_ERROR;
}
static inline int platform_pci_sleep_wake(struct pci_dev *dev, bool enable)
static inline int platform_pci_set_wakeup(struct pci_dev *dev, bool enable)
{
return pci_platform_pm ?
pci_platform_pm->sleep_wake(dev, enable) : -ENODEV;
}
static inline int platform_pci_run_wake(struct pci_dev *dev, bool enable)
{
return pci_platform_pm ?
pci_platform_pm->run_wake(dev, enable) : -ENODEV;
pci_platform_pm->set_wakeup(dev, enable) : -ENODEV;
}
static inline bool platform_pci_need_resume(struct pci_dev *dev)
@@ -1805,6 +1798,23 @@ static void __pci_pme_active(struct pci_dev *dev, bool enable)
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
}
static void pci_pme_restore(struct pci_dev *dev)
{
u16 pmcsr;
if (!dev->pme_support)
return;
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
if (dev->wakeup_prepared) {
pmcsr |= PCI_PM_CTRL_PME_ENABLE;
} else {
pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
pmcsr |= PCI_PM_CTRL_PME_STATUS;
}
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
}
/**
* pci_pme_active - enable or disable PCI device's PME# function
* @dev: PCI device to handle.
@@ -1872,10 +1882,9 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
EXPORT_SYMBOL(pci_pme_active);
/**
* __pci_enable_wake - enable PCI device as wakeup event source
* pci_enable_wake - enable PCI device as wakeup event source
* @dev: PCI device affected
* @state: PCI state from which device will issue wakeup events
* @runtime: True if the events are to be generated at run time
* @enable: True to enable event generation; false to disable
*
* This enables the device as a wakeup event source, or disables it.
@@ -1891,17 +1900,18 @@ EXPORT_SYMBOL(pci_pme_active);
* Error code depending on the platform is returned if both the platform and
* the native mechanism fail to enable the generation of wake-up events
*/
int __pci_enable_wake(struct pci_dev *dev, pci_power_t state,
bool runtime, bool enable)
int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
{
int ret = 0;
if (enable && !runtime && !device_may_wakeup(&dev->dev))
return -EINVAL;
/* Don't do the same thing twice in a row for one device. */
if (!!enable == !!dev->wakeup_prepared)
/*
* Don't do the same thing twice in a row for one device, but restore
* PME Enable in case it has been updated by config space restoration.
*/
if (!!enable == !!dev->wakeup_prepared) {
pci_pme_restore(dev);
return 0;
}
/*
* According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
@@ -1916,24 +1926,20 @@ int __pci_enable_wake(struct pci_dev *dev, pci_power_t state,
pci_pme_active(dev, true);
else
ret = 1;
error = runtime ? platform_pci_run_wake(dev, true) :
platform_pci_sleep_wake(dev, true);
error = platform_pci_set_wakeup(dev, true);
if (ret)
ret = error;
if (!ret)
dev->wakeup_prepared = true;
} else {
if (runtime)
platform_pci_run_wake(dev, false);
else
platform_pci_sleep_wake(dev, false);
platform_pci_set_wakeup(dev, false);
pci_pme_active(dev, false);
dev->wakeup_prepared = false;
}
return ret;
}
EXPORT_SYMBOL(__pci_enable_wake);
EXPORT_SYMBOL(pci_enable_wake);
/**
* pci_wake_from_d3 - enable/disable device to wake up from D3_hot or D3_cold
@@ -2075,12 +2081,12 @@ int pci_finish_runtime_suspend(struct pci_dev *dev)
dev->runtime_d3cold = target_state == PCI_D3cold;
__pci_enable_wake(dev, target_state, true, pci_dev_run_wake(dev));
pci_enable_wake(dev, target_state, pci_dev_run_wake(dev));
error = pci_set_power_state(dev, target_state);
if (error) {
__pci_enable_wake(dev, target_state, true, false);
pci_enable_wake(dev, target_state, false);
dev->runtime_d3cold = false;
}
@@ -2099,7 +2105,7 @@ bool pci_dev_run_wake(struct pci_dev *dev)
{
struct pci_bus *bus = dev->bus;
if (device_run_wake(&dev->dev))
if (device_can_wakeup(&dev->dev))
return true;
if (!dev->pme_support)
@@ -2112,7 +2118,7 @@ bool pci_dev_run_wake(struct pci_dev *dev)
while (bus->parent) {
struct pci_dev *bridge = bus->self;
if (device_run_wake(&bridge->dev))
if (device_can_wakeup(&bridge->dev))
return true;
bus = bus->parent;
@@ -2120,7 +2126,7 @@ bool pci_dev_run_wake(struct pci_dev *dev)
/* We have reached the root bus. */
if (bus->bridge)
return device_run_wake(bus->bridge);
return device_can_wakeup(bus->bridge);
return false;
}
+2 -7
View File
@@ -47,11 +47,7 @@ int pci_probe_reset_function(struct pci_dev *dev);
* platform; to be used during system-wide transitions from a
* sleeping state to the working state and vice versa
*
* @sleep_wake: enables/disables the system wake up capability of given device
*
* @run_wake: enables/disables the platform to generate run-time wake-up events
* for given device (the device's wake-up capability has to be
* enabled by @sleep_wake for this feature to work)
* @set_wakeup: enables/disables wakeup capability for the device
*
* @need_resume: returns 'true' if the given device (which is currently
* suspended) needs to be resumed to be configured for system
@@ -65,8 +61,7 @@ struct pci_platform_pm_ops {
int (*set_state)(struct pci_dev *dev, pci_power_t state);
pci_power_t (*get_state)(struct pci_dev *dev);
pci_power_t (*choose_state)(struct pci_dev *dev);
int (*sleep_wake)(struct pci_dev *dev, bool enable);
int (*run_wake)(struct pci_dev *dev, bool enable);
int (*set_wakeup)(struct pci_dev *dev, bool enable);
bool (*need_resume)(struct pci_dev *dev);
};
+7 -9
View File
@@ -294,31 +294,29 @@ static irqreturn_t pcie_pme_irq(int irq, void *context)
}
/**
* pcie_pme_set_native - Set the PME interrupt flag for given device.
* pcie_pme_can_wakeup - Set the wakeup capability flag.
* @dev: PCI device to handle.
* @ign: Ignored.
*/
static int pcie_pme_set_native(struct pci_dev *dev, void *ign)
static int pcie_pme_can_wakeup(struct pci_dev *dev, void *ign)
{
device_set_run_wake(&dev->dev, true);
dev->pme_interrupt = true;
device_set_wakeup_capable(&dev->dev, true);
return 0;
}
/**
* pcie_pme_mark_devices - Set the PME interrupt flag for devices below a port.
* pcie_pme_mark_devices - Set the wakeup flag for devices below a port.
* @port: PCIe root port or event collector to handle.
*
* For each device below given root port, including the port itself (or for each
* root complex integrated endpoint if @port is a root complex event collector)
* set the flag indicating that it can signal run-time wake-up events via PCIe
* PME interrupts.
* set the flag indicating that it can signal run-time wake-up events.
*/
static void pcie_pme_mark_devices(struct pci_dev *port)
{
pcie_pme_set_native(port, NULL);
pcie_pme_can_wakeup(port, NULL);
if (port->subordinate)
pci_walk_bus(port->subordinate, pcie_pme_set_native, NULL);
pci_walk_bus(port->subordinate, pcie_pme_can_wakeup, NULL);
}
/**
+19
View File
@@ -794,6 +794,25 @@ config INTEL_CHT_INT33FE
This driver instantiates i2c-clients for these, so that standard
i2c drivers for these chips can bind to the them.
config INTEL_INT0002_VGPIO
tristate "Intel ACPI INT0002 Virtual GPIO driver"
depends on GPIOLIB && ACPI
select GPIOLIB_IRQCHIP
---help---
Some peripherals on Bay Trail and Cherry Trail platforms signal a
Power Management Event (PME) to the Power Management Controller (PMC)
to wakeup the system. When this happens software needs to explicitly
clear the PME bus 0 status bit in the GPE0a_STS register to avoid an
IRQ storm on IRQ 9.
This is modelled in ACPI through the INT0002 ACPI device, which is
called a "Virtual GPIO controller" in ACPI because it defines the
event handler to call when the PME triggers through _AEI and _L02
methods as would be done for a real GPIO interrupt in ACPI.
To compile this driver as a module, choose M here: the module will
be called intel_int0002_vgpio.
config INTEL_HID_EVENT
tristate "INTEL HID Event"
depends on ACPI

Some files were not shown because too many files have changed in this diff Show More