Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1660587 > unrolled thread
| Started by | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| First post | 2017-06-08 02:20 +0200 |
| Last post | 2017-06-13 13:30 +0200 |
| Articles | 20 on this page of 29 — 8 participants |
Back to article view | Back to linux.kernel
[PATCH 0/6] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-08 02:20 +0200
[PATCH 1/6] ACPI / PM: Run wakeup notify handlers synchronously "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-08 02:20 +0200
[PATCH 5/6] PM / sleep: Print timing information if debug is enabled "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-08 02:20 +0200
[PATCH 3/6] ACPI / PM: Change log level of wakeup-related message "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-08 02:20 +0200
[PATCH 6/6] ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-08 02:20 +0200
[PATCH 2/6] USB / PCI / PM: Allow the PCI core to do the resume cleanup "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-08 02:20 +0200
Re: [PATCH 2/6] USB / PCI / PM: Allow the PCI core to do the resume cleanup Alan Stern <stern@rowland.harvard.edu> - 2017-06-08 17:30 +0200
Re: [PATCH 2/6] USB / PCI / PM: Allow the PCI core to do the resume cleanup "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-09 01:10 +0200
[PATCH 4/6] ACPI / PM: Clean up device wakeup enable/disable code "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-08 02:20 +0200
Re: [PATCH 0/6] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups Hans de Goede <hdegoede@redhat.com> - 2017-06-08 09:30 +0200
Re: [PATCH 0/6] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups Dominik Brodowski <linux@dominikbrodowski.net> - 2017-06-08 10:50 +0200
Re: [PATCH 0/6] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-08 14:10 +0200
[PATCH v2 0/8] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
[PATCH v2 6/8] PCI / PM: Restore PME Enable if skipping wakeup setup "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
Re: [PATCH v2 6/8] PCI / PM: Restore PME Enable if skipping wakeup setup Bjorn Helgaas <helgaas@kernel.org> - 2017-06-14 20:20 +0200
[PATCH v2 4/8] ACPI / PM: Clean up device wakeup enable/disable code "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
[PATCH v2 5/8] PM / sleep: Print timing information if debug is enabled "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
Re: [PATCH v2 5/8] PM / sleep: Print timing information if debug is enabled Joe Perches <joe@perches.com> - 2017-06-13 00:20 +0200
[PATCH v2 8/8] ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
[PATCH v2 3/8] ACPI / PM: Change log level of wakeup-related message "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
[PATCH v2 2/8] USB / PCI / PM: Allow the PCI core to do the resume cleanup "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
Re: [PATCH v2 2/8] USB / PCI / PM: Allow the PCI core to do the resume cleanup Greg KH <greg@kroah.com> - 2017-06-13 11:00 +0200
Re: [PATCH v2 2/8] USB / PCI / PM: Allow the PCI core to do the resume cleanup "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-13 13:30 +0200
[PATCH v2 1/8] ACPI / PM: Run wakeup notify handlers synchronously "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
Re: [PATCH v2 1/8] ACPI / PM: Run wakeup notify handlers synchronously Bjorn Helgaas <helgaas@kernel.org> - 2017-06-14 20:20 +0200
Re: [PATCH v2 1/8] ACPI / PM: Run wakeup notify handlers synchronously "Rafael J. Wysocki" <rafael@kernel.org> - 2017-06-15 00:30 +0200
[PATCH v2 7/8] platform/x86: Add driver for ACPI INT0002 Virtual GPIO device "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-12 23:10 +0200
Re: [PATCH v2 0/8] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups Dominik Brodowski <linux@dominikbrodowski.net> - 2017-06-13 08:00 +0200
Re: [PATCH v2 0/8] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups "Rafael J. Wysocki" <rjw@rjwysocki.net> - 2017-06-13 13:30 +0200
Page 1 of 2 [1] 2 Next page →
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-08 02:20 +0200 |
| Subject | [PATCH 0/6] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups |
| Message-ID | <tPTl7-5lN-7@gated-at.bofh.it> |
Hi All, This series is a replacement for commit eed4d47efe95 (ACPI / sleep: Ignore spurious SCI wakeups from suspend-to-idle) which is still there in 4.12-rc4 but will be reverted shortly, because it triggered issues on quite a few systems. The last patch in the series is a counterpart of the above commit with a few modifications, mostly to avoid affecting suspend-to-RAM and to reorder messages printed to kernel logs to make them somewhat less confusing. The previous patches are pre-requisite changes plus some cleanups. The major ones are [1-2/6] and [4/6] that are really needed for things to work as expected after [6/6]. In addition to that, this patch from Hans: https://patchwork.kernel.org/patch/9762815/ is needed for USB wakeup on Bay Trail and Cherry Trail systems to work in general. Thanks, Rafael
[toc] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-08 02:20 +0200 |
| Subject | [PATCH 1/6] ACPI / PM: Run wakeup notify handlers synchronously |
| Message-ID | <tPTl7-5lN-11@gated-at.bofh.it> |
| In reply to | #1660587 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The work functions provided by the users of acpi_add_pm_notifier()
should be run synchronously before re-enabling the wakeup GPE in
case they are used to clear the status and/or disable the wakeup
signaling at the source. Otherwise, which is the case currently in
the PCI bus type code, the same wakeup event may be signaled for
multiple times while the execution of the work function in response
to it has already been queued up.
Fortunately, acpi_add_pm_notifier() is only used by PCI and by
ACPI device PM code internally, so the change is relatively
straightforward to make.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/device_pm.c | 27 +++++++++++----------------
drivers/pci/pci-acpi.c | 17 +++++++----------
include/acpi/acpi_bus.h | 4 ++--
3 files changed, 20 insertions(+), 28 deletions(-)
Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -400,8 +400,8 @@ static void acpi_pm_notify_handler(acpi_
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);
+ if (adev->wakeup.context.func)
+ adev->wakeup.context.func(&adev->wakeup.context);
}
mutex_unlock(&acpi_pm_notifier_lock);
@@ -413,7 +413,7 @@ static void acpi_pm_notify_handler(acpi_
* 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 +421,11 @@ static void acpi_pm_notify_handler(acpi_
* 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 +435,7 @@ acpi_status acpi_add_pm_notifier(struct
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 +468,7 @@ acpi_status acpi_remove_pm_notifier(stru
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);
@@ -658,16 +654,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);
}
}
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -319,7 +319,7 @@ struct acpi_device_wakeup_flags {
};
struct acpi_device_wakeup_context {
- struct work_struct work;
+ void (*func)(struct acpi_device_wakeup_context *context);
struct device *dev;
};
@@ -599,7 +599,7 @@ static inline bool acpi_device_always_pr
#ifdef CONFIG_PM
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 acpi_remove_pm_notifier(struct acpi_device *adev);
int acpi_pm_device_sleep_state(struct device *, int *, int);
int acpi_pm_device_run_wake(struct device *, bool);
Index: linux-pm/drivers/pci/pci-acpi.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-acpi.c
+++ linux-pm/drivers/pci/pci-acpi.c
@@ -395,29 +395,26 @@ bool pciehp_is_native(struct pci_dev *pd
/**
* 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)
@@ -425,7 +422,7 @@ static void pci_acpi_wake_dev(struct wor
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;
}
@@ -434,7 +431,7 @@ static void pci_acpi_wake_dev(struct wor
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);
}
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-08 02:20 +0200 |
| Subject | [PATCH 5/6] PM / sleep: Print timing information if debug is enabled |
| Message-ID | <tPTl7-5lN-9@gated-at.bofh.it> |
| In reply to | #1660587 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Avoid printing the device suspend/resume timing information if
CONFIG_PM_DEBUG is not set to reduce the log noise level.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/base/power/main.c | 4 ++++
1 file changed, 4 insertions(+)
Index: linux-pm/drivers/base/power/main.c
===================================================================
--- linux-pm.orig/drivers/base/power/main.c
+++ linux-pm/drivers/base/power/main.c
@@ -417,6 +417,7 @@ static void pm_dev_err(struct device *de
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, char *info)
{
ktime_t calltime;
@@ -433,6 +434,9 @@ static void dpm_show_time(ktime_t startt
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, char *info) {}
+#endif /* CONFIG_PM_DEBUG */
static int dpm_run_callback(pm_callback_t cb, struct device *dev,
pm_message_t state, char *info)
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-08 02:20 +0200 |
| Subject | [PATCH 3/6] ACPI / PM: Change log level of wakeup-related message |
| Message-ID | <tPTl8-5lN-27@gated-at.bofh.it> |
| In reply to | #1660587 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Change the log level of the "System wakeup enabled/disabled by ACPI" message in acpi_pm_device_sleep_wake() to "debug" to reduce to log noise level. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/device_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) Index: linux-pm/drivers/acpi/device_pm.c =================================================================== --- linux-pm.orig/drivers/acpi/device_pm.c +++ linux-pm/drivers/acpi/device_pm.c @@ -756,8 +756,8 @@ int acpi_pm_device_sleep_wake(struct dev 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, "System wakeup %s by ACPI\n", + enable ? "enabled" : "disabled"); return error; }
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-08 02:20 +0200 |
| Subject | [PATCH 6/6] ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle |
| Message-ID | <tPTl9-5lN-55@gated-at.bofh.it> |
| In reply to | #1660587 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The ACPI SCI (System Control Interrupt) is set up as a wakeup IRQ
during suspend-to-idle transitions and, consequently, any events
signaled through it wake up the system from that state. However,
on some systems some of the events signaled via the ACPI SCI while
suspended to idle should not cause the system to wake up. In fact,
quite often they should just be discarded.
Arguably, systems should not resume entirely on such events, but in
order to decide which events really should cause the system to resume
and which are spurious, it is necessary to resume up to the point
when ACPI SCIs are actually handled and processed, which is after
executing dpm_resume_noirq() in the system resume path.
For this reasons, add a loop around freeze_enter() in which the
platforms can process events signaled via multiplexed IRQ lines
like the ACPI SCI and add suspend-to-idle hooks that can be
used for this purpose to struct platform_freeze_ops.
In the ACPI case, the ->wake hook is used for checking if the SCI
has triggered while suspended and deferring the interrupt-induced
system wakeup until the events signaled through it are actually
processed sufficiently to decide whether or not the system should
resume. In turn, the ->sync hook allows all of the relevant event
queues to be flushed so as to prevent events from being missed due
to race conditions.
In addition to that, some ACPI code processing wakeup events needs
to be modified to use the "hard" version of wakeup triggers, so that
it will cause a system resume to happen on device-induced wakeup
events even if the "soft" mechanism to prevent the system from
suspending is not enabled. However, to preserve the existing
behavior with respect to suspend-to-RAM, this only is done in
the suspend-to-idle case and only if an SCI has occurred while
suspended.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/battery.c | 2 +-
drivers/acpi/button.c | 5 +++--
drivers/acpi/device_pm.c | 9 ++++++++-
drivers/acpi/internal.h | 2 ++
drivers/acpi/sleep.c | 37 +++++++++++++++++++++++++++++++++++++
drivers/base/power/main.c | 5 -----
drivers/base/power/wakeup.c | 18 ++++++++++++------
include/acpi/acpi_bus.h | 4 ++++
include/linux/suspend.h | 7 +++++--
kernel/power/process.c | 2 +-
kernel/power/suspend.c | 35 +++++++++++++++++++++++++++++------
11 files changed, 102 insertions(+), 24 deletions(-)
Index: linux-pm/include/linux/suspend.h
===================================================================
--- linux-pm.orig/include/linux/suspend.h
+++ linux-pm/include/linux/suspend.h
@@ -189,6 +189,8 @@ struct platform_suspend_ops {
struct platform_freeze_ops {
int (*begin)(void);
int (*prepare)(void);
+ void (*wake)(void);
+ void (*sync)(void);
void (*restore)(void);
void (*end)(void);
};
@@ -428,7 +430,8 @@ extern unsigned int pm_wakeup_irq;
extern bool pm_wakeup_pending(void);
extern void pm_system_wakeup(void);
-extern void pm_wakeup_clear(void);
+extern void pm_system_cancel_wakeup(void);
+extern void pm_wakeup_clear(bool reset);
extern void pm_system_irq_wakeup(unsigned int irq_number);
extern bool pm_get_wakeup_count(unsigned int *count, bool block);
extern bool pm_save_wakeup_count(unsigned int count);
@@ -478,7 +481,7 @@ static inline int unregister_pm_notifier
static inline bool pm_wakeup_pending(void) { return false; }
static inline void pm_system_wakeup(void) {}
-static inline void pm_wakeup_clear(void) {}
+static inline void pm_wakeup_clear(bool reset) {}
static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
static inline void lock_system_sleep(void) {}
Index: linux-pm/kernel/power/suspend.c
===================================================================
--- linux-pm.orig/kernel/power/suspend.c
+++ linux-pm/kernel/power/suspend.c
@@ -72,6 +72,8 @@ static void freeze_begin(void)
static void freeze_enter(void)
{
+ trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, true);
+
spin_lock_irq(&suspend_freeze_lock);
if (pm_wakeup_pending())
goto out;
@@ -84,11 +86,9 @@ static void freeze_enter(void)
/* Push all the CPUs into the idle loop. */
wake_up_all_idle_cpus();
- pr_debug("PM: suspend-to-idle\n");
/* 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);
- pr_debug("PM: resume from suspend-to-idle\n");
cpuidle_pause();
put_online_cpus();
@@ -98,6 +98,31 @@ static void freeze_enter(void)
out:
suspend_freeze_state = FREEZE_STATE_NONE;
spin_unlock_irq(&suspend_freeze_lock);
+
+ trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, false);
+}
+
+static void s2idle_loop(void)
+{
+ pr_debug("PM: suspend-to-idle\n");
+
+ do {
+ freeze_enter();
+
+ if (freeze_ops && freeze_ops->wake)
+ freeze_ops->wake();
+
+ dpm_resume_noirq(PMSG_RESUME);
+ if (freeze_ops && freeze_ops->sync)
+ freeze_ops->sync();
+
+ if (pm_wakeup_pending())
+ break;
+
+ pm_wakeup_clear(false);
+ } while (!dpm_suspend_noirq(PMSG_SUSPEND));
+
+ pr_debug("PM: resume from suspend-to-idle\n");
}
void freeze_wake(void)
@@ -371,10 +396,8 @@ static int suspend_enter(suspend_state_t
* all the devices are suspended.
*/
if (state == PM_SUSPEND_FREEZE) {
- trace_suspend_resume(TPS("machine_suspend"), state, true);
- freeze_enter();
- trace_suspend_resume(TPS("machine_suspend"), state, false);
- goto Platform_wake;
+ s2idle_loop();
+ goto Platform_early_resume;
}
error = disable_nonboot_cpus();
Index: linux-pm/drivers/base/power/main.c
===================================================================
--- linux-pm.orig/drivers/base/power/main.c
+++ linux-pm/drivers/base/power/main.c
@@ -1095,11 +1095,6 @@ static int __device_suspend_noirq(struct
if (async_error)
goto Complete;
- if (pm_wakeup_pending()) {
- async_error = -EBUSY;
- goto Complete;
- }
-
if (dev->power.syscore || dev->power.direct_complete)
goto Complete;
Index: linux-pm/drivers/base/power/wakeup.c
===================================================================
--- linux-pm.orig/drivers/base/power/wakeup.c
+++ linux-pm/drivers/base/power/wakeup.c
@@ -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.
@@ -855,20 +855,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)
Index: linux-pm/kernel/power/process.c
===================================================================
--- linux-pm.orig/kernel/power/process.c
+++ linux-pm/kernel/power/process.c
@@ -132,7 +132,7 @@ int freeze_processes(void)
if (!pm_freezing)
atomic_inc(&system_freezing_cnt);
- pm_wakeup_clear();
+ pm_wakeup_clear(true);
pr_info("Freezing user space processes ... ");
pm_freezing = true;
error = try_to_freeze_tasks(true);
Index: linux-pm/drivers/acpi/sleep.c
===================================================================
--- linux-pm.orig/drivers/acpi/sleep.c
+++ linux-pm/drivers/acpi/sleep.c
@@ -650,6 +650,8 @@ static const struct platform_suspend_ops
.recover = acpi_pm_finish,
};
+static bool s2idle_wakeup;
+
static int acpi_freeze_begin(void)
{
acpi_scan_lock_acquire();
@@ -666,6 +668,33 @@ static int acpi_freeze_prepare(void)
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)
{
if (acpi_sci_irq_valid())
@@ -682,6 +711,8 @@ static void acpi_freeze_end(void)
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,
};
@@ -700,9 +731,15 @@ static void acpi_sleep_suspend_setup(voi
}
#else /* !CONFIG_SUSPEND */
+#define s2idle_wakeup (false)
static inline void acpi_sleep_suspend_setup(void) {}
#endif /* !CONFIG_SUSPEND */
+bool acpi_s2idle_wakeup(void)
+{
+ return s2idle_wakeup;
+}
+
#ifdef CONFIG_PM_SLEEP
static u32 saved_bm_rld;
Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -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_wakeup_event(struct device *dev)
+{
+ pm_wakeup_dev_event(dev, 0, acpi_s2idle_wakeup());
+}
+EXPORT_SYMBOL_GPL(acpi_wakeup_event);
+
static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
{
struct acpi_device *adev;
@@ -399,7 +406,7 @@ static void acpi_pm_notify_handler(acpi_
mutex_lock(&acpi_pm_notifier_lock);
if (adev->wakeup.flags.notifier_present) {
- __pm_wakeup_event(adev->wakeup.ws, 0);
+ pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup());
if (adev->wakeup.context.func)
adev->wakeup.context.func(&adev->wakeup.context);
}
Index: linux-pm/drivers/acpi/button.c
===================================================================
--- linux-pm.orig/drivers/acpi/button.c
+++ linux-pm/drivers/acpi/button.c
@@ -217,7 +217,7 @@ static int acpi_lid_notify_state(struct
}
if (state)
- pm_wakeup_event(&device->dev, 0);
+ acpi_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 ac
} else {
int keycode;
- pm_wakeup_event(&device->dev, 0);
+ acpi_wakeup_event(&device->dev);
if (button->suspended)
break;
@@ -534,6 +534,7 @@ static int acpi_button_add(struct acpi_d
lid_device = device;
}
+ device_init_wakeup(&device->dev, true);
printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
return 0;
Index: linux-pm/drivers/acpi/battery.c
===================================================================
--- linux-pm.orig/drivers/acpi/battery.c
+++ linux-pm/drivers/acpi/battery.c
@@ -782,7 +782,7 @@ static int acpi_battery_update(struct ac
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_wakeup_event(&battery->device->dev);
return result;
}
Index: linux-pm/drivers/acpi/internal.h
===================================================================
--- linux-pm.orig/drivers/acpi/internal.h
+++ linux-pm/drivers/acpi/internal.h
@@ -198,8 +198,10 @@ void acpi_ec_remove_query_handler(struct
Suspend/Resume
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT
+extern bool acpi_s2idle_wakeup(void);
extern int acpi_sleep_init(void);
#else
+static inline bool acpi_s2idle_wakeup(void) { return false; }
static inline int acpi_sleep_init(void) { return -ENXIO; }
#endif
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -598,12 +598,16 @@ static inline bool acpi_device_always_pr
#endif
#ifdef CONFIG_PM
+void acpi_wakeup_event(struct device *dev);
acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
void (*func)(struct acpi_device_wakeup_context *context));
acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
int acpi_pm_device_sleep_state(struct device *, int *, int);
int acpi_pm_device_run_wake(struct device *, bool);
#else
+void acpi_wakeup_event(struct device *dev)
+{
+}
static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
struct device *dev,
void (*work_func)(struct work_struct *work))
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-08 02:20 +0200 |
| Subject | [PATCH 2/6] USB / PCI / PM: Allow the PCI core to do the resume cleanup |
| Message-ID | <tPTl9-5lN-61@gated-at.bofh.it> |
| In reply to | #1660587 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
hcd_pci_resume_noirq() used as a universal _resume_noirq handler for
PCI USB controllers calls pci_back_from_sleep() which is unnecessary
and may become problematic.
It is unnecessary, because the PCI bus type carries out post-suspend
cleanup of all PCI devices during resume and that covers all things
done by the pci_back_from_sleep(). There is no reason why USB cannot
follow all of the other PCI devices in that respect.
It will become problematic after subsequent changes that make it
possible to go back to sleep again after executing dpm_resume_noirq()
if no valid system wakeup events have been detected at that point.
Namely, calling pci_back_from_sleep() at the _resume_noirq stage
will cause the wakeup status of the devices in question to be cleared
and if any of them has triggered system wakeup, that event may be
missed then.
For the above reasons, drop the pci_back_from_sleep() invocation
from hcd_pci_resume_noirq().
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/usb/core/hcd-pci.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
Index: linux-pm/drivers/usb/core/hcd-pci.c
===================================================================
--- linux-pm.orig/drivers/usb/core/hcd-pci.c
+++ linux-pm/drivers/usb/core/hcd-pci.c
@@ -584,12 +584,7 @@ static int hcd_pci_suspend_noirq(struct
static int hcd_pci_resume_noirq(struct device *dev)
{
- struct pci_dev *pci_dev = to_pci_dev(dev);
-
- powermac_set_asic(pci_dev, 1);
-
- /* Go back to D0 and disable remote wakeup */
- pci_back_from_sleep(pci_dev);
+ powermac_set_asic(to_pci_dev(dev), 1);
return 0;
}
[toc] | [prev] | [next] | [standalone]
| From | Alan Stern <stern@rowland.harvard.edu> |
|---|---|
| Date | 2017-06-08 17:30 +0200 |
| Subject | Re: [PATCH 2/6] USB / PCI / PM: Allow the PCI core to do the resume cleanup |
| Message-ID | <tQ7xM-60p-7@gated-at.bofh.it> |
| In reply to | #1660615 |
On Thu, 8 Jun 2017, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> hcd_pci_resume_noirq() used as a universal _resume_noirq handler for
> PCI USB controllers calls pci_back_from_sleep() which is unnecessary
> and may become problematic.
>
> It is unnecessary, because the PCI bus type carries out post-suspend
> cleanup of all PCI devices during resume and that covers all things
> done by the pci_back_from_sleep(). There is no reason why USB cannot
> follow all of the other PCI devices in that respect.
>
> It will become problematic after subsequent changes that make it
> possible to go back to sleep again after executing dpm_resume_noirq()
> if no valid system wakeup events have been detected at that point.
> Namely, calling pci_back_from_sleep() at the _resume_noirq stage
> will cause the wakeup status of the devices in question to be cleared
> and if any of them has triggered system wakeup, that event may be
> missed then.
>
> For the above reasons, drop the pci_back_from_sleep() invocation
> from hcd_pci_resume_noirq().
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> drivers/usb/core/hcd-pci.c | 7 +------
> 1 file changed, 1 insertion(+), 6 deletions(-)
>
> Index: linux-pm/drivers/usb/core/hcd-pci.c
> ===================================================================
> --- linux-pm.orig/drivers/usb/core/hcd-pci.c
> +++ linux-pm/drivers/usb/core/hcd-pci.c
> @@ -584,12 +584,7 @@ static int hcd_pci_suspend_noirq(struct
>
> static int hcd_pci_resume_noirq(struct device *dev)
> {
> - struct pci_dev *pci_dev = to_pci_dev(dev);
> -
> - powermac_set_asic(pci_dev, 1);
> -
> - /* Go back to D0 and disable remote wakeup */
> - pci_back_from_sleep(pci_dev);
> + powermac_set_asic(to_pci_dev(dev), 1);
> return 0;
> }
Acked-by: Alan Stern <stern@rowland.harvard.edu>
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-09 01:10 +0200 |
| Subject | Re: [PATCH 2/6] USB / PCI / PM: Allow the PCI core to do the resume cleanup |
| Message-ID | <tQeIV-29h-3@gated-at.bofh.it> |
| In reply to | #1661374 |
On Thursday, June 08, 2017 11:24:55 AM Alan Stern wrote:
> On Thu, 8 Jun 2017, Rafael J. Wysocki wrote:
>
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >
> > hcd_pci_resume_noirq() used as a universal _resume_noirq handler for
> > PCI USB controllers calls pci_back_from_sleep() which is unnecessary
> > and may become problematic.
> >
> > It is unnecessary, because the PCI bus type carries out post-suspend
> > cleanup of all PCI devices during resume and that covers all things
> > done by the pci_back_from_sleep(). There is no reason why USB cannot
> > follow all of the other PCI devices in that respect.
> >
> > It will become problematic after subsequent changes that make it
> > possible to go back to sleep again after executing dpm_resume_noirq()
> > if no valid system wakeup events have been detected at that point.
> > Namely, calling pci_back_from_sleep() at the _resume_noirq stage
> > will cause the wakeup status of the devices in question to be cleared
> > and if any of them has triggered system wakeup, that event may be
> > missed then.
> >
> > For the above reasons, drop the pci_back_from_sleep() invocation
> > from hcd_pci_resume_noirq().
> >
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> > drivers/usb/core/hcd-pci.c | 7 +------
> > 1 file changed, 1 insertion(+), 6 deletions(-)
> >
> > Index: linux-pm/drivers/usb/core/hcd-pci.c
> > ===================================================================
> > --- linux-pm.orig/drivers/usb/core/hcd-pci.c
> > +++ linux-pm/drivers/usb/core/hcd-pci.c
> > @@ -584,12 +584,7 @@ static int hcd_pci_suspend_noirq(struct
> >
> > static int hcd_pci_resume_noirq(struct device *dev)
> > {
> > - struct pci_dev *pci_dev = to_pci_dev(dev);
> > -
> > - powermac_set_asic(pci_dev, 1);
> > -
> > - /* Go back to D0 and disable remote wakeup */
> > - pci_back_from_sleep(pci_dev);
> > + powermac_set_asic(to_pci_dev(dev), 1);
> > return 0;
> > }
>
> Acked-by: Alan Stern <stern@rowland.harvard.edu>
Thanks!
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-08 02:20 +0200 |
| Subject | [PATCH 4/6] ACPI / PM: Clean up device wakeup enable/disable code |
| Message-ID | <tPTl9-5lN-63@gated-at.bofh.it> |
| In reply to | #1660587 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The wakeup.flags.enabled flag in struct acpi_device is not used
consistently, as there is no reason why it should only apply
to the enabling/disabling of the wakeup GPE, so put the invocation
of acpi_enable_wakeup_device_power() under it too.
Moreover, it is not necessary to call
acpi_enable_wakeup_devices() and acpi_disable_wakeup_devices() for
suspend-to-idle, so don't do that.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/device_pm.c | 19 ++++++++-----------
drivers/acpi/sleep.c | 4 ++--
2 files changed, 10 insertions(+), 13 deletions(-)
Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -688,26 +688,23 @@ static int acpi_device_wakeup(struct acp
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;
}
Index: linux-pm/drivers/acpi/sleep.c
===================================================================
--- linux-pm.orig/drivers/acpi/sleep.c
+++ linux-pm/drivers/acpi/sleep.c
@@ -658,19 +658,19 @@ static int acpi_freeze_begin(void)
static int acpi_freeze_prepare(void)
{
- acpi_enable_wakeup_devices(ACPI_STATE_S0);
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_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();
}
[toc] | [prev] | [next] | [standalone]
| From | Hans de Goede <hdegoede@redhat.com> |
|---|---|
| Date | 2017-06-08 09:30 +0200 |
| Subject | Re: [PATCH 0/6] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups |
| Message-ID | <tQ03g-1dY-21@gated-at.bofh.it> |
| In reply to | #1660587 |
Hi,
On 08-06-17 02:00, Rafael J. Wysocki wrote:
> Hi All,
>
> This series is a replacement for commit eed4d47efe95 (ACPI / sleep: Ignore
> spurious SCI wakeups from suspend-to-idle) which is still there in 4.12-rc4 but
> will be reverted shortly, because it triggered issues on quite a few systems.
>
> The last patch in the series is a counterpart of the above commit with a few
> modifications, mostly to avoid affecting suspend-to-RAM and to reorder messages
> printed to kernel logs to make them somewhat less confusing.
>
> The previous patches are pre-requisite changes plus some cleanups. The major
> ones are [1-2/6] and [4/6] that are really needed for things to work as expected
> after [6/6].
>
> In addition to that, this patch from Hans: https://patchwork.kernel.org/patch/9762815/
> is needed for USB wakeup on Bay Trail and Cherry Trail systems to work in general.
Small correction, that patch currently only influences Cherry Trail devices, it has:
static const struct x86_cpu_id int0002_cpu_ids[] = {
/*
* Limit ourselves to Cherry Trail for now, until testing shows we
* need to handle the INT0002 device on Baytrail too.
* ICPU(INTEL_FAM6_ATOM_SILVERMONT1), * Valleyview, Bay Trail *
*/
ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */
{}
};
If anyone sees any issues where the SCI (typically irq 9) gets a nobody
cared message on Bay Trail try the linked patch with the Bay Trail line
above uncommented.
Regards,
Hans
[toc] | [prev] | [next] | [standalone]
| From | Dominik Brodowski <linux@dominikbrodowski.net> |
|---|---|
| Date | 2017-06-08 10:50 +0200 |
| Subject | Re: [PATCH 0/6] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups |
| Message-ID | <tQ1iG-1UD-3@gated-at.bofh.it> |
| In reply to | #1660587 |
[Multipart message — attachments visible in raw view] — view raw
Rafael, On Thu, Jun 08, 2017 at 02:00:40AM +0200, Rafael J. Wysocki wrote: > Hi All, > > This series is a replacement for commit eed4d47efe95 (ACPI / sleep: Ignore > spurious SCI wakeups from suspend-to-idle) which is still there in 4.12-rc4 but > will be reverted shortly, because it triggered issues on quite a few systems. > > The last patch in the series is a counterpart of the above commit with a few > modifications, mostly to avoid affecting suspend-to-RAM and to reorder messages > printed to kernel logs to make them somewhat less confusing. > > The previous patches are pre-requisite changes plus some cleanups. The major > ones are [1-2/6] and [4/6] that are really needed for things to work as expected > after [6/6]. > > In addition to that, this patch from Hans: https://patchwork.kernel.org/patch/9762815/ > is needed for USB wakeup on Bay Trail and Cherry Trail systems to work in general. with eed4d47efe95 reverted and this patch series applied, suspend-to-mem works as expected. Thanks! Dominik
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-08 14:10 +0200 |
| Message-ID | <tQ4qd-45j-3@gated-at.bofh.it> |
| In reply to | #1660944 |
On Thursday, June 08, 2017 10:42:02 AM Dominik Brodowski wrote: > Rafael, > > On Thu, Jun 08, 2017 at 02:00:40AM +0200, Rafael J. Wysocki wrote: > > Hi All, > > > > This series is a replacement for commit eed4d47efe95 (ACPI / sleep: Ignore > > spurious SCI wakeups from suspend-to-idle) which is still there in 4.12-rc4 but > > will be reverted shortly, because it triggered issues on quite a few systems. > > > > The last patch in the series is a counterpart of the above commit with a few > > modifications, mostly to avoid affecting suspend-to-RAM and to reorder messages > > printed to kernel logs to make them somewhat less confusing. > > > > The previous patches are pre-requisite changes plus some cleanups. The major > > ones are [1-2/6] and [4/6] that are really needed for things to work as expected > > after [6/6]. > > > > In addition to that, this patch from Hans: https://patchwork.kernel.org/patch/9762815/ > > is needed for USB wakeup on Bay Trail and Cherry Trail systems to work in general. > > with eed4d47efe95 reverted and this patch series applied, suspend-to-mem > works as expected. Thanks! Cool, thanks for the confirmation! Cheers, Rafael
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-12 23:10 +0200 |
| Subject | [PATCH v2 0/8] ACPI / PM: Suspend-to-idle rework to deal with spurious ACPI wakeups |
| Message-ID | <tREKZ-7pZ-1@gated-at.bofh.it> |
| In reply to | #1660587 |
Hi All, On Thursday, June 08, 2017 02:00:40 AM Rafael J. Wysocki wrote: > Hi All, > > This series is a replacement for commit eed4d47efe95 (ACPI / sleep: Ignore > spurious SCI wakeups from suspend-to-idle) which is still there in 4.12-rc4 but > will be reverted shortly, because it triggered issues on quite a few systems. > > The last patch in the series is a counterpart of the above commit with a few > modifications, mostly to avoid affecting suspend-to-RAM and to reorder messages > printed to kernel logs to make them somewhat less confusing. Here's a v2 which is very similar to the previous one, except for 3 things: - There are few build fixes in the last patch. - The patch from Hans mentioned previously is included now (as [7/8]). - There is an additional PCI change related to config space saving/restoring and PME. If anyone has any objections or concerns regarding this, please speak up now, as I'm going to put it into linux-next shortly to allow it to receive some more testing than commit eed4d47efe95 had had before it went it. Thanks, Rafael
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-12 23:10 +0200 |
| Subject | [PATCH v2 6/8] PCI / PM: Restore PME Enable if skipping wakeup setup |
| Message-ID | <tREKZ-7pZ-3@gated-at.bofh.it> |
| In reply to | #1664224 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The wakeup_prepared PCI device flag is used for preventing subsequent
changes of PCI device wakeup settings in the same way (e.g. enabling
device wakeup twice in a row).
However, in some cases PME Enable may be updated by things like PCI
configuration space restoration in the meantime and it may need to be
set again even though the rest of the settings need not change, so
modify __pci_enable_wake() to do that when it is about to return
early.
Also, it is reasonable to expect that __pci_enable_wake() will always
clear PME Status when invoked to disable device wakeup, so make it do
so even if it is going to return early then.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/pci.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
Index: linux-pm/drivers/pci/pci.c
===================================================================
--- linux-pm.orig/drivers/pci/pci.c
+++ linux-pm/drivers/pci/pci.c
@@ -1805,6 +1805,23 @@ static void __pci_pme_active(struct pci_
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.
@@ -1899,9 +1916,14 @@ int __pci_enable_wake(struct pci_dev *de
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
[toc] | [prev] | [next] | [standalone]
| From | Bjorn Helgaas <helgaas@kernel.org> |
|---|---|
| Date | 2017-06-14 20:20 +0200 |
| Subject | Re: [PATCH v2 6/8] PCI / PM: Restore PME Enable if skipping wakeup setup |
| Message-ID | <tSl3z-9p-3@gated-at.bofh.it> |
| In reply to | #1664225 |
On Mon, Jun 12, 2017 at 10:53:36PM +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> The wakeup_prepared PCI device flag is used for preventing subsequent
> changes of PCI device wakeup settings in the same way (e.g. enabling
> device wakeup twice in a row).
>
> However, in some cases PME Enable may be updated by things like PCI
> configuration space restoration in the meantime and it may need to be
> set again even though the rest of the settings need not change, so
> modify __pci_enable_wake() to do that when it is about to return
> early.
>
> Also, it is reasonable to expect that __pci_enable_wake() will always
> clear PME Status when invoked to disable device wakeup, so make it do
> so even if it is going to return early then.
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/pci/pci.c | 26 ++++++++++++++++++++++++--
> 1 file changed, 24 insertions(+), 2 deletions(-)
>
> Index: linux-pm/drivers/pci/pci.c
> ===================================================================
> --- linux-pm.orig/drivers/pci/pci.c
> +++ linux-pm/drivers/pci/pci.c
> @@ -1805,6 +1805,23 @@ static void __pci_pme_active(struct pci_
> 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.
> @@ -1899,9 +1916,14 @@ int __pci_enable_wake(struct pci_dev *de
> 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
>
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-12 23:10 +0200 |
| Subject | [PATCH v2 4/8] ACPI / PM: Clean up device wakeup enable/disable code |
| Message-ID | <tREL0-7pZ-9@gated-at.bofh.it> |
| In reply to | #1664224 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The wakeup.flags.enabled flag in struct acpi_device is not used
consistently, as there is no reason why it should only apply
to the enabling/disabling of the wakeup GPE, so put the invocation
of acpi_enable_wakeup_device_power() under it too.
Moreover, it is not necessary to call
acpi_enable_wakeup_devices() and acpi_disable_wakeup_devices() for
suspend-to-idle, so don't do that.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/device_pm.c | 19 ++++++++-----------
drivers/acpi/sleep.c | 4 ++--
2 files changed, 10 insertions(+), 13 deletions(-)
Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -688,26 +688,23 @@ static int acpi_device_wakeup(struct acp
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;
}
Index: linux-pm/drivers/acpi/sleep.c
===================================================================
--- linux-pm.orig/drivers/acpi/sleep.c
+++ linux-pm/drivers/acpi/sleep.c
@@ -658,19 +658,19 @@ static int acpi_freeze_begin(void)
static int acpi_freeze_prepare(void)
{
- acpi_enable_wakeup_devices(ACPI_STATE_S0);
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_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();
}
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-12 23:10 +0200 |
| Subject | [PATCH v2 5/8] PM / sleep: Print timing information if debug is enabled |
| Message-ID | <tREL0-7pZ-13@gated-at.bofh.it> |
| In reply to | #1664224 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Avoid printing the device suspend/resume timing information if
CONFIG_PM_DEBUG is not set to reduce the log noise level.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/base/power/main.c | 4 ++++
1 file changed, 4 insertions(+)
Index: linux-pm/drivers/base/power/main.c
===================================================================
--- linux-pm.orig/drivers/base/power/main.c
+++ linux-pm/drivers/base/power/main.c
@@ -417,6 +417,7 @@ static void pm_dev_err(struct device *de
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, char *info)
{
ktime_t calltime;
@@ -433,6 +434,9 @@ static void dpm_show_time(ktime_t startt
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, char *info) {}
+#endif /* CONFIG_PM_DEBUG */
static int dpm_run_callback(pm_callback_t cb, struct device *dev,
pm_message_t state, char *info)
[toc] | [prev] | [next] | [standalone]
| From | Joe Perches <joe@perches.com> |
|---|---|
| Date | 2017-06-13 00:20 +0200 |
| Subject | Re: [PATCH v2 5/8] PM / sleep: Print timing information if debug is enabled |
| Message-ID | <tRFQJ-83F-1@gated-at.bofh.it> |
| In reply to | #1664228 |
On Mon, 2017-06-12 at 22:51 +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> Avoid printing the device suspend/resume timing information if
> CONFIG_PM_DEBUG is not set to reduce the log noise level.
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> drivers/base/power/main.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> Index: linux-pm/drivers/base/power/main.c
> ===================================================================
> --- linux-pm.orig/drivers/base/power/main.c
> +++ linux-pm/drivers/base/power/main.c
> @@ -417,6 +417,7 @@ static void pm_dev_err(struct device *de
> 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, char *info)
> {
> ktime_t calltime;
> @@ -433,6 +434,9 @@ static void dpm_show_time(ktime_t startt
> 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, char *info) {}
> +#endif /* CONFIG_PM_DEBUG */
>
> static int dpm_run_callback(pm_callback_t cb, struct device *dev,
> pm_message_t state, char *info)
>
trivia:
This style of code can be reduced a few lines of code
using a single definition.
static type func(args...)
{
#ifdef CONFIG_<FOO>
[code ...]
#endif
}
and compilers will generate the same code for the
!defined CONFIG_<FOO> case.
This style can help avoid defects of updating one
function definition and not the other and only
compile testing the updated version.
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-12 23:10 +0200 |
| Subject | [PATCH v2 8/8] ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle |
| Message-ID | <tREL0-7pZ-23@gated-at.bofh.it> |
| In reply to | #1664224 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The ACPI SCI (System Control Interrupt) is set up as a wakeup IRQ
during suspend-to-idle transitions and, consequently, any events
signaled through it wake up the system from that state. However,
on some systems some of the events signaled via the ACPI SCI while
suspended to idle should not cause the system to wake up. In fact,
quite often they should just be discarded.
Arguably, systems should not resume entirely on such events, but in
order to decide which events really should cause the system to resume
and which are spurious, it is necessary to resume up to the point
when ACPI SCIs are actually handled and processed, which is after
executing dpm_resume_noirq() in the system resume path.
For this reasons, add a loop around freeze_enter() in which the
platforms can process events signaled via multiplexed IRQ lines
like the ACPI SCI and add suspend-to-idle hooks that can be
used for this purpose to struct platform_freeze_ops.
In the ACPI case, the ->wake hook is used for checking if the SCI
has triggered while suspended and deferring the interrupt-induced
system wakeup until the events signaled through it are actually
processed sufficiently to decide whether or not the system should
resume. In turn, the ->sync hook allows all of the relevant event
queues to be flushed so as to prevent events from being missed due
to race conditions.
In addition to that, some ACPI code processing wakeup events needs
to be modified to use the "hard" version of wakeup triggers, so that
it will cause a system resume to happen on device-induced wakeup
events even if the "soft" mechanism to prevent the system from
suspending is not enabled. However, to preserve the existing
behavior with respect to suspend-to-RAM, this only is done in
the suspend-to-idle case and only if an SCI has occurred while
suspended.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/battery.c | 2 +-
drivers/acpi/button.c | 5 +++--
drivers/acpi/device_pm.c | 9 ++++++++-
drivers/acpi/internal.h | 2 ++
drivers/acpi/sleep.c | 37 +++++++++++++++++++++++++++++++++++++
drivers/base/power/main.c | 5 -----
drivers/base/power/wakeup.c | 18 ++++++++++++------
include/acpi/acpi_bus.h | 6 +++++-
include/linux/suspend.h | 7 +++++--
kernel/power/process.c | 2 +-
kernel/power/suspend.c | 35 +++++++++++++++++++++++++++++------
11 files changed, 103 insertions(+), 25 deletions(-)
Index: linux-pm/include/linux/suspend.h
===================================================================
--- linux-pm.orig/include/linux/suspend.h
+++ linux-pm/include/linux/suspend.h
@@ -189,6 +189,8 @@ struct platform_suspend_ops {
struct platform_freeze_ops {
int (*begin)(void);
int (*prepare)(void);
+ void (*wake)(void);
+ void (*sync)(void);
void (*restore)(void);
void (*end)(void);
};
@@ -428,7 +430,8 @@ extern unsigned int pm_wakeup_irq;
extern bool pm_wakeup_pending(void);
extern void pm_system_wakeup(void);
-extern void pm_wakeup_clear(void);
+extern void pm_system_cancel_wakeup(void);
+extern void pm_wakeup_clear(bool reset);
extern void pm_system_irq_wakeup(unsigned int irq_number);
extern bool pm_get_wakeup_count(unsigned int *count, bool block);
extern bool pm_save_wakeup_count(unsigned int count);
@@ -478,7 +481,7 @@ static inline int unregister_pm_notifier
static inline bool pm_wakeup_pending(void) { return false; }
static inline void pm_system_wakeup(void) {}
-static inline void pm_wakeup_clear(void) {}
+static inline void pm_wakeup_clear(bool reset) {}
static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
static inline void lock_system_sleep(void) {}
Index: linux-pm/kernel/power/suspend.c
===================================================================
--- linux-pm.orig/kernel/power/suspend.c
+++ linux-pm/kernel/power/suspend.c
@@ -72,6 +72,8 @@ static void freeze_begin(void)
static void freeze_enter(void)
{
+ trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, true);
+
spin_lock_irq(&suspend_freeze_lock);
if (pm_wakeup_pending())
goto out;
@@ -84,11 +86,9 @@ static void freeze_enter(void)
/* Push all the CPUs into the idle loop. */
wake_up_all_idle_cpus();
- pr_debug("PM: suspend-to-idle\n");
/* 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);
- pr_debug("PM: resume from suspend-to-idle\n");
cpuidle_pause();
put_online_cpus();
@@ -98,6 +98,31 @@ static void freeze_enter(void)
out:
suspend_freeze_state = FREEZE_STATE_NONE;
spin_unlock_irq(&suspend_freeze_lock);
+
+ trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_FREEZE, false);
+}
+
+static void s2idle_loop(void)
+{
+ pr_debug("PM: suspend-to-idle\n");
+
+ do {
+ freeze_enter();
+
+ if (freeze_ops && freeze_ops->wake)
+ freeze_ops->wake();
+
+ dpm_resume_noirq(PMSG_RESUME);
+ if (freeze_ops && freeze_ops->sync)
+ freeze_ops->sync();
+
+ if (pm_wakeup_pending())
+ break;
+
+ pm_wakeup_clear(false);
+ } while (!dpm_suspend_noirq(PMSG_SUSPEND));
+
+ pr_debug("PM: resume from suspend-to-idle\n");
}
void freeze_wake(void)
@@ -371,10 +396,8 @@ static int suspend_enter(suspend_state_t
* all the devices are suspended.
*/
if (state == PM_SUSPEND_FREEZE) {
- trace_suspend_resume(TPS("machine_suspend"), state, true);
- freeze_enter();
- trace_suspend_resume(TPS("machine_suspend"), state, false);
- goto Platform_wake;
+ s2idle_loop();
+ goto Platform_early_resume;
}
error = disable_nonboot_cpus();
Index: linux-pm/drivers/base/power/main.c
===================================================================
--- linux-pm.orig/drivers/base/power/main.c
+++ linux-pm/drivers/base/power/main.c
@@ -1095,11 +1095,6 @@ static int __device_suspend_noirq(struct
if (async_error)
goto Complete;
- if (pm_wakeup_pending()) {
- async_error = -EBUSY;
- goto Complete;
- }
-
if (dev->power.syscore || dev->power.direct_complete)
goto Complete;
Index: linux-pm/drivers/base/power/wakeup.c
===================================================================
--- linux-pm.orig/drivers/base/power/wakeup.c
+++ linux-pm/drivers/base/power/wakeup.c
@@ -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.
@@ -855,20 +855,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)
Index: linux-pm/kernel/power/process.c
===================================================================
--- linux-pm.orig/kernel/power/process.c
+++ linux-pm/kernel/power/process.c
@@ -132,7 +132,7 @@ int freeze_processes(void)
if (!pm_freezing)
atomic_inc(&system_freezing_cnt);
- pm_wakeup_clear();
+ pm_wakeup_clear(true);
pr_info("Freezing user space processes ... ");
pm_freezing = true;
error = try_to_freeze_tasks(true);
Index: linux-pm/drivers/acpi/sleep.c
===================================================================
--- linux-pm.orig/drivers/acpi/sleep.c
+++ linux-pm/drivers/acpi/sleep.c
@@ -650,6 +650,8 @@ static const struct platform_suspend_ops
.recover = acpi_pm_finish,
};
+static bool s2idle_wakeup;
+
static int acpi_freeze_begin(void)
{
acpi_scan_lock_acquire();
@@ -666,6 +668,33 @@ static int acpi_freeze_prepare(void)
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)
{
if (acpi_sci_irq_valid())
@@ -682,6 +711,8 @@ static void acpi_freeze_end(void)
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,
};
@@ -700,9 +731,15 @@ static void acpi_sleep_suspend_setup(voi
}
#else /* !CONFIG_SUSPEND */
+#define s2idle_wakeup (false)
static inline void acpi_sleep_suspend_setup(void) {}
#endif /* !CONFIG_SUSPEND */
+bool acpi_s2idle_wakeup(void)
+{
+ return s2idle_wakeup;
+}
+
#ifdef CONFIG_PM_SLEEP
static u32 saved_bm_rld;
Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -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,7 +406,7 @@ static void acpi_pm_notify_handler(acpi_
mutex_lock(&acpi_pm_notifier_lock);
if (adev->wakeup.flags.notifier_present) {
- __pm_wakeup_event(adev->wakeup.ws, 0);
+ pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup());
if (adev->wakeup.context.func)
adev->wakeup.context.func(&adev->wakeup.context);
}
Index: linux-pm/drivers/acpi/button.c
===================================================================
--- linux-pm.orig/drivers/acpi/button.c
+++ linux-pm/drivers/acpi/button.c
@@ -217,7 +217,7 @@ static int acpi_lid_notify_state(struct
}
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 ac
} 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_d
lid_device = device;
}
+ device_init_wakeup(&device->dev, true);
printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
return 0;
Index: linux-pm/drivers/acpi/battery.c
===================================================================
--- linux-pm.orig/drivers/acpi/battery.c
+++ linux-pm/drivers/acpi/battery.c
@@ -782,7 +782,7 @@ static int acpi_battery_update(struct ac
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;
}
Index: linux-pm/drivers/acpi/internal.h
===================================================================
--- linux-pm.orig/drivers/acpi/internal.h
+++ linux-pm/drivers/acpi/internal.h
@@ -198,8 +198,10 @@ void acpi_ec_remove_query_handler(struct
Suspend/Resume
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT
+extern bool acpi_s2idle_wakeup(void);
extern int acpi_sleep_init(void);
#else
+static inline bool acpi_s2idle_wakeup(void) { return false; }
static inline int acpi_sleep_init(void) { return -ENXIO; }
#endif
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -598,15 +598,19 @@ static inline bool acpi_device_always_pr
#endif
#ifdef CONFIG_PM
+void acpi_pm_wakeup_event(struct device *dev);
acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
void (*func)(struct acpi_device_wakeup_context *context));
acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
int acpi_pm_device_sleep_state(struct device *, int *, int);
int acpi_pm_device_run_wake(struct device *, bool);
#else
+static inline void acpi_pm_wakeup_event(struct device *dev)
+{
+}
static inline 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))
{
return AE_SUPPORT;
}
[toc] | [prev] | [next] | [standalone]
| From | "Rafael J. Wysocki" <rjw@rjwysocki.net> |
|---|---|
| Date | 2017-06-12 23:10 +0200 |
| Subject | [PATCH v2 3/8] ACPI / PM: Change log level of wakeup-related message |
| Message-ID | <tREL0-7pZ-31@gated-at.bofh.it> |
| In reply to | #1664224 |
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Change the log level of the "System wakeup enabled/disabled by ACPI" message in acpi_pm_device_sleep_wake() to "debug" to reduce to log noise level. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> --- drivers/acpi/device_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) Index: linux-pm/drivers/acpi/device_pm.c =================================================================== --- linux-pm.orig/drivers/acpi/device_pm.c +++ linux-pm/drivers/acpi/device_pm.c @@ -756,8 +756,8 @@ int acpi_pm_device_sleep_wake(struct dev 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, "System wakeup %s by ACPI\n", + enable ? "enabled" : "disabled"); return error; }
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web