All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
@ 2014-07-19 20:36 Rafael J. Wysocki
  2014-07-19 20:37 ` [PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup Rafael J. Wysocki
                   ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-19 20:36 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

Hi,

As per the subject, this is to make ACPI-based PCI wakeup (such as WoL on some
systems among other things) work with the "freeze" sleep state.  For this
purpose ACPI wakeup GPEs need to be enabled for wakeup devices before
freeze_enter() is called and it is best to do that when configuring devices
for wakeup.

[1/2] Always enable wakeup GPEs when configuring devices for wakeup
[2/2] Rename one static function to avoid possible future confusion

Thanks!

-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup
  2014-07-19 20:36 [PATCH 0/2] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
@ 2014-07-19 20:37 ` Rafael J. Wysocki
  2014-07-20  7:17   ` [Update][PATCH " Rafael J. Wysocki
  2014-07-19 20:38 ` [PATCH 2/2] ACPI / PM: Rename acpi_wakeup_device() to acpi_device_pm_event() Rafael J. Wysocki
  2014-07-22  1:23 ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
  2 siblings, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-19 20:37 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Wakeup GPEs are currently only enabled when setting up devices for
remote wakeup at run time.  During system-wide transitions they are
enabled by ACPICA at the very last stage of suspend (before asking
the BIOS to take over).  Of course, that only works for system
sleep states supported by ACPI, so in particular it doesn't work
for the "freeze" sleep state.

For this reason, modify the ACPI core device PM code to enable wakeup
GPEs for devices when setting them up for wakeup regardless of whether
that is remote wakeup at runtime or system wakeup.  That allows the
same device wakeup setup routine to be used for both runtime PM and
system-wide PM and makes it possible to reduce code size quite a bit.

That should make things like ACPI-based PCI Wake-on-LAN work with
the "freeze" sleep state among other things.

Tested-on: Toshiba Portege R500
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/device_pm.c |   80 +++++++++++++++++++----------------------------
 include/acpi/acpi_bus.h  |   11 ------
 2 files changed, 34 insertions(+), 57 deletions(-)

Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -600,26 +600,10 @@ int acpi_pm_device_sleep_state(struct de
 }
 EXPORT_SYMBOL(acpi_pm_device_sleep_state);
 
-#ifdef CONFIG_PM_RUNTIME
-/**
- * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
- * @handle: ACPI handle of the device the notification is for.
- * @event: Type of the signaled event.
- * @context: Device corresponding to @handle.
- */
-static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
-{
-	struct device *dev = context;
-
-	if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
-		pm_wakeup_event(dev, 0);
-		pm_runtime_resume(dev);
-	}
-}
-
 /**
- * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device.
- * @adev: ACPI device to enable/disable the remote wakeup for.
+ * acpi_device_wakeup - Enable/disable wakeup functionality for device.
+ * @adev: ACPI device to enable/disable wakeup functionality for.
+ * @target_state: State the system is transitioning into.
  * @enable: Whether to enable or disable the wakeup functionality.
  *
  * Enable/disable the GPE associated with @adev so that it can generate
@@ -629,7 +613,8 @@ static void acpi_wakeup_device(acpi_hand
  * Callers must ensure that @adev is a valid ACPI device node before executing
  * this function.
  */
-int __acpi_device_run_wake(struct acpi_device *adev, bool enable)
+static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
+			      bool enable)
 {
 	struct acpi_device_wakeup *wakeup = &adev->wakeup;
 
@@ -637,7 +622,7 @@ int __acpi_device_run_wake(struct acpi_d
 		acpi_status res;
 		int error;
 
-		error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0);
+		error = acpi_enable_wakeup_device_power(adev, target_state);
 		if (error)
 			return error;
 
@@ -653,6 +638,24 @@ int __acpi_device_run_wake(struct acpi_d
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+/**
+ * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
+ * @handle: ACPI handle of the device the notification is for.
+ * @event: Type of the signaled event.
+ * @context: Device corresponding to @handle.
+ */
+static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
+{
+	struct device *dev = context;
+
+	if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
+		pm_wakeup_event(dev, 0);
+		if (acpi_target_system_state() == ACPI_STATE_S0)
+			pm_runtime_resume(dev);
+	}
+}
+
 /**
  * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
  * @dev: Device to enable/disable the platform to wake up.
@@ -673,7 +676,7 @@ int acpi_pm_device_run_wake(struct devic
 		return -ENODEV;
 	}
 
-	return __acpi_device_run_wake(adev, enable);
+	return acpi_device_wakeup(adev, enable, ACPI_STATE_S0);
 }
 EXPORT_SYMBOL(acpi_pm_device_run_wake);
 #else
@@ -683,20 +686,6 @@ static inline void acpi_wakeup_device(ac
 
 #ifdef CONFIG_PM_SLEEP
 /**
- * __acpi_device_sleep_wake - Enable or disable device to wake up the system.
- * @dev: Device to enable/desible to wake up the system.
- * @target_state: System state the device is supposed to wake up from.
- * @enable: Whether to enable or disable @dev to wake up the system.
- */
-int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state,
-			     bool enable)
-{
-	return enable ?
-		acpi_enable_wakeup_device_power(adev, target_state) :
-		acpi_disable_wakeup_device_power(adev);
-}
-
-/**
  * 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.
@@ -716,8 +705,7 @@ int acpi_pm_device_sleep_wake(struct dev
 		return -ENODEV;
 	}
 
-	error = __acpi_device_sleep_wake(adev, acpi_target_system_state(),
-					 enable);
+	error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
 	if (!error)
 		dev_info(dev, "System wakeup %s by ACPI\n",
 				enable ? "enabled" : "disabled");
@@ -775,13 +763,13 @@ int acpi_dev_runtime_suspend(struct devi
 
 	remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
 				PM_QOS_FLAGS_NONE;
-	error = __acpi_device_run_wake(adev, remote_wakeup);
+	error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup);
 	if (remote_wakeup && error)
 		return -EAGAIN;
 
 	error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
 	if (error)
-		__acpi_device_run_wake(adev, false);
+		acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 
 	return error;
 }
@@ -804,7 +792,7 @@ int acpi_dev_runtime_resume(struct devic
 		return 0;
 
 	error = acpi_dev_pm_full_power(adev);
-	__acpi_device_run_wake(adev, false);
+	acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 	return error;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
@@ -860,13 +848,13 @@ int acpi_dev_suspend_late(struct device
 
 	target_state = acpi_target_system_state();
 	wakeup = device_may_wakeup(dev);
-	error = __acpi_device_sleep_wake(adev, target_state, wakeup);
+	error = acpi_device_wakeup(adev, target_state, wakeup);
 	if (wakeup && error)
 		return error;
 
 	error = acpi_dev_pm_low_power(dev, adev, target_state);
 	if (error)
-		__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
+		acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
 
 	return error;
 }
@@ -889,7 +877,7 @@ int acpi_dev_resume_early(struct device
 		return 0;
 
 	error = acpi_dev_pm_full_power(adev);
-	__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
+	acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
 	return error;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
@@ -1052,7 +1040,7 @@ int acpi_dev_pm_attach(struct device *de
 	dev->pm_domain = &acpi_general_pm_domain;
 	if (power_on) {
 		acpi_dev_pm_full_power(adev);
-		__acpi_device_run_wake(adev, false);
+		acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 	}
 	return 0;
 }
@@ -1086,7 +1074,7 @@ void acpi_dev_pm_detach(struct device *d
 			 */
 			dev_pm_qos_hide_latency_limit(dev);
 			dev_pm_qos_hide_flags(dev);
-			__acpi_device_run_wake(adev, false);
+			acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 			acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
 		}
 	}
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -532,13 +532,8 @@ static inline int acpi_pm_device_sleep_s
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
-int __acpi_device_run_wake(struct acpi_device *, bool);
 int acpi_pm_device_run_wake(struct device *, bool);
 #else
-static inline int __acpi_device_run_wake(struct acpi_device *adev, bool en)
-{
-	return -ENODEV;
-}
 static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;
@@ -546,14 +541,8 @@ static inline int acpi_pm_device_run_wak
 #endif
 
 #ifdef CONFIG_PM_SLEEP
-int __acpi_device_sleep_wake(struct acpi_device *, u32, bool);
 int acpi_pm_device_sleep_wake(struct device *, bool);
 #else
-static inline int __acpi_device_sleep_wake(struct acpi_device *adev,
-					   u32 target_state, bool enable)
-{
-	return -ENODEV;
-}
 static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/2] ACPI / PM: Rename acpi_wakeup_device() to acpi_device_pm_event()
  2014-07-19 20:36 [PATCH 0/2] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
  2014-07-19 20:37 ` [PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup Rafael J. Wysocki
@ 2014-07-19 20:38 ` Rafael J. Wysocki
  2014-07-22  1:23 ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
  2 siblings, 0 replies; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-19 20:38 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

To avoid confusion with acpi_device_wakeup(), rename the default
ACPI device PM notify handler from acpi_wakeup_device() to
acpi_device_pm_event().

No functional changes.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/device_pm.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -640,12 +640,12 @@ static int acpi_device_wakeup(struct acp
 
 #ifdef CONFIG_PM_RUNTIME
 /**
- * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
+ * acpi_device_pm_event - Wakeup notification handler for ACPI devices.
  * @handle: ACPI handle of the device the notification is for.
  * @event: Type of the signaled event.
  * @context: Device corresponding to @handle.
  */
-static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
+static void acpi_device_pm_event(acpi_handle handle, u32 event, void *context)
 {
 	struct device *dev = context;
 
@@ -680,7 +680,7 @@ int acpi_pm_device_run_wake(struct devic
 }
 EXPORT_SYMBOL(acpi_pm_device_run_wake);
 #else
-static inline void acpi_wakeup_device(acpi_handle handle, u32 event,
+static inline void acpi_device_pm_event(acpi_handle handle, u32 event,
 				      void *context) {}
 #endif /* CONFIG_PM_RUNTIME */
 
@@ -1036,7 +1036,7 @@ int acpi_dev_pm_attach(struct device *de
 	if (dev->pm_domain)
 		return -EEXIST;
 
-	acpi_add_pm_notifier(adev, acpi_wakeup_device, dev);
+	acpi_add_pm_notifier(adev, acpi_device_pm_event, dev);
 	dev->pm_domain = &acpi_general_pm_domain;
 	if (power_on) {
 		acpi_dev_pm_full_power(adev);
@@ -1064,7 +1064,7 @@ void acpi_dev_pm_detach(struct device *d
 
 	if (adev && dev->pm_domain == &acpi_general_pm_domain) {
 		dev->pm_domain = NULL;
-		acpi_remove_pm_notifier(adev, acpi_wakeup_device);
+		acpi_remove_pm_notifier(adev, acpi_device_pm_event);
 		if (power_off) {
 			/*
 			 * If the device's PM QoS resume latency limit or flags


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Update][PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup
  2014-07-19 20:37 ` [PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup Rafael J. Wysocki
@ 2014-07-20  7:17   ` Rafael J. Wysocki
  2014-07-20 23:51     ` [Update 2x][PATCH " Rafael J. Wysocki
  0 siblings, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-20  7:17 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Wakeup GPEs are currently only enabled when setting up devices for
remote wakeup at run time.  During system-wide transitions they are
enabled by ACPICA at the very last stage of suspend (before asking
the BIOS to take over).  Of course, that only works for system
sleep states supported by ACPI, so in particular it doesn't work
for the "freeze" sleep state.

For this reason, modify the ACPI core device PM code to enable wakeup
GPEs for devices when setting them up for wakeup regardless of whether
that is remote wakeup at runtime or system wakeup.  That allows the
same device wakeup setup routine to be used for both runtime PM and
system-wide PM and makes it possible to reduce code size quite a bit.

That should make things like ACPI-based PCI Wake-on-LAN work with
the "freeze" sleep state among other things.

Tested-on: Toshiba Portege R500
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

The acpi_target_sleep_state() check in acpi_wakeup_device() would not cover
the "freeze" sleep state, so instead use pm_request_resume() for resuming
the device in there which defers the runtime resume until after system
suspend-resume is complete.

---
 drivers/acpi/device_pm.c |   83 ++++++++++++++++++++---------------------------
 include/acpi/acpi_bus.h  |   11 ------
 2 files changed, 37 insertions(+), 57 deletions(-)

Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -600,26 +600,10 @@ int acpi_pm_device_sleep_state(struct de
 }
 EXPORT_SYMBOL(acpi_pm_device_sleep_state);
 
-#ifdef CONFIG_PM_RUNTIME
-/**
- * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
- * @handle: ACPI handle of the device the notification is for.
- * @event: Type of the signaled event.
- * @context: Device corresponding to @handle.
- */
-static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
-{
-	struct device *dev = context;
-
-	if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
-		pm_wakeup_event(dev, 0);
-		pm_runtime_resume(dev);
-	}
-}
-
 /**
- * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device.
- * @adev: ACPI device to enable/disable the remote wakeup for.
+ * acpi_device_wakeup - Enable/disable wakeup functionality for device.
+ * @adev: ACPI device to enable/disable wakeup functionality for.
+ * @target_state: State the system is transitioning into.
  * @enable: Whether to enable or disable the wakeup functionality.
  *
  * Enable/disable the GPE associated with @adev so that it can generate
@@ -629,7 +613,8 @@ static void acpi_wakeup_device(acpi_hand
  * Callers must ensure that @adev is a valid ACPI device node before executing
  * this function.
  */
-int __acpi_device_run_wake(struct acpi_device *adev, bool enable)
+static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
+			      bool enable)
 {
 	struct acpi_device_wakeup *wakeup = &adev->wakeup;
 
@@ -637,7 +622,7 @@ int __acpi_device_run_wake(struct acpi_d
 		acpi_status res;
 		int error;
 
-		error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0);
+		error = acpi_enable_wakeup_device_power(adev, target_state);
 		if (error)
 			return error;
 
@@ -653,6 +638,27 @@ int __acpi_device_run_wake(struct acpi_d
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+/**
+ * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
+ * @handle: ACPI handle of the device the notification is for.
+ * @event: Type of the signaled event.
+ * @context: Device corresponding to @handle.
+ */
+static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
+{
+	struct device *dev = context;
+
+	if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
+		pm_wakeup_event(dev, 0);
+		/*
+		 * Use the PM workqueue to avoid running the runtime resume
+		 * callback during system suspend which may not be appropriate.
+		 */
+		pm_request_resume(dev);
+	}
+}
+
 /**
  * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
  * @dev: Device to enable/disable the platform to wake up.
@@ -673,7 +679,7 @@ int acpi_pm_device_run_wake(struct devic
 		return -ENODEV;
 	}
 
-	return __acpi_device_run_wake(adev, enable);
+	return acpi_device_wakeup(adev, enable, ACPI_STATE_S0);
 }
 EXPORT_SYMBOL(acpi_pm_device_run_wake);
 #else
@@ -683,20 +689,6 @@ static inline void acpi_wakeup_device(ac
 
 #ifdef CONFIG_PM_SLEEP
 /**
- * __acpi_device_sleep_wake - Enable or disable device to wake up the system.
- * @dev: Device to enable/desible to wake up the system.
- * @target_state: System state the device is supposed to wake up from.
- * @enable: Whether to enable or disable @dev to wake up the system.
- */
-int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state,
-			     bool enable)
-{
-	return enable ?
-		acpi_enable_wakeup_device_power(adev, target_state) :
-		acpi_disable_wakeup_device_power(adev);
-}
-
-/**
  * 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.
@@ -716,8 +708,7 @@ int acpi_pm_device_sleep_wake(struct dev
 		return -ENODEV;
 	}
 
-	error = __acpi_device_sleep_wake(adev, acpi_target_system_state(),
-					 enable);
+	error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
 	if (!error)
 		dev_info(dev, "System wakeup %s by ACPI\n",
 				enable ? "enabled" : "disabled");
@@ -775,13 +766,13 @@ int acpi_dev_runtime_suspend(struct devi
 
 	remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
 				PM_QOS_FLAGS_NONE;
-	error = __acpi_device_run_wake(adev, remote_wakeup);
+	error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup);
 	if (remote_wakeup && error)
 		return -EAGAIN;
 
 	error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
 	if (error)
-		__acpi_device_run_wake(adev, false);
+		acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 
 	return error;
 }
@@ -804,7 +795,7 @@ int acpi_dev_runtime_resume(struct devic
 		return 0;
 
 	error = acpi_dev_pm_full_power(adev);
-	__acpi_device_run_wake(adev, false);
+	acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 	return error;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
@@ -860,13 +851,13 @@ int acpi_dev_suspend_late(struct device
 
 	target_state = acpi_target_system_state();
 	wakeup = device_may_wakeup(dev);
-	error = __acpi_device_sleep_wake(adev, target_state, wakeup);
+	error = acpi_device_wakeup(adev, target_state, wakeup);
 	if (wakeup && error)
 		return error;
 
 	error = acpi_dev_pm_low_power(dev, adev, target_state);
 	if (error)
-		__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
+		acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
 
 	return error;
 }
@@ -889,7 +880,7 @@ int acpi_dev_resume_early(struct device
 		return 0;
 
 	error = acpi_dev_pm_full_power(adev);
-	__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
+	acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
 	return error;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
@@ -1052,7 +1043,7 @@ int acpi_dev_pm_attach(struct device *de
 	dev->pm_domain = &acpi_general_pm_domain;
 	if (power_on) {
 		acpi_dev_pm_full_power(adev);
-		__acpi_device_run_wake(adev, false);
+		acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 	}
 	return 0;
 }
@@ -1086,7 +1077,7 @@ void acpi_dev_pm_detach(struct device *d
 			 */
 			dev_pm_qos_hide_latency_limit(dev);
 			dev_pm_qos_hide_flags(dev);
-			__acpi_device_run_wake(adev, false);
+			acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 			acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
 		}
 	}
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -532,13 +532,8 @@ static inline int acpi_pm_device_sleep_s
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
-int __acpi_device_run_wake(struct acpi_device *, bool);
 int acpi_pm_device_run_wake(struct device *, bool);
 #else
-static inline int __acpi_device_run_wake(struct acpi_device *adev, bool en)
-{
-	return -ENODEV;
-}
 static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;
@@ -546,14 +541,8 @@ static inline int acpi_pm_device_run_wak
 #endif
 
 #ifdef CONFIG_PM_SLEEP
-int __acpi_device_sleep_wake(struct acpi_device *, u32, bool);
 int acpi_pm_device_sleep_wake(struct device *, bool);
 #else
-static inline int __acpi_device_sleep_wake(struct acpi_device *adev,
-					   u32 target_state, bool enable)
-{
-	return -ENODEV;
-}
 static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Update 2x][PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup
  2014-07-20  7:17   ` [Update][PATCH " Rafael J. Wysocki
@ 2014-07-20 23:51     ` Rafael J. Wysocki
  2014-07-21  8:17       ` Peter Zijlstra
  0 siblings, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-20 23:51 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Subject: ACPI / PM: Always enable wakeup GPEs when enabling device wakeup

Wakeup GPEs are currently only enabled when setting up devices for
remote wakeup at run time.  During system-wide transitions they are
enabled by ACPICA at the very last stage of suspend (before asking
the BIOS to take over).  Of course, that only works for system
sleep states supported by ACPI, so in particular it doesn't work
for the "freeze" sleep state.

For this reason, modify the ACPI core device PM code to enable wakeup
GPEs for devices when setting them up for wakeup regardless of whether
that is remote wakeup at runtime or system wakeup.  That allows the
same device wakeup setup routine to be used for both runtime PM and
system-wide PM and makes it possible to reduce code size quite a bit.

That should make things like ACPI-based PCI Wake-on-LAN work with
the "freeze" sleep state among other things.

Tested-on: Toshiba Portege R500
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

The PCI ACPI device PM notify handler has to be updated to avoid running
runtime resume callbacks during system suspend too.

---
 drivers/acpi/device_pm.c |   83 ++++++++++++++++++++---------------------------
 drivers/pci/pci-acpi.c   |   15 +++++---
 include/acpi/acpi_bus.h  |   11 ------
 3 files changed, 47 insertions(+), 62 deletions(-)

Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -600,26 +600,10 @@ int acpi_pm_device_sleep_state(struct de
 }
 EXPORT_SYMBOL(acpi_pm_device_sleep_state);
 
-#ifdef CONFIG_PM_RUNTIME
-/**
- * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
- * @handle: ACPI handle of the device the notification is for.
- * @event: Type of the signaled event.
- * @context: Device corresponding to @handle.
- */
-static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
-{
-	struct device *dev = context;
-
-	if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
-		pm_wakeup_event(dev, 0);
-		pm_runtime_resume(dev);
-	}
-}
-
 /**
- * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device.
- * @adev: ACPI device to enable/disable the remote wakeup for.
+ * acpi_device_wakeup - Enable/disable wakeup functionality for device.
+ * @adev: ACPI device to enable/disable wakeup functionality for.
+ * @target_state: State the system is transitioning into.
  * @enable: Whether to enable or disable the wakeup functionality.
  *
  * Enable/disable the GPE associated with @adev so that it can generate
@@ -629,7 +613,8 @@ static void acpi_wakeup_device(acpi_hand
  * Callers must ensure that @adev is a valid ACPI device node before executing
  * this function.
  */
-int __acpi_device_run_wake(struct acpi_device *adev, bool enable)
+static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
+			      bool enable)
 {
 	struct acpi_device_wakeup *wakeup = &adev->wakeup;
 
@@ -637,7 +622,7 @@ int __acpi_device_run_wake(struct acpi_d
 		acpi_status res;
 		int error;
 
-		error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0);
+		error = acpi_enable_wakeup_device_power(adev, target_state);
 		if (error)
 			return error;
 
@@ -653,6 +638,27 @@ int __acpi_device_run_wake(struct acpi_d
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+/**
+ * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
+ * @handle: ACPI handle of the device the notification is for.
+ * @event: Type of the signaled event.
+ * @context: Device corresponding to @handle.
+ */
+static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
+{
+	struct device *dev = context;
+
+	if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
+		pm_wakeup_event(dev, 0);
+		/*
+		 * Use the PM workqueue to avoid running the runtime resume
+		 * callback during system suspend which may not be appropriate.
+		 */
+		pm_request_resume(dev);
+	}
+}
+
 /**
  * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
  * @dev: Device to enable/disable the platform to wake up.
@@ -673,7 +679,7 @@ int acpi_pm_device_run_wake(struct devic
 		return -ENODEV;
 	}
 
-	return __acpi_device_run_wake(adev, enable);
+	return acpi_device_wakeup(adev, enable, ACPI_STATE_S0);
 }
 EXPORT_SYMBOL(acpi_pm_device_run_wake);
 #else
@@ -683,20 +689,6 @@ static inline void acpi_wakeup_device(ac
 
 #ifdef CONFIG_PM_SLEEP
 /**
- * __acpi_device_sleep_wake - Enable or disable device to wake up the system.
- * @dev: Device to enable/desible to wake up the system.
- * @target_state: System state the device is supposed to wake up from.
- * @enable: Whether to enable or disable @dev to wake up the system.
- */
-int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state,
-			     bool enable)
-{
-	return enable ?
-		acpi_enable_wakeup_device_power(adev, target_state) :
-		acpi_disable_wakeup_device_power(adev);
-}
-
-/**
  * 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.
@@ -716,8 +708,7 @@ int acpi_pm_device_sleep_wake(struct dev
 		return -ENODEV;
 	}
 
-	error = __acpi_device_sleep_wake(adev, acpi_target_system_state(),
-					 enable);
+	error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
 	if (!error)
 		dev_info(dev, "System wakeup %s by ACPI\n",
 				enable ? "enabled" : "disabled");
@@ -775,13 +766,13 @@ int acpi_dev_runtime_suspend(struct devi
 
 	remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
 				PM_QOS_FLAGS_NONE;
-	error = __acpi_device_run_wake(adev, remote_wakeup);
+	error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup);
 	if (remote_wakeup && error)
 		return -EAGAIN;
 
 	error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
 	if (error)
-		__acpi_device_run_wake(adev, false);
+		acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 
 	return error;
 }
@@ -804,7 +795,7 @@ int acpi_dev_runtime_resume(struct devic
 		return 0;
 
 	error = acpi_dev_pm_full_power(adev);
-	__acpi_device_run_wake(adev, false);
+	acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 	return error;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
@@ -860,13 +851,13 @@ int acpi_dev_suspend_late(struct device
 
 	target_state = acpi_target_system_state();
 	wakeup = device_may_wakeup(dev);
-	error = __acpi_device_sleep_wake(adev, target_state, wakeup);
+	error = acpi_device_wakeup(adev, target_state, wakeup);
 	if (wakeup && error)
 		return error;
 
 	error = acpi_dev_pm_low_power(dev, adev, target_state);
 	if (error)
-		__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
+		acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
 
 	return error;
 }
@@ -889,7 +880,7 @@ int acpi_dev_resume_early(struct device
 		return 0;
 
 	error = acpi_dev_pm_full_power(adev);
-	__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
+	acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
 	return error;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
@@ -1052,7 +1043,7 @@ int acpi_dev_pm_attach(struct device *de
 	dev->pm_domain = &acpi_general_pm_domain;
 	if (power_on) {
 		acpi_dev_pm_full_power(adev);
-		__acpi_device_run_wake(adev, false);
+		acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 	}
 	return 0;
 }
@@ -1086,7 +1077,7 @@ void acpi_dev_pm_detach(struct device *d
 			 */
 			dev_pm_qos_hide_latency_limit(dev);
 			dev_pm_qos_hide_flags(dev);
-			__acpi_device_run_wake(adev, false);
+			acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 			acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
 		}
 	}
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -532,13 +532,8 @@ static inline int acpi_pm_device_sleep_s
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
-int __acpi_device_run_wake(struct acpi_device *, bool);
 int acpi_pm_device_run_wake(struct device *, bool);
 #else
-static inline int __acpi_device_run_wake(struct acpi_device *adev, bool en)
-{
-	return -ENODEV;
-}
 static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;
@@ -546,14 +541,8 @@ static inline int acpi_pm_device_run_wak
 #endif
 
 #ifdef CONFIG_PM_SLEEP
-int __acpi_device_sleep_wake(struct acpi_device *, u32, bool);
 int acpi_pm_device_sleep_wake(struct device *, bool);
 #else
-static inline int __acpi_device_sleep_wake(struct acpi_device *adev,
-					   u32 target_state, bool enable)
-{
-	return -ENODEV;
-}
 static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;
Index: linux-pm/drivers/pci/pci-acpi.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-acpi.c
+++ linux-pm/drivers/pci/pci-acpi.c
@@ -47,9 +47,15 @@ static void pci_acpi_wake_dev(acpi_handl
 	if (pci_dev->pme_poll)
 		pci_dev->pme_poll = false;
 
+	pci_wakeup_event(pci_dev);
+	/*
+	 * Use the PM workqueue for resuming devices to avoid running runtime
+	 * resume callbacks during system suspend which may not be appropriate.
+	 * Bridges are an exception, because they are never suspended, so it is
+	 * not necessary to resume them here.
+	 */
 	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;
 	}
 
@@ -57,11 +63,10 @@ static void pci_acpi_wake_dev(acpi_handl
 	if (pci_dev->pme_support)
 		pci_check_pme_status(pci_dev);
 
-	pci_wakeup_event(pci_dev);
-	pm_runtime_resume(&pci_dev->dev);
-
 	if (pci_dev->subordinate)
 		pci_pme_wakeup_bus(pci_dev->subordinate);
+	else
+		pm_request_resume(&pci_dev->dev);
 }
 
 /**


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Update 2x][PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup
  2014-07-20 23:51     ` [Update 2x][PATCH " Rafael J. Wysocki
@ 2014-07-21  8:17       ` Peter Zijlstra
  2014-07-22  1:02         ` Rafael J. Wysocki
  0 siblings, 1 reply; 24+ messages in thread
From: Peter Zijlstra @ 2014-07-21  8:17 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Mon, Jul 21, 2014 at 01:51:46AM +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Subject: ACPI / PM: Always enable wakeup GPEs when enabling device wakeup
> 
> Wakeup GPEs are currently only enabled when setting up devices for
> remote wakeup at run time.  During system-wide transitions they are
> enabled by ACPICA at the very last stage of suspend (before asking
> the BIOS to take over).  Of course, that only works for system
> sleep states supported by ACPI, so in particular it doesn't work
> for the "freeze" sleep state.
> 
> For this reason, modify the ACPI core device PM code to enable wakeup
> GPEs for devices when setting them up for wakeup regardless of whether
> that is remote wakeup at runtime or system wakeup.  That allows the
> same device wakeup setup routine to be used for both runtime PM and
> system-wide PM and makes it possible to reduce code size quite a bit.
> 
> That should make things like ACPI-based PCI Wake-on-LAN work with
> the "freeze" sleep state among other things.
> 
> Tested-on: Toshiba Portege R500
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> 
> The PCI ACPI device PM notify handler has to be updated to avoid running
> runtime resume callbacks during system suspend too.

So I tested the first version, with that my WSM-EP didn't resume on WoL
and pressing the power button after the WoL had it crash and burn in the
igb driver.

Today I tested this latest version and WoL still didn't trigger a
resume, but the power button did make it go again, no crashes and I
suppose I can confirm the earlier patch that stopped making it go halt
works.

When I 'halt' I can wake the machine back up using a WoL so that all
_should_ work afaik.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Update 2x][PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup
  2014-07-21  8:17       ` Peter Zijlstra
@ 2014-07-22  1:02         ` Rafael J. Wysocki
  0 siblings, 0 replies; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22  1:02 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Monday, July 21, 2014 10:17:34 AM Peter Zijlstra wrote:
> On Mon, Jul 21, 2014 at 01:51:46AM +0200, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > Subject: ACPI / PM: Always enable wakeup GPEs when enabling device wakeup
> > 
> > Wakeup GPEs are currently only enabled when setting up devices for
> > remote wakeup at run time.  During system-wide transitions they are
> > enabled by ACPICA at the very last stage of suspend (before asking
> > the BIOS to take over).  Of course, that only works for system
> > sleep states supported by ACPI, so in particular it doesn't work
> > for the "freeze" sleep state.
> > 
> > For this reason, modify the ACPI core device PM code to enable wakeup
> > GPEs for devices when setting them up for wakeup regardless of whether
> > that is remote wakeup at runtime or system wakeup.  That allows the
> > same device wakeup setup routine to be used for both runtime PM and
> > system-wide PM and makes it possible to reduce code size quite a bit.
> > 
> > That should make things like ACPI-based PCI Wake-on-LAN work with
> > the "freeze" sleep state among other things.
> > 
> > Tested-on: Toshiba Portege R500
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> > 
> > The PCI ACPI device PM notify handler has to be updated to avoid running
> > runtime resume callbacks during system suspend too.
> 
> So I tested the first version, with that my WSM-EP didn't resume on WoL
> and pressing the power button after the WoL had it crash and burn in the
> igb driver.
> 
> Today I tested this latest version and WoL still didn't trigger a
> resume, but the power button did make it go again, no crashes and I
> suppose I can confirm the earlier patch that stopped making it go halt
> works.

OK, thanks!

> When I 'halt' I can wake the machine back up using a WoL so that all
> _should_ work afaik.

Yes, it should.

I'll send an updated patchset shortly, so please test that one.  If it
doesn't help, we'll need to dig deeper still.

Rafael


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-19 20:36 [PATCH 0/2] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
  2014-07-19 20:37 ` [PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup Rafael J. Wysocki
  2014-07-19 20:38 ` [PATCH 2/2] ACPI / PM: Rename acpi_wakeup_device() to acpi_device_pm_event() Rafael J. Wysocki
@ 2014-07-22  1:23 ` Rafael J. Wysocki
  2014-07-22  1:24   ` [PATCH 1/3] PM: Create PM workqueue if runtime PM is not configured too Rafael J. Wysocki
                     ` (3 more replies)
  2 siblings, 4 replies; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22  1:23 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

On Saturday, July 19, 2014 10:36:53 PM Rafael J. Wysocki wrote:
> Hi,
> 
> As per the subject, this is to make ACPI-based PCI wakeup (such as WoL on some
> systems among other things) work with the "freeze" sleep state.  For this
> purpose ACPI wakeup GPEs need to be enabled for wakeup devices before
> freeze_enter() is called and it is best to do that when configuring devices
> for wakeup.
> 
> [1/2] Always enable wakeup GPEs when configuring devices for wakeup
> [2/2] Rename one static function to avoid possible future confusion
> 
> Thanks!

That turned out to be more challenging than I had thought initially.

The last version I sent was almost OK, but it had some issues (like it could
walk the PCI hierarchy before resuming any PCI devices during system resume),
so a new version follows.  I did my best to avoid introducing any new problems
with it, but I obviously might overlook something.

It works for me and doesn't seem to break anything as far as I can say.

[1/3] Make PM workqueue available for CONFIG_PM_RUNTIME unset.
[2/3] Rework the handling of ACPI device wakeup notifications.
[3/3] Enable wakeup GPEs while setting up devices for wakeup during system
      suspend too.

Thanks!

-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/3] PM: Create PM workqueue if runtime PM is not configured too
  2014-07-22  1:23 ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
@ 2014-07-22  1:24   ` Rafael J. Wysocki
  2014-07-22  1:25   ` [PATCH 2/3] ACPI / PM: Revork the handling of ACPI device wakeup notifications Rafael J. Wysocki
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22  1:24 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

The PM workqueue is going to be used by ACPI PM notify handlers
regardless of whether or not runtime PM is configured, so move
it out of #ifdef CONFIG_PM_RUNTIME.

Do that in three places in the ACPI device PM code.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 include/linux/pm_runtime.h |   11 +++++++++--
 kernel/power/main.c        |    4 ----
 2 files changed, 9 insertions(+), 6 deletions(-)

Index: linux-pm/include/linux/pm_runtime.h
===================================================================
--- linux-pm.orig/include/linux/pm_runtime.h
+++ linux-pm/include/linux/pm_runtime.h
@@ -24,11 +24,20 @@
 #define RPM_AUTO		0x08	/* Use autosuspend_delay */
 
 #ifdef CONFIG_PM
+extern struct workqueue_struct *pm_wq;
+
+static inline bool queue_pm_work(struct work_struct *work)
+{
+	return queue_work(pm_wq, work);
+}
+
 extern int pm_generic_runtime_suspend(struct device *dev);
 extern int pm_generic_runtime_resume(struct device *dev);
 extern int pm_runtime_force_suspend(struct device *dev);
 extern int pm_runtime_force_resume(struct device *dev);
 #else
+static inline bool queue_pm_work(struct work_struct *work) { return false; }
+
 static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
 static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
@@ -37,8 +46,6 @@ static inline int pm_runtime_force_resum
 
 #ifdef CONFIG_PM_RUNTIME
 
-extern struct workqueue_struct *pm_wq;
-
 extern int __pm_runtime_idle(struct device *dev, int rpmflags);
 extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
 extern int __pm_runtime_resume(struct device *dev, int rpmflags);
Index: linux-pm/kernel/power/main.c
===================================================================
--- linux-pm.orig/kernel/power/main.c
+++ linux-pm/kernel/power/main.c
@@ -616,7 +616,6 @@ static struct attribute_group attr_group
 	.attrs = g,
 };
 
-#ifdef CONFIG_PM_RUNTIME
 struct workqueue_struct *pm_wq;
 EXPORT_SYMBOL_GPL(pm_wq);
 
@@ -626,9 +625,6 @@ static int __init pm_start_workqueue(voi
 
 	return pm_wq ? 0 : -ENOMEM;
 }
-#else
-static inline int pm_start_workqueue(void) { return 0; }
-#endif
 
 static int __init pm_init(void)
 {

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 2/3] ACPI / PM: Revork the handling of ACPI device wakeup notifications
  2014-07-22  1:23 ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
  2014-07-22  1:24   ` [PATCH 1/3] PM: Create PM workqueue if runtime PM is not configured too Rafael J. Wysocki
@ 2014-07-22  1:25   ` Rafael J. Wysocki
  2014-07-22 12:29     ` [Update][PATCH " Rafael J. Wysocki
  2014-07-22  1:26   ` [PATCH 3/3] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup Rafael J. Wysocki
  2014-07-22  8:55   ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Peter Zijlstra
  3 siblings, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22  1:25 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Since ACPI wakeup GPEs are going to be enabled during system suspend
as well as for runtime wakeup by a subsequent patch and the same
notify handlers will be used in both cases, rework the ACPI device
wakeup notification framework so that the part specific to physical
devices is always run asynchronously from the PM workqueue.  This
prevents runtime resume callbacks for those devices from being
run during system suspend and resume which may not be appropriate,
among other things.

Also make ACPI device wakeup notification handling a bit more robust
agaist subsequent removal of ACPI device objects, whould that ever
happen, and create a wakeup source object for each ACPI device
configured for wakeup so that wakeup notifications for those
devices can wake up the system from the "freeze" sleep state.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/device_pm.c |   74 +++++++++++++++++++++++++++++++++--------------
 drivers/acpi/pci_root.c  |    2 -
 drivers/pci/pci-acpi.c   |   60 ++++++++++++--------------------------
 include/acpi/acpi_bus.h  |   21 ++++++++-----
 include/linux/pci-acpi.h |   13 +++++---
 5 files changed, 95 insertions(+), 75 deletions(-)

Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -315,12 +315,19 @@ struct acpi_device_wakeup_flags {
 	u8 notifier_present:1;  /* Wake-up notify handler has been installed */
 };
 
+struct acpi_device_wakeup_context {
+	struct work_struct work;
+	struct device *dev;
+};
+
 struct acpi_device_wakeup {
 	acpi_handle gpe_device;
 	u64 gpe_number;
 	u64 sleep_state;
 	struct list_head resources;
 	struct acpi_device_wakeup_flags flags;
+	struct acpi_device_wakeup_context context;
+	struct wakeup_source *ws;
 	int prepare_count;
 };
 
@@ -504,20 +511,18 @@ int acpi_enable_wakeup_device_power(stru
 int acpi_disable_wakeup_device_power(struct acpi_device *dev);
 
 #ifdef CONFIG_PM
-acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-				 acpi_notify_handler handler, void *context);
-acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-				    acpi_notify_handler handler);
+acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
+				 void (*work_func)(struct work_struct *work));
+acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
 int acpi_pm_device_sleep_state(struct device *, int *, int);
 #else
 static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-					       acpi_notify_handler handler,
-					       void *context)
+					       struct device *dev,
+				               void (*work_func)(struct work_struct *work))
 {
 	return AE_SUPPORT;
 }
-static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-						  acpi_notify_handler handler)
+static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
 {
 	return AE_SUPPORT;
 }
Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -367,29 +367,55 @@ EXPORT_SYMBOL(acpi_bus_power_manageable)
 #ifdef CONFIG_PM
 static DEFINE_MUTEX(acpi_pm_notifier_lock);
 
+static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
+{
+	struct acpi_device *adev;
+
+	if (val != ACPI_NOTIFY_DEVICE_WAKE)
+		return;
+
+	adev = acpi_bus_get_acpi_device(handle);
+	if (!adev)
+		return;
+
+	__pm_wakeup_event(adev->wakeup.ws, 0);
+	if (adev->wakeup.context.work.func)
+		queue_pm_work(&adev->wakeup.context.work);
+
+	acpi_bus_put_acpi_device(adev);
+}
+
 /**
- * acpi_add_pm_notifier - Register PM notifier for given ACPI device.
- * @adev: ACPI device to add the notifier for.
- * @context: Context information to pass to the notifier routine.
+ * 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.
  *
  * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
  * PM wakeup events.  For example, wakeup events may be generated for bridges
  * if one of the devices below the bridge is signaling wakeup, even if the
  * bridge itself doesn't have a wakeup GPE associated with it.
  */
-acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-				 acpi_notify_handler handler, void *context)
+acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
+				 void (*work_func)(struct work_struct *work))
 {
 	acpi_status status = AE_ALREADY_EXISTS;
 
+	if (!dev && !work_func)
+		return AE_BAD_PARAMETER;
+
 	mutex_lock(&acpi_pm_notifier_lock);
 
 	if (adev->wakeup.flags.notifier_present)
 		goto out;
 
-	status = acpi_install_notify_handler(adev->handle,
-					     ACPI_SYSTEM_NOTIFY,
-					     handler, context);
+	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);
+
+	status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY,
+					     acpi_pm_notify_handler, NULL);
 	if (ACPI_FAILURE(status))
 		goto out;
 
@@ -404,8 +430,7 @@ acpi_status acpi_add_pm_notifier(struct
  * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device.
  * @adev: ACPI device to remove the notifier from.
  */
-acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-				    acpi_notify_handler handler)
+acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
 {
 	acpi_status status = AE_BAD_PARAMETER;
 
@@ -416,10 +441,17 @@ acpi_status acpi_remove_pm_notifier(stru
 
 	status = acpi_remove_notify_handler(adev->handle,
 					    ACPI_SYSTEM_NOTIFY,
-					    handler);
+					    acpi_pm_notify_handler);
 	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.dev = NULL;
+	wakeup_source_unregister(adev->wakeup.ws);
+
 	adev->wakeup.flags.notifier_present = false;
 
  out:
@@ -602,16 +634,15 @@ EXPORT_SYMBOL(acpi_pm_device_sleep_state
 
 #ifdef CONFIG_PM_RUNTIME
 /**
- * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
- * @handle: ACPI handle of the device the notification is for.
- * @event: Type of the signaled event.
- * @context: Device corresponding to @handle.
+ * acpi_pm_notify_work_func - ACPI devices wakeup notification work function.
+ * @work: Work item to handle.
  */
-static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
+static void acpi_pm_notify_work_func(struct work_struct *work)
 {
-	struct device *dev = context;
+	struct device *dev;
 
-	if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
+	dev = container_of(work, struct acpi_device_wakeup_context, work)->dev;
+	if (dev) {
 		pm_wakeup_event(dev, 0);
 		pm_runtime_resume(dev);
 	}
@@ -677,8 +708,7 @@ int acpi_pm_device_run_wake(struct devic
 }
 EXPORT_SYMBOL(acpi_pm_device_run_wake);
 #else
-static inline void acpi_wakeup_device(acpi_handle handle, u32 event,
-				      void *context) {}
+static inline void acpi_pm_notify_work_func(struct work_struct *work) {}
 #endif /* CONFIG_PM_RUNTIME */
 
 #ifdef CONFIG_PM_SLEEP
@@ -1048,7 +1078,7 @@ int acpi_dev_pm_attach(struct device *de
 	if (dev->pm_domain)
 		return -EEXIST;
 
-	acpi_add_pm_notifier(adev, acpi_wakeup_device, dev);
+	acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func);
 	dev->pm_domain = &acpi_general_pm_domain;
 	if (power_on) {
 		acpi_dev_pm_full_power(adev);
@@ -1076,7 +1106,7 @@ void acpi_dev_pm_detach(struct device *d
 
 	if (adev && dev->pm_domain == &acpi_general_pm_domain) {
 		dev->pm_domain = NULL;
-		acpi_remove_pm_notifier(adev, acpi_wakeup_device);
+		acpi_remove_pm_notifier(adev);
 		if (power_off) {
 			/*
 			 * If the device's PM QoS resume latency limit or flags
Index: linux-pm/drivers/pci/pci-acpi.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-acpi.c
+++ linux-pm/drivers/pci/pci-acpi.c
@@ -18,31 +18,31 @@
 #include "pci.h"
 
 /**
- * pci_acpi_wake_bus - Wake-up notification handler for root buses.
- * @handle: ACPI handle of a device the notification is for.
- * @event: Type of the signaled event.
- * @context: PCI root bus to wake up devices on.
+ * pci_acpi_wake_bus - Root bus wakeup notification fork function.
+ * @work: Work item to handle.
  */
-static void pci_acpi_wake_bus(acpi_handle handle, u32 event, void *context)
+static void pci_acpi_wake_bus(struct work_struct *work)
 {
-	struct pci_bus *pci_bus = context;
+	struct acpi_device *adev;
+	struct acpi_pci_root *root;
 
-	if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_bus)
-		pci_pme_wakeup_bus(pci_bus);
+	adev = container_of(work, struct acpi_device, wakeup.context.work);
+	root = acpi_driver_data(adev);
+	pci_pme_wakeup_bus(root->bus);
 }
 
 /**
- * pci_acpi_wake_dev - Wake-up notification handler for PCI devices.
+ * pci_acpi_wake_dev - PCI device wakeup notification work function.
  * @handle: ACPI handle of a device the notification is for.
- * @event: Type of the signaled event.
- * @context: PCI device object to wake up.
+ * @work: Work item to handle.
  */
-static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
+static void pci_acpi_wake_dev(struct work_struct *work)
 {
-	struct pci_dev *pci_dev = context;
+	struct acpi_device_wakeup_context *context;
+	struct pci_dev *pci_dev;
 
-	if (event != ACPI_NOTIFY_DEVICE_WAKE || !pci_dev)
-		return;
+	context = container_of(work, struct acpi_device_wakeup_context, work);
+	pci_dev = to_pci_dev(context->dev);
 
 	if (pci_dev->pme_poll)
 		pci_dev->pme_poll = false;
@@ -65,23 +65,12 @@ static void pci_acpi_wake_dev(acpi_handl
 }
 
 /**
- * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus.
- * @dev: ACPI device to add the notifier for.
- * @pci_bus: PCI bus to walk checking for PME status if an event is signaled.
+ * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus.
+ * @dev: PCI root bridge ACPI device.
  */
-acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev,
-					 struct pci_bus *pci_bus)
+acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev)
 {
-	return acpi_add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus);
-}
-
-/**
- * pci_acpi_remove_bus_pm_notifier - Unregister PCI bus PM notifier.
- * @dev: ACPI device to remove the notifier from.
- */
-acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
-{
-	return acpi_remove_pm_notifier(dev, pci_acpi_wake_bus);
+	return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus);
 }
 
 /**
@@ -92,16 +81,7 @@ acpi_status pci_acpi_remove_bus_pm_notif
 acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
 				     struct pci_dev *pci_dev)
 {
-	return acpi_add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev);
-}
-
-/**
- * pci_acpi_remove_pm_notifier - Unregister PCI device PM notifier.
- * @dev: ACPI device to remove the notifier from.
- */
-acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
-{
-	return acpi_remove_pm_notifier(dev, pci_acpi_wake_dev);
+	return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
 }
 
 phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
Index: linux-pm/include/linux/pci-acpi.h
===================================================================
--- linux-pm.orig/include/linux/pci-acpi.h
+++ linux-pm/include/linux/pci-acpi.h
@@ -11,12 +11,17 @@
 #include <linux/acpi.h>
 
 #ifdef CONFIG_ACPI
-extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev,
-						 struct pci_bus *pci_bus);
-extern acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev);
+extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev);
+static inline acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
+{
+	return acpi_remove_pm_notifier(dev);
+}
 extern acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
 					     struct pci_dev *pci_dev);
-extern acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev);
+static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
+{
+	return acpi_remove_pm_notifier(dev);
+}
 extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
 
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
Index: linux-pm/drivers/acpi/pci_root.c
===================================================================
--- linux-pm.orig/drivers/acpi/pci_root.c
+++ linux-pm/drivers/acpi/pci_root.c
@@ -593,7 +593,7 @@ static int acpi_pci_root_add(struct acpi
 	if (no_aspm)
 		pcie_no_aspm();
 
-	pci_acpi_add_bus_pm_notifier(device, root->bus);
+	pci_acpi_add_bus_pm_notifier(device);
 	if (device->wakeup.flags.run_wake)
 		device_set_run_wake(root->bus->bridge, true);
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 3/3] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup
  2014-07-22  1:23 ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
  2014-07-22  1:24   ` [PATCH 1/3] PM: Create PM workqueue if runtime PM is not configured too Rafael J. Wysocki
  2014-07-22  1:25   ` [PATCH 2/3] ACPI / PM: Revork the handling of ACPI device wakeup notifications Rafael J. Wysocki
@ 2014-07-22  1:26   ` Rafael J. Wysocki
  2014-07-22  8:55   ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Peter Zijlstra
  3 siblings, 0 replies; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22  1:26 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Wakeup GPEs are currently only enabled when setting up devices for
remote wakeup at run time.  During system-wide transitions they are
enabled by ACPICA at the very last stage of suspend (before asking
the BIOS to take over).  Of course, that only works for system
sleep states supported by ACPI, so in particular it doesn't work
for the "freeze" sleep state.

For this reason, modify the ACPI core device PM code to enable wakeup
GPEs for devices when setting them up for wakeup regardless of whether
that is remote wakeup at runtime or system wakeup.  That allows the
same device wakeup setup routine to be used for both runtime PM and
system-wide PM and makes it possible to reduce code size quite a bit.

This make ACPI-based PCI Wake-on-LAN work with the "freeze" sleep
state on my venerable Toshiba Portege R500 and should help other
systems too.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/device_pm.c |   49 ++++++++++++++++-------------------------------
 include/acpi/acpi_bus.h  |   11 ----------
 2 files changed, 17 insertions(+), 43 deletions(-)

Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -632,7 +632,6 @@ int acpi_pm_device_sleep_state(struct de
 }
 EXPORT_SYMBOL(acpi_pm_device_sleep_state);
 
-#ifdef CONFIG_PM_RUNTIME
 /**
  * acpi_pm_notify_work_func - ACPI devices wakeup notification work function.
  * @work: Work item to handle.
@@ -649,8 +648,9 @@ static void acpi_pm_notify_work_func(str
 }
 
 /**
- * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device.
- * @adev: ACPI device to enable/disable the remote wakeup for.
+ * acpi_device_wakeup - Enable/disable wakeup functionality for device.
+ * @adev: ACPI device to enable/disable wakeup functionality for.
+ * @target_state: State the system is transitioning into.
  * @enable: Whether to enable or disable the wakeup functionality.
  *
  * Enable/disable the GPE associated with @adev so that it can generate
@@ -660,7 +660,8 @@ static void acpi_pm_notify_work_func(str
  * Callers must ensure that @adev is a valid ACPI device node before executing
  * this function.
  */
-int __acpi_device_run_wake(struct acpi_device *adev, bool enable)
+static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
+			      bool enable)
 {
 	struct acpi_device_wakeup *wakeup = &adev->wakeup;
 
@@ -668,7 +669,7 @@ int __acpi_device_run_wake(struct acpi_d
 		acpi_status res;
 		int error;
 
-		error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0);
+		error = acpi_enable_wakeup_device_power(adev, target_state);
 		if (error)
 			return error;
 
@@ -684,6 +685,7 @@ int __acpi_device_run_wake(struct acpi_d
 	return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
 /**
  * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
  * @dev: Device to enable/disable the platform to wake up.
@@ -704,29 +706,13 @@ int acpi_pm_device_run_wake(struct devic
 		return -ENODEV;
 	}
 
-	return __acpi_device_run_wake(adev, enable);
+	return acpi_device_wakeup(adev, enable, ACPI_STATE_S0);
 }
 EXPORT_SYMBOL(acpi_pm_device_run_wake);
-#else
-static inline void acpi_pm_notify_work_func(struct work_struct *work) {}
 #endif /* CONFIG_PM_RUNTIME */
 
 #ifdef CONFIG_PM_SLEEP
 /**
- * __acpi_device_sleep_wake - Enable or disable device to wake up the system.
- * @dev: Device to enable/desible to wake up the system.
- * @target_state: System state the device is supposed to wake up from.
- * @enable: Whether to enable or disable @dev to wake up the system.
- */
-int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state,
-			     bool enable)
-{
-	return enable ?
-		acpi_enable_wakeup_device_power(adev, target_state) :
-		acpi_disable_wakeup_device_power(adev);
-}
-
-/**
  * 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.
@@ -746,8 +732,7 @@ int acpi_pm_device_sleep_wake(struct dev
 		return -ENODEV;
 	}
 
-	error = __acpi_device_sleep_wake(adev, acpi_target_system_state(),
-					 enable);
+	error = acpi_device_wakeup(adev, acpi_target_system_state(), enable);
 	if (!error)
 		dev_info(dev, "System wakeup %s by ACPI\n",
 				enable ? "enabled" : "disabled");
@@ -805,13 +790,13 @@ int acpi_dev_runtime_suspend(struct devi
 
 	remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
 				PM_QOS_FLAGS_NONE;
-	error = __acpi_device_run_wake(adev, remote_wakeup);
+	error = acpi_device_wakeup(adev, ACPI_STATE_S0, remote_wakeup);
 	if (remote_wakeup && error)
 		return -EAGAIN;
 
 	error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
 	if (error)
-		__acpi_device_run_wake(adev, false);
+		acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 
 	return error;
 }
@@ -834,7 +819,7 @@ int acpi_dev_runtime_resume(struct devic
 		return 0;
 
 	error = acpi_dev_pm_full_power(adev);
-	__acpi_device_run_wake(adev, false);
+	acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 	return error;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
@@ -890,13 +875,13 @@ int acpi_dev_suspend_late(struct device
 
 	target_state = acpi_target_system_state();
 	wakeup = device_may_wakeup(dev);
-	error = __acpi_device_sleep_wake(adev, target_state, wakeup);
+	error = acpi_device_wakeup(adev, target_state, wakeup);
 	if (wakeup && error)
 		return error;
 
 	error = acpi_dev_pm_low_power(dev, adev, target_state);
 	if (error)
-		__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
+		acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
 
 	return error;
 }
@@ -919,7 +904,7 @@ int acpi_dev_resume_early(struct device
 		return 0;
 
 	error = acpi_dev_pm_full_power(adev);
-	__acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
+	acpi_device_wakeup(adev, ACPI_STATE_UNKNOWN, false);
 	return error;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
@@ -1082,7 +1067,7 @@ int acpi_dev_pm_attach(struct device *de
 	dev->pm_domain = &acpi_general_pm_domain;
 	if (power_on) {
 		acpi_dev_pm_full_power(adev);
-		__acpi_device_run_wake(adev, false);
+		acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 	}
 	return 0;
 }
@@ -1116,7 +1101,7 @@ void acpi_dev_pm_detach(struct device *d
 			 */
 			dev_pm_qos_hide_latency_limit(dev);
 			dev_pm_qos_hide_flags(dev);
-			__acpi_device_run_wake(adev, false);
+			acpi_device_wakeup(adev, ACPI_STATE_S0, false);
 			acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
 		}
 	}
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -537,13 +537,8 @@ static inline int acpi_pm_device_sleep_s
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
-int __acpi_device_run_wake(struct acpi_device *, bool);
 int acpi_pm_device_run_wake(struct device *, bool);
 #else
-static inline int __acpi_device_run_wake(struct acpi_device *adev, bool en)
-{
-	return -ENODEV;
-}
 static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;
@@ -551,14 +546,8 @@ static inline int acpi_pm_device_run_wak
 #endif
 
 #ifdef CONFIG_PM_SLEEP
-int __acpi_device_sleep_wake(struct acpi_device *, u32, bool);
 int acpi_pm_device_sleep_wake(struct device *, bool);
 #else
-static inline int __acpi_device_sleep_wake(struct acpi_device *adev,
-					   u32 target_state, bool enable)
-{
-	return -ENODEV;
-}
 static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
 {
 	return -ENODEV;

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-22  1:23 ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
                     ` (2 preceding siblings ...)
  2014-07-22  1:26   ` [PATCH 3/3] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup Rafael J. Wysocki
@ 2014-07-22  8:55   ` Peter Zijlstra
  2014-07-22  9:42     ` Peter Zijlstra
  2014-07-22 12:23     ` Rafael J. Wysocki
  3 siblings, 2 replies; 24+ messages in thread
From: Peter Zijlstra @ 2014-07-22  8:55 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Tue, Jul 22, 2014 at 03:23:29AM +0200, Rafael J. Wysocki wrote:

> That turned out to be more challenging than I had thought initially.
> 
> The last version I sent was almost OK, but it had some issues (like it could
> walk the PCI hierarchy before resuming any PCI devices during system resume),
> so a new version follows.  I did my best to avoid introducing any new problems
> with it, but I obviously might overlook something.
> 
> It works for me and doesn't seem to break anything as far as I can say.
> 
> [1/3] Make PM workqueue available for CONFIG_PM_RUNTIME unset.
> [2/3] Rework the handling of ACPI device wakeup notifications.
> [3/3] Enable wakeup GPEs while setting up devices for wakeup during system
>       suspend too.

Doesn't break, doesn't 'work' either. Is there anything I can provide
you with to make this easier? lspci output or anything like that?

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-22  8:55   ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Peter Zijlstra
@ 2014-07-22  9:42     ` Peter Zijlstra
  2014-07-22 12:23     ` Rafael J. Wysocki
  1 sibling, 0 replies; 24+ messages in thread
From: Peter Zijlstra @ 2014-07-22  9:42 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Tue, Jul 22, 2014 at 10:55:38AM +0200, Peter Zijlstra wrote:
> On Tue, Jul 22, 2014 at 03:23:29AM +0200, Rafael J. Wysocki wrote:
> 
> > That turned out to be more challenging than I had thought initially.
> > 
> > The last version I sent was almost OK, but it had some issues (like it could
> > walk the PCI hierarchy before resuming any PCI devices during system resume),
> > so a new version follows.  I did my best to avoid introducing any new problems
> > with it, but I obviously might overlook something.
> > 
> > It works for me and doesn't seem to break anything as far as I can say.
> > 
> > [1/3] Make PM workqueue available for CONFIG_PM_RUNTIME unset.
> > [2/3] Rework the handling of ACPI device wakeup notifications.
> > [3/3] Enable wakeup GPEs while setting up devices for wakeup during system
> >       suspend too.
> 
> Doesn't break, doesn't 'work' either. Is there anything I can provide
> you with to make this easier? lspci output or anything like that?

Also, I'm more than willing to get you early_printk() or ftrace logs for
this. Except of course that early_printk() seems to not work throughout
the freeze cycle as I've already reported.

But given that I can wake the machine with the power button, I can get
you trace logs.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-22 12:23     ` Rafael J. Wysocki
@ 2014-07-22 12:13       ` Peter Zijlstra
  2014-07-22 22:26         ` Rafael J. Wysocki
  0 siblings, 1 reply; 24+ messages in thread
From: Peter Zijlstra @ 2014-07-22 12:13 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Tue, Jul 22, 2014 at 02:23:03PM +0200, Rafael J. Wysocki wrote:
> > Doesn't break, doesn't 'work' either.
> 
> This probably means that WoL on that machine is not ACPI-based.

Oh lovely, of course that's an 'option' !

> > Is there anything I can provide you with to make this easier? lspci output
> > or anything like that?
> 
> Yes, /proc/interrupts from the machine in question would help to start with.

Be sure to get a _wide_ terminal when viewing ;-)

            CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       CPU8       CPU9       CPU10      CPU11      CPU12      CPU13      CPU14      CPU15      CPU16      CPU17      CPU18      CPU19      CPU20      CPU21      CPU22      CPU23      
   0:        433          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC-edge      timer
   1:          3          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC-edge      i8042
   3:          4          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC-edge    
   4:        357          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC-edge      serial
   8:          1          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC-edge      rtc0
   9:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC-fasteoi   acpi
  12:          4          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC-edge      i8042
  16:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC   16-fasteoi   pata_jmicron, uhci_hcd:usb3
  18:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC   18-fasteoi   ehci_hcd:usb1, uhci_hcd:usb7, i801_smbus
  19:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC   19-fasteoi   uhci_hcd:usb4, uhci_hcd:usb6
  23:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IO-APIC   23-fasteoi   ehci_hcd:usb2, uhci_hcd:usb5
  25:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
  27:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
  29:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
  31:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
  33:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
  34:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      PCIe PME
  35:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      PCIe PME
  36:       2039          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      ahci
  37:          1          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0
  38:       6467          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0-TxRx-0
  39:       5504          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0-TxRx-1
  40:       5298          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0-TxRx-2
  41:       5221          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0-TxRx-3
  42:       6415          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0-TxRx-4
  43:       5311          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0-TxRx-5
  44:       5231          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0-TxRx-6
  45:       5556          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      eth0-TxRx-7
 NMI:          8          1          1          0          0          0          0          0          7          0          0          2          0          3          1          0          0          0          0          2          0          0          0          1   Non-maskable interrupts
 LOC:      37022      15954      12352      10360      10326       9371       9760       9739      13134      11383      10975      11614       8692      15659      10999       9948       8597       8485      10011      15927      10431      10164       8530      10337   Local timer interrupts
 SPU:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   Spurious interrupts
 PMI:          8          1          1          0          0          0          0          0          7          0          0          2          0          3          1          0          0          0          0          2          0          0          0          1   Performance monitoring interrupts
 IWI:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   IRQ work interrupts
 RTR:         15          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   APIC ICR read retries
 RES:       1150        345        168         73         60         66         92         70        243         60         54         54         35        108         66         35         32         36         41        286         60         37         46         55   Rescheduling interrupts
 CAL:         49         68         76         76         76         76        173        141        160        197        169        146         73         73         73         73         73         73         76        254         90        167         83         79   Function call interrupts
 TLB:          0          0          0          0          0          0          0          0          1          1          0          0          1          0          0          0          0          0          0          3          1          0          1          0   TLB shootdowns
 TRM:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   Thermal event interrupts
 THR:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   Threshold APIC interrupts
 MCE:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   Machine check exceptions
 MCP:         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36         36   Machine check polls
 ERR:          0
 MIS:          0

> Also /sys/kernel/debug/wakeup_sources (if /sys/kernel/debug/ is where your debugfs
> lives) before

of course not, that's /debug :-)

name		active_count	event_count	wakeup_count	expire_count	active_since	total_time	max_time	last_change	prevent_suspend_time
00:06       	0		0		0		0		0		0		0		7066		0
00:02       	0		0		0		0		0		0		0		7056		0
0000:00:1d.2	0		0		0		0		0		0		0		7056		0
0000:00:1d.1	0		0		0		0		0		0		0		7046		0
0000:00:1d.0	0		0		0		0		0		0		0		7035		0
0000:00:1a.2	0		0		0		0		0		0		0		7025		0
0000:00:1a.0	0		0		0		0		0		0		0		7015		0
0000:00:1d.7	0		0		0		0		0		0		0		7004		0
0000:00:1a.7	0		0		0		0		0		0		0		6982		0
0000:01:00.1	0		0		0		0		0		0		0		6797		0
0000:01:00.0	0		0		0		0		0		0		0		6591		0
alarmtimer  	0		0		0		0		0		0		0		5012		0
PNP0C0C:00  	0		0		0		0		0		0		0		1924		0
PNP0C0E:00  	0		0		0		0		0		0		0		1924		0
LNXPWRBN:00 	0		0		0		0		0		0		0		1922		0
PNP0A08:00  	0		0		0		0		0		0		0		1838		0
device:2a   	0		0		0		0		0		0		0		1802		0
device:29   	0		0		0		0		0		0		0		1798		0
device:10   	0		0		0		0		0		0		0		1763		0
device:02   	0		0		0		0		0		0		0		1757		0
device:00   	0		0		0		0		0		0		0		1746		0
device:01   	0		0		0		0		0		0		0		1735		0
device:15   	0		0		0		0		0		0		0		1730		0
device:13   	0		0		0		0		0		0		0		1723		0
device:12   	0		0		0		0		0		0		0		1718		0
device:11   	0		0		0		0		0		0		0		1711		0
device:1f   	0		0		0		0		0		0		0		1705		0
device:1b   	0		0		0		0		0		0		0		1699		0
device:19   	0		0		0		0		0		0		0		1693		0
device:18   	0		0		0		0		0		0		0		1685		0
device:16   	0		0		0		0		0		0		0		1678		0
device:28   	0		0		0		0		0		0		0		1616		0
device:26   	0		0		0		0		0		0		0		1612		0
device:24   	0		0		0		0		0		0		0		1607		0
device:22   	0		0		0		0		0		0		0		1602		0
device:20   	0		0		0		0		0		0		0		1597		0

> and after a "freeze" with an attempt to use WoL to wake it up.

Issued 3 WoLs then hit the power button:

name		active_count	event_count	wakeup_count	expire_count	active_since	total_time	max_time	last_change	prevent_suspend_time
00:06       	0		0		0		0		0		0		0		7066		0
00:02       	0		0		0		0		0		0		0		7056		0
0000:00:1d.2	0		0		0		0		0		0		0		7056		0
0000:00:1d.1	0		0		0		0		0		0		0		7046		0
0000:00:1d.0	0		0		0		0		0		0		0		7035		0
0000:00:1a.2	0		0		0		0		0		0		0		7025		0
0000:00:1a.0	0		0		0		0		0		0		0		7015		0
0000:00:1d.7	0		0		0		0		0		0		0		7004		0
0000:00:1a.7	0		0		0		0		0		0		0		6982		0
0000:01:00.1	0		0		0		0		0		0		0		6797		0
0000:01:00.0	0		0		0		0		0		0		0		6591		0
alarmtimer  	0		0		0		0		0		0		0		5012		0
PNP0C0C:00  	0		0		0		0		0		0		0		1924		0
PNP0C0E:00  	0		0		0		0		0		0		0		1924		0
LNXPWRBN:00 	1		1		0		0		0		0		0		10597988		0
PNP0A08:00  	0		0		0		0		0		0		0		1838		0
device:2a   	0		0		0		0		0		0		0		1802		0
device:29   	0		0		0		0		0		0		0		1798		0
device:10   	0		0		0		0		0		0		0		1763		0
device:02   	0		0		0		0		0		0		0		1757		0
device:00   	0		0		0		0		0		0		0		1746		0
device:01   	0		0		0		0		0		0		0		1735		0
device:15   	0		0		0		0		0		0		0		1730		0
device:13   	0		0		0		0		0		0		0		1723		0
device:12   	0		0		0		0		0		0		0		1718		0
device:11   	0		0		0		0		0		0		0		1711		0
device:1f   	0		0		0		0		0		0		0		1705		0
device:1b   	0		0		0		0		0		0		0		1699		0
device:19   	0		0		0		0		0		0		0		1693		0
device:18   	0		0		0		0		0		0		0		1685		0
device:16   	0		0		0		0		0		0		0		1678		0
device:28   	0		0		0		0		0		0		0		1616		0
device:26   	0		0		0		0		0		0		0		1612		0
device:24   	0		0		0		0		0		0		0		1607		0
device:22   	0		0		0		0		0		0		0		1602		0
device:20   	0		0		0		0		0		0		0		1597		0

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-22  8:55   ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Peter Zijlstra
  2014-07-22  9:42     ` Peter Zijlstra
@ 2014-07-22 12:23     ` Rafael J. Wysocki
  2014-07-22 12:13       ` Peter Zijlstra
  1 sibling, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22 12:23 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Tuesday, July 22, 2014 10:55:38 AM Peter Zijlstra wrote:
> On Tue, Jul 22, 2014 at 03:23:29AM +0200, Rafael J. Wysocki wrote:
> 
> > That turned out to be more challenging than I had thought initially.
> > 
> > The last version I sent was almost OK, but it had some issues (like it could
> > walk the PCI hierarchy before resuming any PCI devices during system resume),
> > so a new version follows.  I did my best to avoid introducing any new problems
> > with it, but I obviously might overlook something.
> > 
> > It works for me and doesn't seem to break anything as far as I can say.
> > 
> > [1/3] Make PM workqueue available for CONFIG_PM_RUNTIME unset.
> > [2/3] Rework the handling of ACPI device wakeup notifications.
> > [3/3] Enable wakeup GPEs while setting up devices for wakeup during system
> >       suspend too.
> 
> Doesn't break, doesn't 'work' either.

This probably means that WoL on that machine is not ACPI-based.

> Is there anything I can provide you with to make this easier? lspci output
> or anything like that?

Yes, /proc/interrupts from the machine in question would help to start with.

Also /sys/kernel/debug/wakeup_sources (if /sys/kernel/debug/ is where your debugfs
lives) before and after a "freeze" with an attempt to use WoL to wake it up.

Rafael


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Update][PATCH 2/3] ACPI / PM: Revork the handling of ACPI device wakeup notifications
  2014-07-22  1:25   ` [PATCH 2/3] ACPI / PM: Revork the handling of ACPI device wakeup notifications Rafael J. Wysocki
@ 2014-07-22 12:29     ` Rafael J. Wysocki
  0 siblings, 0 replies; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22 12:29 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Linux Kernel Mailing List, Linux PM list, Linux PCI, Zhang Rui,
	Peter Zijlstra

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Since ACPI wakeup GPEs are going to be enabled during system suspend
as well as for runtime wakeup by a subsequent patch and the same
notify handlers will be used in both cases, rework the ACPI device
wakeup notification framework so that the part specific to physical
devices is always run asynchronously from the PM workqueue.  This
prevents runtime resume callbacks for those devices from being
run during system suspend and resume which may not be appropriate,
among other things.

Also make ACPI device wakeup notification handling a bit more robust
agaist subsequent removal of ACPI device objects, whould that ever
happen, and create a wakeup source object for each ACPI device
configured for wakeup so that wakeup notifications for those
devices can wake up the system from the "freeze" sleep state.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

I noticed that acpi_pm_notify_handler() was racy with the handler
unregistration, so added locking and a check to it.

---
 drivers/acpi/device_pm.c |   80 ++++++++++++++++++++++++++++++++++-------------
 drivers/acpi/pci_root.c  |    2 -
 drivers/pci/pci-acpi.c   |   60 +++++++++++------------------------
 include/acpi/acpi_bus.h  |   21 +++++++-----
 include/linux/pci-acpi.h |   13 +++++--
 5 files changed, 101 insertions(+), 75 deletions(-)

Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -315,12 +315,19 @@ struct acpi_device_wakeup_flags {
 	u8 notifier_present:1;  /* Wake-up notify handler has been installed */
 };
 
+struct acpi_device_wakeup_context {
+	struct work_struct work;
+	struct device *dev;
+};
+
 struct acpi_device_wakeup {
 	acpi_handle gpe_device;
 	u64 gpe_number;
 	u64 sleep_state;
 	struct list_head resources;
 	struct acpi_device_wakeup_flags flags;
+	struct acpi_device_wakeup_context context;
+	struct wakeup_source *ws;
 	int prepare_count;
 };
 
@@ -504,20 +511,18 @@ int acpi_enable_wakeup_device_power(stru
 int acpi_disable_wakeup_device_power(struct acpi_device *dev);
 
 #ifdef CONFIG_PM
-acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-				 acpi_notify_handler handler, void *context);
-acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-				    acpi_notify_handler handler);
+acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
+				 void (*work_func)(struct work_struct *work));
+acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
 int acpi_pm_device_sleep_state(struct device *, int *, int);
 #else
 static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-					       acpi_notify_handler handler,
-					       void *context)
+					       struct device *dev,
+				               void (*work_func)(struct work_struct *work))
 {
 	return AE_SUPPORT;
 }
-static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-						  acpi_notify_handler handler)
+static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
 {
 	return AE_SUPPORT;
 }
Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -367,29 +367,61 @@ EXPORT_SYMBOL(acpi_bus_power_manageable)
 #ifdef CONFIG_PM
 static DEFINE_MUTEX(acpi_pm_notifier_lock);
 
+static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used)
+{
+	struct acpi_device *adev;
+
+	if (val != ACPI_NOTIFY_DEVICE_WAKE)
+		return;
+
+	adev = acpi_bus_get_acpi_device(handle);
+	if (!adev)
+		return;
+
+	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);
+	}
+
+	mutex_unlock(&acpi_pm_notifier_lock);
+
+	acpi_bus_put_acpi_device(adev);
+}
+
 /**
- * acpi_add_pm_notifier - Register PM notifier for given ACPI device.
- * @adev: ACPI device to add the notifier for.
- * @context: Context information to pass to the notifier routine.
+ * 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.
  *
  * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
  * PM wakeup events.  For example, wakeup events may be generated for bridges
  * if one of the devices below the bridge is signaling wakeup, even if the
  * bridge itself doesn't have a wakeup GPE associated with it.
  */
-acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
-				 acpi_notify_handler handler, void *context)
+acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
+				 void (*work_func)(struct work_struct *work))
 {
 	acpi_status status = AE_ALREADY_EXISTS;
 
+	if (!dev && !work_func)
+		return AE_BAD_PARAMETER;
+
 	mutex_lock(&acpi_pm_notifier_lock);
 
 	if (adev->wakeup.flags.notifier_present)
 		goto out;
 
-	status = acpi_install_notify_handler(adev->handle,
-					     ACPI_SYSTEM_NOTIFY,
-					     handler, context);
+	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);
+
+	status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY,
+					     acpi_pm_notify_handler, NULL);
 	if (ACPI_FAILURE(status))
 		goto out;
 
@@ -404,8 +436,7 @@ acpi_status acpi_add_pm_notifier(struct
  * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device.
  * @adev: ACPI device to remove the notifier from.
  */
-acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
-				    acpi_notify_handler handler)
+acpi_status acpi_remove_pm_notifier(struct acpi_device *adev)
 {
 	acpi_status status = AE_BAD_PARAMETER;
 
@@ -416,10 +447,17 @@ acpi_status acpi_remove_pm_notifier(stru
 
 	status = acpi_remove_notify_handler(adev->handle,
 					    ACPI_SYSTEM_NOTIFY,
-					    handler);
+					    acpi_pm_notify_handler);
 	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.dev = NULL;
+	wakeup_source_unregister(adev->wakeup.ws);
+
 	adev->wakeup.flags.notifier_present = false;
 
  out:
@@ -602,16 +640,15 @@ EXPORT_SYMBOL(acpi_pm_device_sleep_state
 
 #ifdef CONFIG_PM_RUNTIME
 /**
- * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
- * @handle: ACPI handle of the device the notification is for.
- * @event: Type of the signaled event.
- * @context: Device corresponding to @handle.
+ * acpi_pm_notify_work_func - ACPI devices wakeup notification work function.
+ * @work: Work item to handle.
  */
-static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
+static void acpi_pm_notify_work_func(struct work_struct *work)
 {
-	struct device *dev = context;
+	struct device *dev;
 
-	if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
+	dev = container_of(work, struct acpi_device_wakeup_context, work)->dev;
+	if (dev) {
 		pm_wakeup_event(dev, 0);
 		pm_runtime_resume(dev);
 	}
@@ -677,8 +714,7 @@ int acpi_pm_device_run_wake(struct devic
 }
 EXPORT_SYMBOL(acpi_pm_device_run_wake);
 #else
-static inline void acpi_wakeup_device(acpi_handle handle, u32 event,
-				      void *context) {}
+static inline void acpi_pm_notify_work_func(struct work_struct *work) {}
 #endif /* CONFIG_PM_RUNTIME */
 
 #ifdef CONFIG_PM_SLEEP
@@ -1048,7 +1084,7 @@ int acpi_dev_pm_attach(struct device *de
 	if (dev->pm_domain)
 		return -EEXIST;
 
-	acpi_add_pm_notifier(adev, acpi_wakeup_device, dev);
+	acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func);
 	dev->pm_domain = &acpi_general_pm_domain;
 	if (power_on) {
 		acpi_dev_pm_full_power(adev);
@@ -1076,7 +1112,7 @@ void acpi_dev_pm_detach(struct device *d
 
 	if (adev && dev->pm_domain == &acpi_general_pm_domain) {
 		dev->pm_domain = NULL;
-		acpi_remove_pm_notifier(adev, acpi_wakeup_device);
+		acpi_remove_pm_notifier(adev);
 		if (power_off) {
 			/*
 			 * If the device's PM QoS resume latency limit or flags
Index: linux-pm/drivers/pci/pci-acpi.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-acpi.c
+++ linux-pm/drivers/pci/pci-acpi.c
@@ -18,31 +18,31 @@
 #include "pci.h"
 
 /**
- * pci_acpi_wake_bus - Wake-up notification handler for root buses.
- * @handle: ACPI handle of a device the notification is for.
- * @event: Type of the signaled event.
- * @context: PCI root bus to wake up devices on.
+ * pci_acpi_wake_bus - Root bus wakeup notification fork function.
+ * @work: Work item to handle.
  */
-static void pci_acpi_wake_bus(acpi_handle handle, u32 event, void *context)
+static void pci_acpi_wake_bus(struct work_struct *work)
 {
-	struct pci_bus *pci_bus = context;
+	struct acpi_device *adev;
+	struct acpi_pci_root *root;
 
-	if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_bus)
-		pci_pme_wakeup_bus(pci_bus);
+	adev = container_of(work, struct acpi_device, wakeup.context.work);
+	root = acpi_driver_data(adev);
+	pci_pme_wakeup_bus(root->bus);
 }
 
 /**
- * pci_acpi_wake_dev - Wake-up notification handler for PCI devices.
+ * pci_acpi_wake_dev - PCI device wakeup notification work function.
  * @handle: ACPI handle of a device the notification is for.
- * @event: Type of the signaled event.
- * @context: PCI device object to wake up.
+ * @work: Work item to handle.
  */
-static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
+static void pci_acpi_wake_dev(struct work_struct *work)
 {
-	struct pci_dev *pci_dev = context;
+	struct acpi_device_wakeup_context *context;
+	struct pci_dev *pci_dev;
 
-	if (event != ACPI_NOTIFY_DEVICE_WAKE || !pci_dev)
-		return;
+	context = container_of(work, struct acpi_device_wakeup_context, work);
+	pci_dev = to_pci_dev(context->dev);
 
 	if (pci_dev->pme_poll)
 		pci_dev->pme_poll = false;
@@ -65,23 +65,12 @@ static void pci_acpi_wake_dev(acpi_handl
 }
 
 /**
- * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus.
- * @dev: ACPI device to add the notifier for.
- * @pci_bus: PCI bus to walk checking for PME status if an event is signaled.
+ * pci_acpi_add_bus_pm_notifier - Register PM notifier for root PCI bus.
+ * @dev: PCI root bridge ACPI device.
  */
-acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev,
-					 struct pci_bus *pci_bus)
+acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev)
 {
-	return acpi_add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus);
-}
-
-/**
- * pci_acpi_remove_bus_pm_notifier - Unregister PCI bus PM notifier.
- * @dev: ACPI device to remove the notifier from.
- */
-acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
-{
-	return acpi_remove_pm_notifier(dev, pci_acpi_wake_bus);
+	return acpi_add_pm_notifier(dev, NULL, pci_acpi_wake_bus);
 }
 
 /**
@@ -92,16 +81,7 @@ acpi_status pci_acpi_remove_bus_pm_notif
 acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
 				     struct pci_dev *pci_dev)
 {
-	return acpi_add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev);
-}
-
-/**
- * pci_acpi_remove_pm_notifier - Unregister PCI device PM notifier.
- * @dev: ACPI device to remove the notifier from.
- */
-acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
-{
-	return acpi_remove_pm_notifier(dev, pci_acpi_wake_dev);
+	return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
 }
 
 phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
Index: linux-pm/include/linux/pci-acpi.h
===================================================================
--- linux-pm.orig/include/linux/pci-acpi.h
+++ linux-pm/include/linux/pci-acpi.h
@@ -11,12 +11,17 @@
 #include <linux/acpi.h>
 
 #ifdef CONFIG_ACPI
-extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev,
-						 struct pci_bus *pci_bus);
-extern acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev);
+extern acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev);
+static inline acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev)
+{
+	return acpi_remove_pm_notifier(dev);
+}
 extern acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
 					     struct pci_dev *pci_dev);
-extern acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev);
+static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
+{
+	return acpi_remove_pm_notifier(dev);
+}
 extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
 
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
Index: linux-pm/drivers/acpi/pci_root.c
===================================================================
--- linux-pm.orig/drivers/acpi/pci_root.c
+++ linux-pm/drivers/acpi/pci_root.c
@@ -593,7 +593,7 @@ static int acpi_pci_root_add(struct acpi
 	if (no_aspm)
 		pcie_no_aspm();
 
-	pci_acpi_add_bus_pm_notifier(device, root->bus);
+	pci_acpi_add_bus_pm_notifier(device);
 	if (device->wakeup.flags.run_wake)
 		device_set_run_wake(root->bus->bridge, true);
 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-22 12:13       ` Peter Zijlstra
@ 2014-07-22 22:26         ` Rafael J. Wysocki
  2014-07-23  7:28           ` Peter Zijlstra
  0 siblings, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-22 22:26 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Tuesday, July 22, 2014 02:13:45 PM Peter Zijlstra wrote:
> On Tue, Jul 22, 2014 at 02:23:03PM +0200, Rafael J. Wysocki wrote:
> > > Doesn't break, doesn't 'work' either.
> > 
> > This probably means that WoL on that machine is not ACPI-based.
> 
> Oh lovely, of course that's an 'option' !
> 
> > > Is there anything I can provide you with to make this easier? lspci output
> > > or anything like that?
> > 
> > Yes, /proc/interrupts from the machine in question would help to start with.
> 
> Be sure to get a _wide_ terminal when viewing ;-)

[cut]

OK, so the "PCIe PME" labels indicate that at least some devices on that system
use native PME signaling, in which case that's what is used for the WoL most
likely.

All of the counts below seem to be 0, though, so I'm not sure if they actually
work.  I guess we'll see. :-)

>   25:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
>   27:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
>   29:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
>   31:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
>   33:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      aerdrv, PCIe PME
>   34:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      PCIe PME
>   35:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI-edge      PCIe PME

[cut]

> > Also /sys/kernel/debug/wakeup_sources (if /sys/kernel/debug/ is where your debugfs
> > lives) before
> 
> of course not, that's /debug :-)

[cut]

OK, there are several wakeup sources for ACPI devices added by one of the patches
you have tested in there:

> device:2a   	0		0		0		0		0		0		0		1802		0
> device:29   	0		0		0		0		0		0		0		1798		0
> device:10   	0		0		0		0		0		0		0		1763		0
> device:02   	0		0		0		0		0		0		0		1757		0
> device:00   	0		0		0		0		0		0		0		1746		0
> device:01   	0		0		0		0		0		0		0		1735		0
> device:15   	0		0		0		0		0		0		0		1730		0
> device:13   	0		0		0		0		0		0		0		1723		0
> device:12   	0		0		0		0		0		0		0		1718		0
> device:11   	0		0		0		0		0		0		0		1711		0
> device:1f   	0		0		0		0		0		0		0		1705		0
> device:1b   	0		0		0		0		0		0		0		1699		0
> device:19   	0		0		0		0		0		0		0		1693		0
> device:18   	0		0		0		0		0		0		0		1685		0
> device:16   	0		0		0		0		0		0		0		1678		0
> device:28   	0		0		0		0		0		0		0		1616		0
> device:26   	0		0		0		0		0		0		0		1612		0
> device:24   	0		0		0		0		0		0		0		1607		0
> device:22   	0		0		0		0		0		0		0		1602		0
> device:20   	0		0		0		0		0		0		0		1597		0

but since their counts are 0, there are no events signaled via ACPI.

All of that indicates that the machine in question has WoL based on native PCIe
PME signaling.  In that case it doesn't wake up from the "freeze" state, because
some code is missing.

The below is my idea about how to implement that code.

Register an additional wakeup source object for each PCIe PME service
device.  That object will be used to generate wakeups from the "freeze"
sleep state.

For each PCIe port with PME service during the "prepare" phase of
system suspend walk the bus below it and see if any devices on that
bus are configured for wakeup.  If so, mark the port as one that can
be used for system wakeup signaling and handle it differenty going
forward.

Namely, while suspending its PME service, do not disable the PME
interrupt, but configure that interrupt for system wakeup and set
a "suspended" flag for the PME service to make the interrupt handled
behave in a special way, which is to call __pm_wakeup_event() with
the service's wakeup source object as the first argument whenever the
interrupt is triggered.

The "suspended" flag is cleared while resuming the PME service and
the "wakeup" flag is cleared at the "complete" stage of system
resume.

Please check if the patch below makes any difference.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/pcie/pme.c          |   96 +++++++++++++++++++++++++++++++++++-----
 drivers/pci/pcie/portdrv.h      |    2 
 drivers/pci/pcie/portdrv_core.c |   45 ++++++++++++++++++
 drivers/pci/pcie/portdrv_pci.c  |    2 
 include/linux/pcieport_if.h     |    2 
 5 files changed, 134 insertions(+), 13 deletions(-)

Index: linux-pm/drivers/pci/pcie/pme.c
===================================================================
--- linux-pm.orig/drivers/pci/pcie/pme.c
+++ linux-pm/drivers/pci/pcie/pme.c
@@ -20,6 +20,7 @@
 #include <linux/device.h>
 #include <linux/pcieport_if.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm_wakeup.h>
 
 #include "../pci.h"
 #include "portdrv.h"
@@ -45,7 +46,9 @@ struct pcie_pme_service_data {
 	spinlock_t lock;
 	struct pcie_device *srv;
 	struct work_struct work;
-	bool noirq; /* Don't enable the PME interrupt used by this service. */
+	struct wakeup_source *ws;
+	bool suspended; /* The PME service has been suspended. */
+	bool wakeup; /* The PME interrupt is used for system wakeup. */
 };
 
 /**
@@ -223,7 +226,7 @@ static void pcie_pme_work_fn(struct work
 	spin_lock_irq(&data->lock);
 
 	for (;;) {
-		if (data->noirq)
+		if (data->suspended && !data->wakeup)
 			break;
 
 		pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
@@ -234,6 +237,11 @@ static void pcie_pme_work_fn(struct work
 			 */
 			pcie_clear_root_pme_status(port);
 
+			if (data->wakeup && data->suspended) {
+				__pm_wakeup_event(data->ws, 0);
+				break;
+			}
+
 			spin_unlock_irq(&data->lock);
 			pcie_pme_handle_request(port, rtsta & 0xffff);
 			spin_lock_irq(&data->lock);
@@ -250,7 +258,7 @@ static void pcie_pme_work_fn(struct work
 		spin_lock_irq(&data->lock);
 	}
 
-	if (!data->noirq)
+	if (!data->suspended || data->wakeup)
 		pcie_pme_interrupt_enable(port, true);
 
 	spin_unlock_irq(&data->lock);
@@ -360,6 +368,7 @@ static int pcie_pme_probe(struct pcie_de
 	if (ret) {
 		kfree(data);
 	} else {
+		data->ws = wakeup_source_register(dev_name(&srv->device));
 		pcie_pme_mark_devices(port);
 		pcie_pme_interrupt_enable(port, true);
 	}
@@ -367,6 +376,43 @@ static int pcie_pme_probe(struct pcie_de
 	return ret;
 }
 
+static bool pcie_pme_check_wakeup(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	if (!bus)
+		return false;
+
+	list_for_each_entry(dev, &bus->devices, bus_list)
+		if (device_may_wakeup(&dev->dev)
+		    || pcie_pme_check_wakeup(dev->subordinate))
+			return true;
+
+	return false;
+}
+
+/**
+ * pcie_pme_prepare - Prepare system PM transition for PCIe PME service device.
+ * @srv - PCIe service device to handle.
+ *
+ * Check if any devices below the port are configured for wakeup.  If so, set
+ * the service's wakeup flag.
+ */
+static int pcie_pme_prepare(struct pcie_device *srv)
+{
+	struct pcie_pme_service_data *data = get_service_data(srv);
+	struct pci_dev *port = srv->port;
+
+	if (device_may_wakeup(&port->dev)) {
+		data->wakeup = true;
+	} else {
+		down_read(&pci_bus_sem);
+		data->wakeup = pcie_pme_check_wakeup(port->subordinate);
+		up_read(&pci_bus_sem);
+	}
+	return 0;
+}
+
 /**
  * pcie_pme_suspend - Suspend PCIe PME service device.
  * @srv: PCIe service device to suspend.
@@ -374,12 +420,17 @@ static int pcie_pme_probe(struct pcie_de
 static int pcie_pme_suspend(struct pcie_device *srv)
 {
 	struct pcie_pme_service_data *data = get_service_data(srv);
-	struct pci_dev *port = srv->port;
 
 	spin_lock_irq(&data->lock);
-	pcie_pme_interrupt_enable(port, false);
-	pcie_clear_root_pme_status(port);
-	data->noirq = true;
+	if (data->wakeup) {
+		enable_irq_wake(srv->irq);
+	} else {
+		struct pci_dev *port = srv->port;
+
+		pcie_pme_interrupt_enable(port, false);
+		pcie_clear_root_pme_status(port);
+	}
+	data->suspended = true;
 	spin_unlock_irq(&data->lock);
 
 	synchronize_irq(srv->irq);
@@ -394,26 +445,45 @@ static int pcie_pme_suspend(struct pcie_
 static int pcie_pme_resume(struct pcie_device *srv)
 {
 	struct pcie_pme_service_data *data = get_service_data(srv);
-	struct pci_dev *port = srv->port;
 
 	spin_lock_irq(&data->lock);
-	data->noirq = false;
-	pcie_clear_root_pme_status(port);
-	pcie_pme_interrupt_enable(port, true);
+	data->suspended = false;
+	if (data->wakeup) {
+		disable_irq_wake(srv->irq);
+	} else {
+		struct pci_dev *port = srv->port;
+
+		pcie_clear_root_pme_status(port);
+		pcie_pme_interrupt_enable(port, true);
+	}
 	spin_unlock_irq(&data->lock);
 
 	return 0;
 }
 
 /**
+ * pcie_pme_resume - Complete system PM transition for PCIe PME service device.
+ * @srv - PCIe service device to handle.
+ */
+static void pcie_pme_complete(struct pcie_device *srv)
+{
+	struct pcie_pme_service_data *data = get_service_data(srv);
+
+	data->wakeup = false;
+}
+
+/**
  * pcie_pme_remove - Prepare PCIe PME service device for removal.
  * @srv - PCIe service device to remove.
  */
 static void pcie_pme_remove(struct pcie_device *srv)
 {
+	struct pcie_pme_service_data *data = get_service_data(srv);
+
 	pcie_pme_suspend(srv);
 	free_irq(srv->irq, srv);
-	kfree(get_service_data(srv));
+	wakeup_source_unregister(data->ws);
+	kfree(data);
 }
 
 static struct pcie_port_service_driver pcie_pme_driver = {
@@ -422,8 +492,10 @@ static struct pcie_port_service_driver p
 	.service	= PCIE_PORT_SERVICE_PME,
 
 	.probe		= pcie_pme_probe,
+	.prepare	= pcie_pme_prepare,
 	.suspend	= pcie_pme_suspend,
 	.resume		= pcie_pme_resume,
+	.complete	= pcie_pme_complete,
 	.remove		= pcie_pme_remove,
 };
 
Index: linux-pm/drivers/pci/pcie/portdrv_core.c
===================================================================
--- linux-pm.orig/drivers/pci/pcie/portdrv_core.c
+++ linux-pm/drivers/pci/pcie/portdrv_core.c
@@ -413,6 +413,27 @@ error_disable:
 }
 
 #ifdef CONFIG_PM
+static int prepare_iter(struct device *dev, void *data)
+{
+	struct pcie_port_service_driver *service_driver;
+
+	if ((dev->bus == &pcie_port_bus_type) && dev->driver) {
+		service_driver = to_service_driver(dev->driver);
+		if (service_driver->prepare)
+			service_driver->prepare(to_pcie_device(dev));
+	}
+	return 0;
+}
+
+/**
+ * pcie_port_device_prepare - prepare PCIe port services for system suspend
+ * @dev: PCI Express port to handle
+ */
+int pcie_port_device_prepare(struct device *dev)
+{
+	return device_for_each_child(dev, NULL, prepare_iter);
+}
+
 static int suspend_iter(struct device *dev, void *data)
 {
 	struct pcie_port_service_driver *service_driver;
@@ -448,13 +469,35 @@ static int resume_iter(struct device *de
 }
 
 /**
- * pcie_port_device_suspend - resume port services associated with a PCIe port
+ * pcie_port_device_resume - resume port services associated with a PCIe port
  * @dev: PCI Express port to handle
  */
 int pcie_port_device_resume(struct device *dev)
 {
 	return device_for_each_child(dev, NULL, resume_iter);
 }
+
+static int complete_iter(struct device *dev, void *data)
+{
+	struct pcie_port_service_driver *service_driver;
+
+	if ((dev->bus == &pcie_port_bus_type) && dev->driver) {
+		service_driver = to_service_driver(dev->driver);
+		if (service_driver->complete)
+			service_driver->complete(to_pcie_device(dev));
+	}
+	return 0;
+}
+
+/**
+ * pcie_port_device_complete - complete system resume for PCIe port services
+ * @dev: PCI Express port to handle
+ */
+void pcie_port_device_complete(struct device *dev)
+{
+	device_for_each_child(dev, NULL, complete_iter);
+}
+
 #endif /* PM */
 
 static int remove_iter(struct device *dev, void *data)
Index: linux-pm/drivers/pci/pcie/portdrv.h
===================================================================
--- linux-pm.orig/drivers/pci/pcie/portdrv.h
+++ linux-pm/drivers/pci/pcie/portdrv.h
@@ -23,8 +23,10 @@
 extern struct bus_type pcie_port_bus_type;
 int pcie_port_device_register(struct pci_dev *dev);
 #ifdef CONFIG_PM
+int pcie_port_device_prepare(struct device *dev);
 int pcie_port_device_suspend(struct device *dev);
 int pcie_port_device_resume(struct device *dev);
+void pcie_port_device_complete(struct device *dev);
 #endif
 void pcie_port_device_remove(struct pci_dev *dev);
 int __must_check pcie_port_bus_register(void);
Index: linux-pm/drivers/pci/pcie/portdrv_pci.c
===================================================================
--- linux-pm.orig/drivers/pci/pcie/portdrv_pci.c
+++ linux-pm/drivers/pci/pcie/portdrv_pci.c
@@ -165,6 +165,8 @@ static int pcie_port_runtime_idle(struct
 #endif
 
 static const struct dev_pm_ops pcie_portdrv_pm_ops = {
+	.prepare	= pcie_port_device_prepare,
+	.complete	= pcie_port_device_complete,
 	.suspend	= pcie_port_device_suspend,
 	.resume		= pcie_port_device_resume,
 	.freeze		= pcie_port_device_suspend,
Index: linux-pm/include/linux/pcieport_if.h
===================================================================
--- linux-pm.orig/include/linux/pcieport_if.h
+++ linux-pm/include/linux/pcieport_if.h
@@ -45,8 +45,10 @@ struct pcie_port_service_driver {
 	const char *name;
 	int (*probe) (struct pcie_device *dev);
 	void (*remove) (struct pcie_device *dev);
+	int (*prepare) (struct pcie_device *dev);
 	int (*suspend) (struct pcie_device *dev);
 	int (*resume) (struct pcie_device *dev);
+	void (*complete) (struct pcie_device *dev);
 
 	/* Service Error Recovery Handler */
 	const struct pci_error_handlers *err_handler;


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-22 22:26         ` Rafael J. Wysocki
@ 2014-07-23  7:28           ` Peter Zijlstra
  2014-07-23 11:43             ` Rafael J. Wysocki
  0 siblings, 1 reply; 24+ messages in thread
From: Peter Zijlstra @ 2014-07-23  7:28 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Wed, Jul 23, 2014 at 12:26:20AM +0200, Rafael J. Wysocki wrote:
> All of that indicates that the machine in question has WoL based on native PCIe
> PME signaling.  In that case it doesn't wake up from the "freeze" state, because
> some code is missing.

Didn't wake, but it did show:

0000:00:01.0:pcie01     1               1               0               0               0               0               0               99207           0
LNXPWRBN:00             1               1               0               0               0               0               0               99191           0

So at least something's moving, although its not quite working yet.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-23 11:43             ` Rafael J. Wysocki
@ 2014-07-23 11:38               ` Peter Zijlstra
  2014-07-23 12:17                 ` Rafael J. Wysocki
  0 siblings, 1 reply; 24+ messages in thread
From: Peter Zijlstra @ 2014-07-23 11:38 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Wed, Jul 23, 2014 at 01:43:59PM +0200, Rafael J. Wysocki wrote:
> On Wednesday, July 23, 2014 09:28:50 AM Peter Zijlstra wrote:
> > On Wed, Jul 23, 2014 at 12:26:20AM +0200, Rafael J. Wysocki wrote:
> > > All of that indicates that the machine in question has WoL based on native PCIe
> > > PME signaling.  In that case it doesn't wake up from the "freeze" state, because
> > > some code is missing.
> > 
> > Didn't wake, but it did show:
> > 
> > 0000:00:01.0:pcie01     1               1               0               0               0               0               0               99207           0
> > LNXPWRBN:00             1               1               0               0               0               0               0               99191           0
> > 
> > So at least something's moving, although its not quite working yet.
> 
> That may be because I forgot about one piece, sorry about that.
> This patch:
> 
> https://patchwork.kernel.org/patch/4526561/
> 
> (which I think is in tip already) is needed to make enable_irq_wake()
> work with the "freeze" state.
> 
> Can you please apply this in addition and retest?

I appear to have that hunk already (I'm running -tip based kernels).

(also, patchwork blows chunks :/)

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-23  7:28           ` Peter Zijlstra
@ 2014-07-23 11:43             ` Rafael J. Wysocki
  2014-07-23 11:38               ` Peter Zijlstra
  0 siblings, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-23 11:43 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Wednesday, July 23, 2014 09:28:50 AM Peter Zijlstra wrote:
> On Wed, Jul 23, 2014 at 12:26:20AM +0200, Rafael J. Wysocki wrote:
> > All of that indicates that the machine in question has WoL based on native PCIe
> > PME signaling.  In that case it doesn't wake up from the "freeze" state, because
> > some code is missing.
> 
> Didn't wake, but it did show:
> 
> 0000:00:01.0:pcie01     1               1               0               0               0               0               0               99207           0
> LNXPWRBN:00             1               1               0               0               0               0               0               99191           0
> 
> So at least something's moving, although its not quite working yet.

That may be because I forgot about one piece, sorry about that.
This patch:

https://patchwork.kernel.org/patch/4526561/

(which I think is in tip already) is needed to make enable_irq_wake()
work with the "freeze" state.

Can you please apply this in addition and retest?

Rafael


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-23 12:17                 ` Rafael J. Wysocki
@ 2014-07-23 12:04                   ` Peter Zijlstra
  2014-07-23 16:55                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 24+ messages in thread
From: Peter Zijlstra @ 2014-07-23 12:04 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Wed, Jul 23, 2014 at 02:17:55PM +0200, Rafael J. Wysocki wrote:
> > (also, patchwork blows chunks :/)
> 
> That's never happened to me (and there's only one hunk in that patch).

I meant that patchwork sucks :-) It hides the actual patch, I had to
download things in order to see the actual patch.

> Anyway, the count for 0000:00:01.0:pcie01 means that the wakeup source
> has been activated, so it should have woken it up in theory.
> 
> Unless, of course, it was activated after the power button wakeup.

Yeah, I was thikning that maybe it doesn't get through entirely but has
pending state and comes through once we press the power button.

> It looks like the stuff works on the hardware level, though, so we should be
> able to make the wakeup work too.  I'll have another look later today.

Thanks.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-23 11:38               ` Peter Zijlstra
@ 2014-07-23 12:17                 ` Rafael J. Wysocki
  2014-07-23 12:04                   ` Peter Zijlstra
  0 siblings, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-23 12:17 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: ACPI Devel Maling List, Linux Kernel Mailing List, Linux PM list,
	Linux PCI, Zhang Rui

On Wednesday, July 23, 2014 01:38:40 PM Peter Zijlstra wrote:
> On Wed, Jul 23, 2014 at 01:43:59PM +0200, Rafael J. Wysocki wrote:
> > On Wednesday, July 23, 2014 09:28:50 AM Peter Zijlstra wrote:
> > > On Wed, Jul 23, 2014 at 12:26:20AM +0200, Rafael J. Wysocki wrote:
> > > > All of that indicates that the machine in question has WoL based on native PCIe
> > > > PME signaling.  In that case it doesn't wake up from the "freeze" state, because
> > > > some code is missing.
> > > 
> > > Didn't wake, but it did show:
> > > 
> > > 0000:00:01.0:pcie01     1               1               0               0               0               0               0               99207           0
> > > LNXPWRBN:00             1               1               0               0               0               0               0               99191           0
> > > 
> > > So at least something's moving, although its not quite working yet.
> > 
> > That may be because I forgot about one piece, sorry about that.
> > This patch:
> > 
> > https://patchwork.kernel.org/patch/4526561/
> > 
> > (which I think is in tip already) is needed to make enable_irq_wake()
> > work with the "freeze" state.
> > 
> > Can you please apply this in addition and retest?
> 
> I appear to have that hunk already (I'm running -tip based kernels).

I see.

> (also, patchwork blows chunks :/)

That's never happened to me (and there's only one hunk in that patch).

Anyway, the count for 0000:00:01.0:pcie01 means that the wakeup source
has been activated, so it should have woken it up in theory.

Unless, of course, it was activated after the power button wakeup.

It looks like the stuff works on the hardware level, though, so we should be
able to make the wakeup work too.  I'll have another look later today.

Rafael


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-23 16:55                     ` Rafael J. Wysocki
@ 2014-07-23 16:50                       ` Peter Zijlstra
  0 siblings, 0 replies; 24+ messages in thread
From: Peter Zijlstra @ 2014-07-23 16:50 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM list, Linux PCI

On Wed, Jul 23, 2014 at 06:55:53PM +0200, Rafael J. Wysocki wrote:
> OK, so I think that before going any deeper it's better to check if we don't
> leave anything obvious behind, so please see if this makes any difference (on
> top of the previous one):
> 
> ---
>  drivers/pci/pcie/pme.c |    3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> Index: linux-pm/drivers/pci/pcie/pme.c
> ===================================================================
> --- linux-pm.orig/drivers/pci/pcie/pme.c
> +++ linux-pm/drivers/pci/pcie/pme.c
> @@ -364,7 +364,8 @@ static int pcie_pme_probe(struct pcie_de
>  	pcie_pme_interrupt_enable(port, false);
>  	pcie_clear_root_pme_status(port);
>  
> -	ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv);
> +	ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED | IRQF_NO_SUSPEND,
> +			  "PCIe PME", srv);
>  	if (ret) {
>  		kfree(data);
>  	} else {
> 

No joy :-(

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state
  2014-07-23 12:04                   ` Peter Zijlstra
@ 2014-07-23 16:55                     ` Rafael J. Wysocki
  2014-07-23 16:50                       ` Peter Zijlstra
  0 siblings, 1 reply; 24+ messages in thread
From: Rafael J. Wysocki @ 2014-07-23 16:55 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Linux PM list, Linux PCI

[Trimming CC list somewhat]

On Wednesday, July 23, 2014 02:04:32 PM Peter Zijlstra wrote:
> On Wed, Jul 23, 2014 at 02:17:55PM +0200, Rafael J. Wysocki wrote:
> > > (also, patchwork blows chunks :/)
> > 
> > That's never happened to me (and there's only one hunk in that patch).
> 
> I meant that patchwork sucks :-) It hides the actual patch, I had to
> download things in order to see the actual patch.

Well, my experience is much better here, never mind. :-)

> > Anyway, the count for 0000:00:01.0:pcie01 means that the wakeup source
> > has been activated, so it should have woken it up in theory.
> > 
> > Unless, of course, it was activated after the power button wakeup.
> 
> Yeah, I was thikning that maybe it doesn't get through entirely but has
> pending state and comes through once we press the power button.

It looks like that's what happens.

> > It looks like the stuff works on the hardware level, though, so we should be
> > able to make the wakeup work too.  I'll have another look later today.
> 
> Thanks.

OK, so I think that before going any deeper it's better to check if we don't
leave anything obvious behind, so please see if this makes any difference (on
top of the previous one):

---
 drivers/pci/pcie/pme.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Index: linux-pm/drivers/pci/pcie/pme.c
===================================================================
--- linux-pm.orig/drivers/pci/pcie/pme.c
+++ linux-pm/drivers/pci/pcie/pme.c
@@ -364,7 +364,8 @@ static int pcie_pme_probe(struct pcie_de
 	pcie_pme_interrupt_enable(port, false);
 	pcie_clear_root_pme_status(port);
 
-	ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv);
+	ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED | IRQF_NO_SUSPEND,
+			  "PCIe PME", srv);
 	if (ret) {
 		kfree(data);
 	} else {


^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2014-07-23 16:50 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-19 20:36 [PATCH 0/2] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
2014-07-19 20:37 ` [PATCH 1/2] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup Rafael J. Wysocki
2014-07-20  7:17   ` [Update][PATCH " Rafael J. Wysocki
2014-07-20 23:51     ` [Update 2x][PATCH " Rafael J. Wysocki
2014-07-21  8:17       ` Peter Zijlstra
2014-07-22  1:02         ` Rafael J. Wysocki
2014-07-19 20:38 ` [PATCH 2/2] ACPI / PM: Rename acpi_wakeup_device() to acpi_device_pm_event() Rafael J. Wysocki
2014-07-22  1:23 ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Rafael J. Wysocki
2014-07-22  1:24   ` [PATCH 1/3] PM: Create PM workqueue if runtime PM is not configured too Rafael J. Wysocki
2014-07-22  1:25   ` [PATCH 2/3] ACPI / PM: Revork the handling of ACPI device wakeup notifications Rafael J. Wysocki
2014-07-22 12:29     ` [Update][PATCH " Rafael J. Wysocki
2014-07-22  1:26   ` [PATCH 3/3] ACPI / PM: Always enable wakeup GPEs when enabling device wakeup Rafael J. Wysocki
2014-07-22  8:55   ` [PATCH 0/3] ACPI / PM: Make ACPI-based PCI wakeup work for the "freeze" sleep state Peter Zijlstra
2014-07-22  9:42     ` Peter Zijlstra
2014-07-22 12:23     ` Rafael J. Wysocki
2014-07-22 12:13       ` Peter Zijlstra
2014-07-22 22:26         ` Rafael J. Wysocki
2014-07-23  7:28           ` Peter Zijlstra
2014-07-23 11:43             ` Rafael J. Wysocki
2014-07-23 11:38               ` Peter Zijlstra
2014-07-23 12:17                 ` Rafael J. Wysocki
2014-07-23 12:04                   ` Peter Zijlstra
2014-07-23 16:55                     ` Rafael J. Wysocki
2014-07-23 16:50                       ` Peter Zijlstra

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.