linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] ACPI / PM: ACPI power management update
@ 2013-01-04 21:58 Rafael J. Wysocki
  2013-01-04 22:00 ` [PATCH 1/6] ACPI / PM: Change the way power transitions to D3cold are carried out Rafael J. Wysocki
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-04 21:58 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Lv Zheng, Huang Ying

Hi All,

There are a few changes of the ACPI power management code I've gathered
over the last few weeks.  Some of them are just cleanups etc., but some
fix (potential) problems and/or add new functionality.

[1/6] - Rework power states changing so that we put devices into D3hot
        (if available) before removing power from them entirely.
[2/6] - Rename __acpi_bus_get_power() (for future use).
[3/6] - Rename state_string() (in bus.c, for future use).
[4/6] - Export the (current) power states of ACPI devices via sysfs.
[5/6] - Move device power management functions from bus.c to device_pm.c.
[6/6] - (Unrelated to the above) Get rid of some ugly #ifdefs in sleep.c.

All of them except for [1/6] have been posted already and no one has had any
comments.

Please review.

Thanks,
Rafael


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

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

* [PATCH 1/6] ACPI / PM: Change the way power transitions to D3cold are carried out
  2013-01-04 21:58 [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
@ 2013-01-04 22:00 ` Rafael J. Wysocki
  2013-01-05  2:37   ` Zheng, Lv
  2013-01-04 22:01 ` [PATCH 2/6] ACPI / PM: More visible function for retrieving device power states Rafael J. Wysocki
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-04 22:00 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Lv Zheng, Huang Ying

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

During power transitions into D3cold from any shallower power states
we are supposed to transition the device into D3hot and remove power
from it afterward, but the current code in acpi_device_set_power()
doesn't work this way.

At the same time, though, we need to be careful enough to preserve
backwards compatibility for systems that don't distinguish between
D3hot and D3cold (e.g. designed before ACPI 4).

Modify acpi_device_set_power() so that it works in accordance with
the expectations in both cases.

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

Index: linux/drivers/acpi/bus.c
===================================================================
--- linux.orig/drivers/acpi/bus.c
+++ linux/drivers/acpi/bus.c
@@ -270,6 +270,7 @@ int acpi_device_set_power(struct acpi_de
 	int result = 0;
 	acpi_status status = AE_OK;
 	char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
+	bool cut_power = false;
 
 	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
 		return -EINVAL;
@@ -294,9 +295,13 @@ int acpi_device_set_power(struct acpi_de
 		return -ENODEV;
 	}
 
-	/* For D3cold we should execute _PS3, not _PS4. */
-	if (state == ACPI_STATE_D3_COLD)
+	/* For D3cold we should first transition into D3hot. */
+	if (state == ACPI_STATE_D3_COLD
+	    && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
+		state = ACPI_STATE_D3_HOT;
 		object_name[3] = '3';
+		cut_power = true;
+	}
 
 	/*
 	 * Transition Power
@@ -341,6 +346,9 @@ int acpi_device_set_power(struct acpi_de
 		}
 	}
 
+	if (cut_power)
+		result = acpi_power_transition(device, ACPI_STATE_D3_COLD);
+
       end:
 	if (result)
 		printk(KERN_WARNING PREFIX


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

* [PATCH 2/6] ACPI / PM: More visible function for retrieving device power states
  2013-01-04 21:58 [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
  2013-01-04 22:00 ` [PATCH 1/6] ACPI / PM: Change the way power transitions to D3cold are carried out Rafael J. Wysocki
@ 2013-01-04 22:01 ` Rafael J. Wysocki
  2013-01-04 22:02 ` [PATCH 3/6] ACPI / PM: Common string representations of " Rafael J. Wysocki
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-04 22:01 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Lv Zheng, Huang Ying

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

The function used for retrieving ACPI device power states,
__acpi_bus_get_power(), is now static, because it is only used
internally in drivers/acpi/bus.c.  However, it will be used
outside of that file going forward, so rename it to
acpi_device_get_power(), in analogy with acpi_device_set_power(),
add a kerneldoc comment to it and add its header to acpi_bus.h.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/bus.c      |   15 ++++++++++++---
 include/acpi/acpi_bus.h |    1 +
 2 files changed, 13 insertions(+), 3 deletions(-)

Index: linux/drivers/acpi/bus.c
===================================================================
--- linux.orig/drivers/acpi/bus.c
+++ linux/drivers/acpi/bus.c
@@ -200,7 +200,16 @@ static const char *state_string(int stat
 	}
 }
 
-static int __acpi_bus_get_power(struct acpi_device *device, int *state)
+/**
+ * acpi_device_get_power - Get power state of an ACPI device.
+ * @device: Device to get the power state of.
+ * @state: Place to store the power state of the device.
+ *
+ * This function does not update the device's power.state field, but it may
+ * update its parent's power.state field (when the parent's power state is
+ * unknown and the device's power state turns out to be D0).
+ */
+int acpi_device_get_power(struct acpi_device *device, int *state)
 {
 	int result = ACPI_STATE_UNKNOWN;
 
@@ -397,7 +406,7 @@ int acpi_bus_init_power(struct acpi_devi
 
 	device->power.state = ACPI_STATE_UNKNOWN;
 
-	result = __acpi_bus_get_power(device, &state);
+	result = acpi_device_get_power(device, &state);
 	if (result)
 		return result;
 
@@ -421,7 +430,7 @@ int acpi_bus_update_power(acpi_handle ha
 	if (result)
 		return result;
 
-	result = __acpi_bus_get_power(device, &state);
+	result = acpi_device_get_power(device, &state);
 	if (result)
 		return result;
 
Index: linux/include/acpi/acpi_bus.h
===================================================================
--- linux.orig/include/acpi/acpi_bus.h
+++ linux/include/acpi/acpi_bus.h
@@ -334,6 +334,7 @@ acpi_status acpi_bus_get_status_handle(a
 				       unsigned long long *sta);
 int acpi_bus_get_status(struct acpi_device *device);
 int acpi_bus_set_power(acpi_handle handle, int state);
+int acpi_device_get_power(struct acpi_device *device, int *state);
 int acpi_device_set_power(struct acpi_device *device, int state);
 int acpi_bus_update_power(acpi_handle handle, int *state_p);
 bool acpi_bus_power_manageable(acpi_handle handle);


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

* [PATCH 3/6] ACPI / PM: Common string representations of device power states
  2013-01-04 21:58 [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
  2013-01-04 22:00 ` [PATCH 1/6] ACPI / PM: Change the way power transitions to D3cold are carried out Rafael J. Wysocki
  2013-01-04 22:01 ` [PATCH 2/6] ACPI / PM: More visible function for retrieving device power states Rafael J. Wysocki
@ 2013-01-04 22:02 ` Rafael J. Wysocki
  2013-01-04 22:03 ` [PATCH 4/6] ACPI / PM: Export power states of ACPI devices via sysfs Rafael J. Wysocki
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-04 22:02 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Lv Zheng, Huang Ying

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

The function returning string representations of ACPI device power
states, state_string((), is now static, because it is only used
internally in drivers/acpi/bus.c.  However, it will be used outside
of that file going forward, so rename it to
acpi_power_state_string(), add a kerneldoc comment to it and add its
header to acpi_bus.h.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/bus.c      |   18 ++++++++++++------
 include/acpi/acpi_bus.h |    1 +
 2 files changed, 13 insertions(+), 6 deletions(-)

Index: linux/drivers/acpi/bus.c
===================================================================
--- linux.orig/drivers/acpi/bus.c
+++ linux/drivers/acpi/bus.c
@@ -182,7 +182,11 @@ EXPORT_SYMBOL(acpi_bus_get_private_data)
                                  Power Management
    -------------------------------------------------------------------------- */
 
-static const char *state_string(int state)
+/**
+ * acpi_power_state_string - String representation of ACPI device power state.
+ * @state: ACPI device power state to return the string representation of.
+ */
+const char *acpi_power_state_string(int state)
 {
 	switch (state) {
 	case ACPI_STATE_D0:
@@ -260,7 +264,7 @@ int acpi_device_get_power(struct acpi_de
 
  out:
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
-			  device->pnp.bus_id, state_string(*state)));
+			  device->pnp.bus_id, acpi_power_state_string(*state)));
 
 	return 0;
 }
@@ -288,13 +292,13 @@ int acpi_device_set_power(struct acpi_de
 
 	if (state == device->power.state) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
-				  state_string(state)));
+				  acpi_power_state_string(state)));
 		return 0;
 	}
 
 	if (!device->power.states[state].flags.valid) {
 		printk(KERN_WARNING PREFIX "Device does not support %s\n",
-		       state_string(state));
+		       acpi_power_state_string(state));
 		return -ENODEV;
 	}
 	if (device->parent && (state < device->parent->power.state)) {
@@ -362,12 +366,14 @@ int acpi_device_set_power(struct acpi_de
 	if (result)
 		printk(KERN_WARNING PREFIX
 			      "Device [%s] failed to transition to %s\n",
-			      device->pnp.bus_id, state_string(state));
+			      device->pnp.bus_id,
+			      acpi_power_state_string(state));
 	else {
 		device->power.state = state;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Device [%s] transitioned to %s\n",
-				  device->pnp.bus_id, state_string(state)));
+				  device->pnp.bus_id,
+				  acpi_power_state_string(state)));
 	}
 
 	return result;
Index: linux/include/acpi/acpi_bus.h
===================================================================
--- linux.orig/include/acpi/acpi_bus.h
+++ linux/include/acpi/acpi_bus.h
@@ -334,6 +334,7 @@ acpi_status acpi_bus_get_status_handle(a
 				       unsigned long long *sta);
 int acpi_bus_get_status(struct acpi_device *device);
 int acpi_bus_set_power(acpi_handle handle, int state);
+const char *acpi_power_state_string(int state);
 int acpi_device_get_power(struct acpi_device *device, int *state);
 int acpi_device_set_power(struct acpi_device *device, int state);
 int acpi_bus_update_power(acpi_handle handle, int *state_p);


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

* [PATCH 4/6] ACPI / PM: Export power states of ACPI devices via sysfs
  2013-01-04 21:58 [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
                   ` (2 preceding siblings ...)
  2013-01-04 22:02 ` [PATCH 3/6] ACPI / PM: Common string representations of " Rafael J. Wysocki
@ 2013-01-04 22:03 ` Rafael J. Wysocki
  2013-01-19 20:53   ` [Update][PATCH] " Rafael J. Wysocki
  2013-01-04 22:03 ` [PATCH 5/6] ACPI / PM: Move device power management functions to device_pm.c Rafael J. Wysocki
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-04 22:03 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Lv Zheng, Huang Ying

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

Make it possible to retrieve the current power state of an ACPI
device from user space via sysfs by adding a new attribute
power_state to the power subdirectory of the sysfs directory
associated with the struct acpi_device representing the device's
ACPI node.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 Documentation/ABI/testing/sysfs-devices-power |   13 ++++++++
 drivers/acpi/scan.c                           |   41 ++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)

Index: linux/drivers/acpi/scan.c
===================================================================
--- linux.orig/drivers/acpi/scan.c
+++ linux/drivers/acpi/scan.c
@@ -184,6 +184,43 @@ err_out:
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
+#ifdef CONFIG_PM
+static ssize_t power_state_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(dev);
+	int state;
+	int ret;
+
+	ret = acpi_device_get_power(adev, &state);
+	return ret ? ret : sprintf(buf, "%s\n", acpi_power_state_string(state));
+}
+
+static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
+
+static struct attribute *acpi_dev_pm_attrs[] = {
+	&dev_attr_power_state.attr,
+	NULL,
+};
+static struct attribute_group acpi_dev_pm_attr_group = {
+	.name	= power_group_name,
+	.attrs	= acpi_dev_pm_attrs,
+};
+
+static void acpi_dev_pm_sysfs_add(struct device *dev)
+{
+	sysfs_merge_group(&dev->kobj, &acpi_dev_pm_attr_group);
+}
+
+static void acpi_dev_pm_sysfs_remove(struct device *dev)
+{
+	sysfs_unmerge_group(&dev->kobj, &acpi_dev_pm_attr_group);
+}
+#else /* !CONFIG_PM */
+static inline void acpi_dev_pm_sysfs_add(struct device *dev) {}
+static inline void acpi_dev_pm_sysfs_remove(struct device *dev) {}
+#endif /* !CONFIG_PM */
+
 static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
@@ -377,6 +414,9 @@ static int acpi_device_setup_files(struc
 	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
 	if (ACPI_SUCCESS(status))
 		result = device_create_file(&dev->dev, &dev_attr_eject);
+
+	acpi_dev_pm_sysfs_add(&dev->dev);
+
 end:
 	return result;
 }
@@ -386,6 +426,7 @@ static void acpi_device_remove_files(str
 	acpi_status status;
 	acpi_handle temp;
 
+	acpi_dev_pm_sysfs_remove(&dev->dev);
 	/*
 	 * If device has _STR, remove 'description' file
 	 */
Index: linux/Documentation/ABI/testing/sysfs-devices-power
===================================================================
--- linux.orig/Documentation/ABI/testing/sysfs-devices-power
+++ linux/Documentation/ABI/testing/sysfs-devices-power
@@ -235,3 +235,16 @@ Description:
 
 		This attribute has no effect on system-wide suspend/resume and
 		hibernation.
+
+What:		/sys/devices/.../power/power_state
+Date:		December 2012
+Contact:	Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+		The /sys/devices/.../power/power_state attribute is only present
+		for ACPI device nodes (i.e. objects of type struct acpi_device).
+
+		If present, it contains the string representation of the current
+		ACPI power state of the device represented by the given ACPI
+		device node.
+
+		This attribute is read-only.


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

* [PATCH 5/6] ACPI / PM: Move device power management functions to device_pm.c
  2013-01-04 21:58 [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
                   ` (3 preceding siblings ...)
  2013-01-04 22:03 ` [PATCH 4/6] ACPI / PM: Export power states of ACPI devices via sysfs Rafael J. Wysocki
@ 2013-01-04 22:03 ` Rafael J. Wysocki
  2013-01-04 22:04 ` [PATCH 6/6] ACPI / PM: Consolidate suspend-specific and hibernate-specific code Rafael J. Wysocki
  2013-01-11 21:59 ` [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
  6 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-04 22:03 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Lv Zheng, Huang Ying

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

Move ACPI device power management functions from drivers/acpi/bus.c
to drivers/acpi/device_pm.c.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/bus.c       |  293 -----------------------------------------------
 drivers/acpi/device_pm.c |  288 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/internal.h  |    1 
 include/acpi/acpi_bus.h  |   38 ++++++
 4 files changed, 326 insertions(+), 294 deletions(-)

Index: linux/drivers/acpi/device_pm.c
===================================================================
--- linux.orig/drivers/acpi/device_pm.c
+++ linux/drivers/acpi/device_pm.c
@@ -30,6 +30,12 @@
 
 #include <acpi/acpi.h>
 #include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#include "internal.h"
+
+#define _COMPONENT	ACPI_POWER_COMPONENT
+ACPI_MODULE_NAME("device_pm");
 
 static DEFINE_MUTEX(acpi_pm_notifier_lock);
 
@@ -94,6 +100,288 @@ acpi_status acpi_remove_pm_notifier(stru
 }
 
 /**
+ * acpi_power_state_string - String representation of ACPI device power state.
+ * @state: ACPI device power state to return the string representation of.
+ */
+const char *acpi_power_state_string(int state)
+{
+	switch (state) {
+	case ACPI_STATE_D0:
+		return "D0";
+	case ACPI_STATE_D1:
+		return "D1";
+	case ACPI_STATE_D2:
+		return "D2";
+	case ACPI_STATE_D3_HOT:
+		return "D3hot";
+	case ACPI_STATE_D3_COLD:
+		return "D3";
+	default:
+		return "(unknown)";
+	}
+}
+
+/**
+ * acpi_device_get_power - Get power state of an ACPI device.
+ * @device: Device to get the power state of.
+ * @state: Place to store the power state of the device.
+ *
+ * This function does not update the device's power.state field, but it may
+ * update its parent's power.state field (when the parent's power state is
+ * unknown and the device's power state turns out to be D0).
+ */
+int acpi_device_get_power(struct acpi_device *device, int *state)
+{
+	int result = ACPI_STATE_UNKNOWN;
+
+	if (!device || !state)
+		return -EINVAL;
+
+	if (!device->flags.power_manageable) {
+		/* TBD: Non-recursive algorithm for walking up hierarchy. */
+		*state = device->parent ?
+			device->parent->power.state : ACPI_STATE_D0;
+		goto out;
+	}
+
+	/*
+	 * Get the device's power state either directly (via _PSC) or
+	 * indirectly (via power resources).
+	 */
+	if (device->power.flags.explicit_get) {
+		unsigned long long psc;
+		acpi_status status = acpi_evaluate_integer(device->handle,
+							   "_PSC", NULL, &psc);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+
+		result = psc;
+	}
+	/* The test below covers ACPI_STATE_UNKNOWN too. */
+	if (result <= ACPI_STATE_D2) {
+	  ; /* Do nothing. */
+	} else if (device->power.flags.power_resources) {
+		int error = acpi_power_get_inferred_state(device, &result);
+		if (error)
+			return error;
+	} else if (result == ACPI_STATE_D3_HOT) {
+		result = ACPI_STATE_D3;
+	}
+
+	/*
+	 * If we were unsure about the device parent's power state up to this
+	 * point, the fact that the device is in D0 implies that the parent has
+	 * to be in D0 too.
+	 */
+	if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
+	    && result == ACPI_STATE_D0)
+		device->parent->power.state = ACPI_STATE_D0;
+
+	*state = result;
+
+ out:
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
+			  device->pnp.bus_id, acpi_power_state_string(*state)));
+
+	return 0;
+}
+
+/**
+ * acpi_device_set_power - Set power state of an ACPI device.
+ * @device: Device to set the power state of.
+ * @state: New power state to set.
+ *
+ * Callers must ensure that the device is power manageable before using this
+ * function.
+ */
+int acpi_device_set_power(struct acpi_device *device, int state)
+{
+	int result = 0;
+	acpi_status status = AE_OK;
+	char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
+	bool cut_power = false;
+
+	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
+		return -EINVAL;
+
+	/* Make sure this is a valid target state */
+
+	if (state == device->power.state) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
+				  acpi_power_state_string(state)));
+		return 0;
+	}
+
+	if (!device->power.states[state].flags.valid) {
+		printk(KERN_WARNING PREFIX "Device does not support %s\n",
+		       acpi_power_state_string(state));
+		return -ENODEV;
+	}
+	if (device->parent && (state < device->parent->power.state)) {
+		printk(KERN_WARNING PREFIX
+			      "Cannot set device to a higher-powered"
+			      " state than parent\n");
+		return -ENODEV;
+	}
+
+	/* For D3cold we should first transition into D3hot. */
+	if (state == ACPI_STATE_D3_COLD
+	    && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
+		state = ACPI_STATE_D3_HOT;
+		object_name[3] = '3';
+		cut_power = true;
+	}
+
+	/*
+	 * Transition Power
+	 * ----------------
+	 * On transitions to a high-powered state we first apply power (via
+	 * power resources) then evalute _PSx.  Conversly for transitions to
+	 * a lower-powered state.
+	 */
+	if (state < device->power.state) {
+		if (device->power.state >= ACPI_STATE_D3_HOT &&
+		    state != ACPI_STATE_D0) {
+			printk(KERN_WARNING PREFIX
+			      "Cannot transition to non-D0 state from D3\n");
+			return -ENODEV;
+		}
+		if (device->power.flags.power_resources) {
+			result = acpi_power_transition(device, state);
+			if (result)
+				goto end;
+		}
+		if (device->power.states[state].flags.explicit_set) {
+			status = acpi_evaluate_object(device->handle,
+						      object_name, NULL, NULL);
+			if (ACPI_FAILURE(status)) {
+				result = -ENODEV;
+				goto end;
+			}
+		}
+	} else {
+		if (device->power.states[state].flags.explicit_set) {
+			status = acpi_evaluate_object(device->handle,
+						      object_name, NULL, NULL);
+			if (ACPI_FAILURE(status)) {
+				result = -ENODEV;
+				goto end;
+			}
+		}
+		if (device->power.flags.power_resources) {
+			result = acpi_power_transition(device, state);
+			if (result)
+				goto end;
+		}
+	}
+
+	if (cut_power)
+		result = acpi_power_transition(device, ACPI_STATE_D3_COLD);
+
+      end:
+	if (result)
+		printk(KERN_WARNING PREFIX
+			      "Device [%s] failed to transition to %s\n",
+			      device->pnp.bus_id,
+			      acpi_power_state_string(state));
+	else {
+		device->power.state = state;
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Device [%s] transitioned to %s\n",
+				  device->pnp.bus_id,
+				  acpi_power_state_string(state)));
+	}
+
+	return result;
+}
+EXPORT_SYMBOL(acpi_device_set_power);
+
+int acpi_bus_set_power(acpi_handle handle, int state)
+{
+	struct acpi_device *device;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	if (result)
+		return result;
+
+	if (!device->flags.power_manageable) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				"Device [%s] is not power manageable\n",
+				dev_name(&device->dev)));
+		return -ENODEV;
+	}
+
+	return acpi_device_set_power(device, state);
+}
+EXPORT_SYMBOL(acpi_bus_set_power);
+
+int acpi_bus_init_power(struct acpi_device *device)
+{
+	int state;
+	int result;
+
+	if (!device)
+		return -EINVAL;
+
+	device->power.state = ACPI_STATE_UNKNOWN;
+
+	result = acpi_device_get_power(device, &state);
+	if (result)
+		return result;
+
+	if (device->power.flags.power_resources)
+		result = acpi_power_on_resources(device, state);
+
+	if (!result)
+		device->power.state = state;
+
+	return result;
+}
+
+int acpi_bus_update_power(acpi_handle handle, int *state_p)
+{
+	struct acpi_device *device;
+	int state;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	if (result)
+		return result;
+
+	result = acpi_device_get_power(device, &state);
+	if (result)
+		return result;
+
+	result = acpi_device_set_power(device, state);
+	if (!result && state_p)
+		*state_p = state;
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_update_power);
+
+bool acpi_bus_power_manageable(acpi_handle handle)
+{
+	struct acpi_device *device;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	return result ? false : device->flags.power_manageable;
+}
+EXPORT_SYMBOL(acpi_bus_power_manageable);
+
+bool acpi_bus_can_wakeup(acpi_handle handle)
+{
+	struct acpi_device *device;
+	int result;
+
+	result = acpi_bus_get_device(handle, &device);
+	return result ? false : device->wakeup.flags.valid;
+}
+EXPORT_SYMBOL(acpi_bus_can_wakeup);
+
+/**
  * acpi_device_power_state - Get preferred power state of ACPI device.
  * @dev: Device whose preferred target power state to return.
  * @adev: ACPI device node corresponding to @dev.
Index: linux/include/acpi/acpi_bus.h
===================================================================
--- linux.orig/include/acpi/acpi_bus.h
+++ linux/include/acpi/acpi_bus.h
@@ -333,13 +333,51 @@ void acpi_bus_data_handler(acpi_handle h
 acpi_status acpi_bus_get_status_handle(acpi_handle handle,
 				       unsigned long long *sta);
 int acpi_bus_get_status(struct acpi_device *device);
+
+#ifdef CONFIG_PM
 int acpi_bus_set_power(acpi_handle handle, int state);
 const char *acpi_power_state_string(int state);
 int acpi_device_get_power(struct acpi_device *device, int *state);
 int acpi_device_set_power(struct acpi_device *device, int state);
+int acpi_bus_init_power(struct acpi_device *device);
 int acpi_bus_update_power(acpi_handle handle, int *state_p);
 bool acpi_bus_power_manageable(acpi_handle handle);
 bool acpi_bus_can_wakeup(acpi_handle handle);
+#else /* !CONFIG_PM */
+static inline int acpi_bus_set_power(acpi_handle handle, int state)
+{
+	return 0;
+}
+static inline const char *acpi_power_state_string(int state)
+{
+	return "D0";
+}
+static inline int acpi_device_get_power(struct acpi_device *device, int *state)
+{
+	return 0;
+}
+static inline int acpi_device_set_power(struct acpi_device *device, int state)
+{
+	return 0;
+}
+static inline int acpi_bus_init_power(struct acpi_device *device)
+{
+	return 0;
+}
+static inline int acpi_bus_update_power(acpi_handle handle, int *state_p)
+{
+	return 0;
+}
+static inline bool acpi_bus_power_manageable(acpi_handle handle)
+{
+	return false;
+}
+static inline bool acpi_bus_can_wakeup(acpi_handle handle)
+{
+	return false;
+}
+#endif /* !CONFIG_PM */
+
 #ifdef CONFIG_ACPI_PROC_EVENT
 int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data);
 int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data);
Index: linux/drivers/acpi/internal.h
===================================================================
--- linux.orig/drivers/acpi/internal.h
+++ linux/drivers/acpi/internal.h
@@ -61,7 +61,6 @@ int acpi_device_sleep_wake(struct acpi_d
 int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
 int acpi_power_on_resources(struct acpi_device *device, int state);
 int acpi_power_transition(struct acpi_device *device, int state);
-int acpi_bus_init_power(struct acpi_device *device);
 
 int acpi_wakeup_device_init(void);
 void acpi_early_processor_set_pdc(void);
Index: linux/drivers/acpi/bus.c
===================================================================
--- linux.orig/drivers/acpi/bus.c
+++ linux/drivers/acpi/bus.c
@@ -178,299 +178,6 @@ int acpi_bus_get_private_data(acpi_handl
 }
 EXPORT_SYMBOL(acpi_bus_get_private_data);
 
-/* --------------------------------------------------------------------------
-                                 Power Management
-   -------------------------------------------------------------------------- */
-
-/**
- * acpi_power_state_string - String representation of ACPI device power state.
- * @state: ACPI device power state to return the string representation of.
- */
-const char *acpi_power_state_string(int state)
-{
-	switch (state) {
-	case ACPI_STATE_D0:
-		return "D0";
-	case ACPI_STATE_D1:
-		return "D1";
-	case ACPI_STATE_D2:
-		return "D2";
-	case ACPI_STATE_D3_HOT:
-		return "D3hot";
-	case ACPI_STATE_D3_COLD:
-		return "D3";
-	default:
-		return "(unknown)";
-	}
-}
-
-/**
- * acpi_device_get_power - Get power state of an ACPI device.
- * @device: Device to get the power state of.
- * @state: Place to store the power state of the device.
- *
- * This function does not update the device's power.state field, but it may
- * update its parent's power.state field (when the parent's power state is
- * unknown and the device's power state turns out to be D0).
- */
-int acpi_device_get_power(struct acpi_device *device, int *state)
-{
-	int result = ACPI_STATE_UNKNOWN;
-
-	if (!device || !state)
-		return -EINVAL;
-
-	if (!device->flags.power_manageable) {
-		/* TBD: Non-recursive algorithm for walking up hierarchy. */
-		*state = device->parent ?
-			device->parent->power.state : ACPI_STATE_D0;
-		goto out;
-	}
-
-	/*
-	 * Get the device's power state either directly (via _PSC) or
-	 * indirectly (via power resources).
-	 */
-	if (device->power.flags.explicit_get) {
-		unsigned long long psc;
-		acpi_status status = acpi_evaluate_integer(device->handle,
-							   "_PSC", NULL, &psc);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-
-		result = psc;
-	}
-	/* The test below covers ACPI_STATE_UNKNOWN too. */
-	if (result <= ACPI_STATE_D2) {
-	  ; /* Do nothing. */
-	} else if (device->power.flags.power_resources) {
-		int error = acpi_power_get_inferred_state(device, &result);
-		if (error)
-			return error;
-	} else if (result == ACPI_STATE_D3_HOT) {
-		result = ACPI_STATE_D3;
-	}
-
-	/*
-	 * If we were unsure about the device parent's power state up to this
-	 * point, the fact that the device is in D0 implies that the parent has
-	 * to be in D0 too.
-	 */
-	if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
-	    && result == ACPI_STATE_D0)
-		device->parent->power.state = ACPI_STATE_D0;
-
-	*state = result;
-
- out:
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n",
-			  device->pnp.bus_id, acpi_power_state_string(*state)));
-
-	return 0;
-}
-
-
-/**
- * acpi_device_set_power - Set power state of an ACPI device.
- * @device: Device to set the power state of.
- * @state: New power state to set.
- *
- * Callers must ensure that the device is power manageable before using this
- * function.
- */
-int acpi_device_set_power(struct acpi_device *device, int state)
-{
-	int result = 0;
-	acpi_status status = AE_OK;
-	char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
-	bool cut_power = false;
-
-	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
-		return -EINVAL;
-
-	/* Make sure this is a valid target state */
-
-	if (state == device->power.state) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
-				  acpi_power_state_string(state)));
-		return 0;
-	}
-
-	if (!device->power.states[state].flags.valid) {
-		printk(KERN_WARNING PREFIX "Device does not support %s\n",
-		       acpi_power_state_string(state));
-		return -ENODEV;
-	}
-	if (device->parent && (state < device->parent->power.state)) {
-		printk(KERN_WARNING PREFIX
-			      "Cannot set device to a higher-powered"
-			      " state than parent\n");
-		return -ENODEV;
-	}
-
-	/* For D3cold we should first transition into D3hot. */
-	if (state == ACPI_STATE_D3_COLD
-	    && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
-		state = ACPI_STATE_D3_HOT;
-		object_name[3] = '3';
-		cut_power = true;
-	}
-
-	/*
-	 * Transition Power
-	 * ----------------
-	 * On transitions to a high-powered state we first apply power (via
-	 * power resources) then evalute _PSx.  Conversly for transitions to
-	 * a lower-powered state.
-	 */
-	if (state < device->power.state) {
-		if (device->power.state >= ACPI_STATE_D3_HOT &&
-		    state != ACPI_STATE_D0) {
-			printk(KERN_WARNING PREFIX
-			      "Cannot transition to non-D0 state from D3\n");
-			return -ENODEV;
-		}
-		if (device->power.flags.power_resources) {
-			result = acpi_power_transition(device, state);
-			if (result)
-				goto end;
-		}
-		if (device->power.states[state].flags.explicit_set) {
-			status = acpi_evaluate_object(device->handle,
-						      object_name, NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				result = -ENODEV;
-				goto end;
-			}
-		}
-	} else {
-		if (device->power.states[state].flags.explicit_set) {
-			status = acpi_evaluate_object(device->handle,
-						      object_name, NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				result = -ENODEV;
-				goto end;
-			}
-		}
-		if (device->power.flags.power_resources) {
-			result = acpi_power_transition(device, state);
-			if (result)
-				goto end;
-		}
-	}
-
-	if (cut_power)
-		result = acpi_power_transition(device, ACPI_STATE_D3_COLD);
-
-      end:
-	if (result)
-		printk(KERN_WARNING PREFIX
-			      "Device [%s] failed to transition to %s\n",
-			      device->pnp.bus_id,
-			      acpi_power_state_string(state));
-	else {
-		device->power.state = state;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Device [%s] transitioned to %s\n",
-				  device->pnp.bus_id,
-				  acpi_power_state_string(state)));
-	}
-
-	return result;
-}
-EXPORT_SYMBOL(acpi_device_set_power);
-
-
-int acpi_bus_set_power(acpi_handle handle, int state)
-{
-	struct acpi_device *device;
-	int result;
-
-	result = acpi_bus_get_device(handle, &device);
-	if (result)
-		return result;
-
-	if (!device->flags.power_manageable) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				"Device [%s] is not power manageable\n",
-				dev_name(&device->dev)));
-		return -ENODEV;
-	}
-
-	return acpi_device_set_power(device, state);
-}
-EXPORT_SYMBOL(acpi_bus_set_power);
-
-
-int acpi_bus_init_power(struct acpi_device *device)
-{
-	int state;
-	int result;
-
-	if (!device)
-		return -EINVAL;
-
-	device->power.state = ACPI_STATE_UNKNOWN;
-
-	result = acpi_device_get_power(device, &state);
-	if (result)
-		return result;
-
-	if (device->power.flags.power_resources)
-		result = acpi_power_on_resources(device, state);
-
-	if (!result)
-		device->power.state = state;
-
-	return result;
-}
-
-
-int acpi_bus_update_power(acpi_handle handle, int *state_p)
-{
-	struct acpi_device *device;
-	int state;
-	int result;
-
-	result = acpi_bus_get_device(handle, &device);
-	if (result)
-		return result;
-
-	result = acpi_device_get_power(device, &state);
-	if (result)
-		return result;
-
-	result = acpi_device_set_power(device, state);
-	if (!result && state_p)
-		*state_p = state;
-
-	return result;
-}
-EXPORT_SYMBOL_GPL(acpi_bus_update_power);
-
-
-bool acpi_bus_power_manageable(acpi_handle handle)
-{
-	struct acpi_device *device;
-	int result;
-
-	result = acpi_bus_get_device(handle, &device);
-	return result ? false : device->flags.power_manageable;
-}
-
-EXPORT_SYMBOL(acpi_bus_power_manageable);
-
-bool acpi_bus_can_wakeup(acpi_handle handle)
-{
-	struct acpi_device *device;
-	int result;
-
-	result = acpi_bus_get_device(handle, &device);
-	return result ? false : device->wakeup.flags.valid;
-}
-
-EXPORT_SYMBOL(acpi_bus_can_wakeup);
-
 static void acpi_print_osc_error(acpi_handle handle,
 	struct acpi_osc_context *context, char *error)
 {


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

* [PATCH 6/6] ACPI / PM: Consolidate suspend-specific and hibernate-specific code
  2013-01-04 21:58 [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
                   ` (4 preceding siblings ...)
  2013-01-04 22:03 ` [PATCH 5/6] ACPI / PM: Move device power management functions to device_pm.c Rafael J. Wysocki
@ 2013-01-04 22:04 ` Rafael J. Wysocki
  2013-01-11 21:59 ` [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
  6 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-04 22:04 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Lv Zheng, Huang Ying

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

Move some suspend-specific and hibernate-specific code from
acpi_sleep_init() into separate functions to get rid of explicit
#ifdefs in acpi_sleep_init().  Use pr_info() to start and pr_cont()
to continue printing the supported ACPI sleep states line.

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

Index: linux/drivers/acpi/sleep.c
===================================================================
--- linux.orig/drivers/acpi/sleep.c
+++ linux/drivers/acpi/sleep.c
@@ -579,7 +579,28 @@ static const struct platform_suspend_ops
 	.end = acpi_pm_end,
 	.recover = acpi_pm_finish,
 };
-#endif /* CONFIG_SUSPEND */
+
+static void acpi_sleep_suspend_setup(void)
+{
+	int i;
+
+	for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
+		acpi_status status;
+		u8 type_a, type_b;
+
+		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
+		if (ACPI_SUCCESS(status)) {
+			sleep_states[i] = 1;
+			pr_cont(" S%d", i);
+		}
+	}
+
+	suspend_set_ops(old_suspend_ordering ?
+		&acpi_suspend_ops_old : &acpi_suspend_ops);
+}
+#else /* !CONFIG_SUSPEND */
+static inline void acpi_sleep_suspend_setup(void) {}
+#endif /* !CONFIG_SUSPEND */
 
 #ifdef CONFIG_HIBERNATION
 static unsigned long s4_hardware_signature;
@@ -700,7 +721,30 @@ static const struct platform_hibernation
 	.restore_cleanup = acpi_pm_thaw,
 	.recover = acpi_pm_finish,
 };
-#endif /* CONFIG_HIBERNATION */
+
+static void acpi_sleep_hibernate_setup(void)
+{
+	acpi_status status;
+	u8 type_a, type_b;
+
+	status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
+	if (ACPI_FAILURE(status))
+		return;
+
+	hibernation_set_ops(old_suspend_ordering ?
+			&acpi_hibernation_ops_old : &acpi_hibernation_ops);
+	sleep_states[ACPI_STATE_S4] = 1;
+	pr_cont(KERN_CONT " S4");
+	if (nosigcheck)
+		return;
+
+	acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
+	if (facs)
+		s4_hardware_signature = facs->hardware_signature;
+}
+#else /* !CONFIG_HIBERNATION */
+static inline void acpi_sleep_hibernate_setup(void) {}
+#endif /* !CONFIG_HIBERNATION */
 
 int acpi_suspend(u32 acpi_state)
 {
@@ -736,9 +780,6 @@ int __init acpi_sleep_init(void)
 {
 	acpi_status status;
 	u8 type_a, type_b;
-#ifdef CONFIG_SUSPEND
-	int i = 0;
-#endif
 
 	if (acpi_disabled)
 		return 0;
@@ -746,45 +787,19 @@ int __init acpi_sleep_init(void)
 	acpi_sleep_dmi_check();
 
 	sleep_states[ACPI_STATE_S0] = 1;
-	printk(KERN_INFO PREFIX "(supports S0");
-
-#ifdef CONFIG_SUSPEND
-	for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
-		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
-		if (ACPI_SUCCESS(status)) {
-			sleep_states[i] = 1;
-			printk(KERN_CONT " S%d", i);
-		}
-	}
+	pr_info(PREFIX "(supports S0");
 
-	suspend_set_ops(old_suspend_ordering ?
-		&acpi_suspend_ops_old : &acpi_suspend_ops);
-#endif
+	acpi_sleep_suspend_setup();
+	acpi_sleep_hibernate_setup();
 
-#ifdef CONFIG_HIBERNATION
-	status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
-	if (ACPI_SUCCESS(status)) {
-		hibernation_set_ops(old_suspend_ordering ?
-			&acpi_hibernation_ops_old : &acpi_hibernation_ops);
-		sleep_states[ACPI_STATE_S4] = 1;
-		printk(KERN_CONT " S4");
-		if (!nosigcheck) {
-			acpi_get_table(ACPI_SIG_FACS, 1,
-				(struct acpi_table_header **)&facs);
-			if (facs)
-				s4_hardware_signature =
-					facs->hardware_signature;
-		}
-	}
-#endif
 	status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
 	if (ACPI_SUCCESS(status)) {
 		sleep_states[ACPI_STATE_S5] = 1;
-		printk(KERN_CONT " S5");
+		pr_cont(" S5");
 		pm_power_off_prepare = acpi_power_off_prepare;
 		pm_power_off = acpi_power_off;
 	}
-	printk(KERN_CONT ")\n");
+	pr_cont(")\n");
 	/*
 	 * Register the tts_notifier to reboot notifier list so that the _TTS
 	 * object can also be evaluated when the system enters S5.


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

* RE: [PATCH 1/6] ACPI / PM: Change the way power transitions to D3cold are carried out
  2013-01-04 22:00 ` [PATCH 1/6] ACPI / PM: Change the way power transitions to D3cold are carried out Rafael J. Wysocki
@ 2013-01-05  2:37   ` Zheng, Lv
  0 siblings, 0 replies; 13+ messages in thread
From: Zheng, Lv @ 2013-01-05  2:37 UTC (permalink / raw)
  To: Rafael J. Wysocki, ACPI Devel Maling List
  Cc: LKML, Len Brown, Huang, Ying, Cheng, Anton, Palanisamy, Kanda K,
	Gough, Robert, Weyhing, Linda, Kalowsky, Daniel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4078 bytes --]

Thanks for your patch, it might be useful as_PR3 off method of I2C hosts and targets might be different from their _PR0 off method, ACPI BIOS may implement protection in the _PR3 off method in order not to break the transactions during the powering off process:
As I2C is wired-AND logic bus, if a device will be LOW on SDA or SCL during the powering off process, it will pull the bus from HIGH to LOW which may break the current transaction on the bus that targeted to another slave device.

I just wonder one more thing which is not related to the ACPI BIOS.
If busses like I2C have such "non-hotpluggable" nature, we need to cut power of single target device only when there are not any transactions visible in the same segment.

How could an equivalent solution be implemented in the Linux kernel for I2C busses?
It could be useful for those platforms without such firmware deployed to protect the OS.

It seems we may need to redesign acpi_device_set_power/acpi_device_power_state to meet the following requirements:
1. suspend/resume -> One function can be used to switch device power state from 0 to 3 or 3 to 0.
2. poweroff -> One function can be used to cut device power currently applied.
And we may need new interface in the power core as "poweroff" (maybe also poweron) or likewise for platform_suspend/hibernate_ops.

Then I2C in the kernel can also implement a solution putting all of the devices (the masters and all of their slaves) in one segment (where there is wired-AND logic) into D3 (suspend all non-hotpluggable devices in one segment), and "poweroff" one of them when there are not any transactions visible on the bus.

Thanks and best regards
-Lv

> -----Original Message-----
> From: Rafael J. Wysocki [mailto:rjw@sisk.pl]
> Sent: Saturday, January 05, 2013 6:00 AM
> To: ACPI Devel Maling List
> Cc: LKML; Len Brown; Zheng, Lv; Huang, Ying
> Subject: [PATCH 1/6] ACPI / PM: Change the way power transitions to D3cold
> are carried out
> 
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> During power transitions into D3cold from any shallower power states we are
> supposed to transition the device into D3hot and remove power from it
> afterward, but the current code in acpi_device_set_power() doesn't work this
> way.
> 
> At the same time, though, we need to be careful enough to preserve
> backwards compatibility for systems that don't distinguish between D3hot and
> D3cold (e.g. designed before ACPI 4).
> 
> Modify acpi_device_set_power() so that it works in accordance with the
> expectations in both cases.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/acpi/bus.c |   12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> Index: linux/drivers/acpi/bus.c
> ================================================================
> ===
> --- linux.orig/drivers/acpi/bus.c
> +++ linux/drivers/acpi/bus.c
> @@ -270,6 +270,7 @@ int acpi_device_set_power(struct acpi_de
>  	int result = 0;
>  	acpi_status status = AE_OK;
>  	char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
> +	bool cut_power = false;
> 
>  	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
>  		return -EINVAL;
> @@ -294,9 +295,13 @@ int acpi_device_set_power(struct acpi_de
>  		return -ENODEV;
>  	}
> 
> -	/* For D3cold we should execute _PS3, not _PS4. */
> -	if (state == ACPI_STATE_D3_COLD)
> +	/* For D3cold we should first transition into D3hot. */
> +	if (state == ACPI_STATE_D3_COLD
> +	    &&
> device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
> +		state = ACPI_STATE_D3_HOT;
>  		object_name[3] = '3';
> +		cut_power = true;
> +	}
> 
>  	/*
>  	 * Transition Power
> @@ -341,6 +346,9 @@ int acpi_device_set_power(struct acpi_de
>  		}
>  	}
> 
> +	if (cut_power)
> +		result = acpi_power_transition(device, ACPI_STATE_D3_COLD);
> +
>        end:
>  	if (result)
>  		printk(KERN_WARNING PREFIX

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH 0/6] ACPI / PM: ACPI power management update
  2013-01-04 21:58 [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
                   ` (5 preceding siblings ...)
  2013-01-04 22:04 ` [PATCH 6/6] ACPI / PM: Consolidate suspend-specific and hibernate-specific code Rafael J. Wysocki
@ 2013-01-11 21:59 ` Rafael J. Wysocki
  6 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-11 21:59 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Lv Zheng, Huang Ying

On Friday, January 04, 2013 10:58:41 PM Rafael J. Wysocki wrote:
> Hi All,
> 
> There are a few changes of the ACPI power management code I've gathered
> over the last few weeks.  Some of them are just cleanups etc., but some
> fix (potential) problems and/or add new functionality.
> 
> [1/6] - Rework power states changing so that we put devices into D3hot
>         (if available) before removing power from them entirely.
> [2/6] - Rename __acpi_bus_get_power() (for future use).
> [3/6] - Rename state_string() (in bus.c, for future use).
> [4/6] - Export the (current) power states of ACPI devices via sysfs.
> [5/6] - Move device power management functions from bus.c to device_pm.c.
> [6/6] - (Unrelated to the above) Get rid of some ugly #ifdefs in sleep.c.
> 
> All of them except for [1/6] have been posted already and no one has had any
> comments.
> 
> Please review.

OK, I don't see any objections, so I'm taking it into linux-next for v3.9.

Thanks,
Rafael


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

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

* [Update][PATCH] ACPI / PM: Export power states of ACPI devices via sysfs
  2013-01-04 22:03 ` [PATCH 4/6] ACPI / PM: Export power states of ACPI devices via sysfs Rafael J. Wysocki
@ 2013-01-19 20:53   ` Rafael J. Wysocki
  2013-01-21 12:59     ` Rafael J. Wysocki
  0 siblings, 1 reply; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-19 20:53 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Kristen C. Accardi

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Subject: ACPI / PM: Export power states of ACPI devices via sysfs

Make it possible to retrieve the current power state of a device with
ACPI power management from user space via sysfs by adding a new
attribute power_state to the sysfs directory associated with the
struct acpi_device object representing the device's ACPI node.

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

I've changed my mind here.  It looks like it's more convenient to put the
power_state attribute directly into the ACPI device node's directory in sysfs
rather than into its power subdirectory.

Thanks,
Rafael

---
 Documentation/ABI/testing/sysfs-devices-power |   13 +++++++++++++
 drivers/acpi/scan.c                           |   25 ++++++++++++++++++++++++-
 2 files changed, 37 insertions(+), 1 deletion(-)

Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -184,6 +184,19 @@ err_out:
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
+static ssize_t power_state_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct acpi_device *adev = to_acpi_device(dev);
+	int state;
+	int ret;
+
+	ret = acpi_device_get_power(adev, &state);
+	return ret ? ret : sprintf(buf, "%s\n", acpi_power_state_string(state));
+}
+
+static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
+
 static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
@@ -375,8 +388,15 @@ static int acpi_device_setup_files(struc
          * hot-removal function from userland.
          */
 	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-	if (ACPI_SUCCESS(status))
+	if (ACPI_SUCCESS(status)) {
 		result = device_create_file(&dev->dev, &dev_attr_eject);
+		if (result)
+			goto end;
+	}
+
+	if (dev->flags.power_manageable)
+		result = device_create_file(&dev->dev, &dev_attr_power_state);
+
 end:
 	return result;
 }
@@ -386,6 +406,9 @@ static void acpi_device_remove_files(str
 	acpi_status status;
 	acpi_handle temp;
 
+	if (dev->flags.power_manageable)
+		device_remove_file(&dev->dev, &dev_attr_power_state);
+
 	/*
 	 * If device has _STR, remove 'description' file
 	 */


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

* Re: [Update][PATCH] ACPI / PM: Export power states of ACPI devices via sysfs
  2013-01-19 20:53   ` [Update][PATCH] " Rafael J. Wysocki
@ 2013-01-21 12:59     ` Rafael J. Wysocki
  0 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-21 12:59 UTC (permalink / raw)
  To: ACPI Devel Maling List; +Cc: LKML, Len Brown, Kristen C. Accardi

On Saturday, January 19, 2013 09:53:32 PM Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Subject: ACPI / PM: Export power states of ACPI devices via sysfs
> 
> Make it possible to retrieve the current power state of a device with
> ACPI power management from user space via sysfs by adding a new
> attribute power_state to the sysfs directory associated with the
> struct acpi_device object representing the device's ACPI node.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> 
> I've changed my mind here.  It looks like it's more convenient to put the
> power_state attribute directly into the ACPI device node's directory in sysfs
> rather than into its power subdirectory.

Well, please scratch this, I'm dropping it for now.

I'll send a new version shortly along with the patches that export power
resources information.

Thanks,
Rafael


> ---
>  Documentation/ABI/testing/sysfs-devices-power |   13 +++++++++++++
>  drivers/acpi/scan.c                           |   25 ++++++++++++++++++++++++-
>  2 files changed, 37 insertions(+), 1 deletion(-)
> 
> Index: linux-pm/drivers/acpi/scan.c
> ===================================================================
> --- linux-pm.orig/drivers/acpi/scan.c
> +++ linux-pm/drivers/acpi/scan.c
> @@ -184,6 +184,19 @@ err_out:
>  }
>  EXPORT_SYMBOL(acpi_bus_hot_remove_device);
>  
> +static ssize_t power_state_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct acpi_device *adev = to_acpi_device(dev);
> +	int state;
> +	int ret;
> +
> +	ret = acpi_device_get_power(adev, &state);
> +	return ret ? ret : sprintf(buf, "%s\n", acpi_power_state_string(state));
> +}
> +
> +static DEVICE_ATTR(power_state, 0444, power_state_show, NULL);
> +
>  static ssize_t
>  acpi_eject_store(struct device *d, struct device_attribute *attr,
>  		const char *buf, size_t count)
> @@ -375,8 +388,15 @@ static int acpi_device_setup_files(struc
>           * hot-removal function from userland.
>           */
>  	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
> -	if (ACPI_SUCCESS(status))
> +	if (ACPI_SUCCESS(status)) {
>  		result = device_create_file(&dev->dev, &dev_attr_eject);
> +		if (result)
> +			goto end;
> +	}
> +
> +	if (dev->flags.power_manageable)
> +		result = device_create_file(&dev->dev, &dev_attr_power_state);
> +
>  end:
>  	return result;
>  }
> @@ -386,6 +406,9 @@ static void acpi_device_remove_files(str
>  	acpi_status status;
>  	acpi_handle temp;
>  
> +	if (dev->flags.power_manageable)
> +		device_remove_file(&dev->dev, &dev_attr_power_state);
> +
>  	/*
>  	 * If device has _STR, remove 'description' file
>  	 */
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

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

* Re: [PATCH 0/6] ACPI / PM: ACPI power management update
  2013-01-05  9:31 Sedat Dilek
@ 2013-01-05 21:59 ` Rafael J. Wysocki
  0 siblings, 0 replies; 13+ messages in thread
From: Rafael J. Wysocki @ 2013-01-05 21:59 UTC (permalink / raw)
  To: sedat.dilek; +Cc: LKML, Linux ACPI

On Saturday, January 05, 2013 10:31:11 AM Sedat Dilek wrote:
> Hi Rafael,
> 
> against which Linux-kernel version is your patchset?
> Linux v3.8-rc2?
> Mambo number 5 [1] aka patch 5/6 does not apply cleanly.

Oh, I didn't say, sorry about that.

It is on top of the linux-next branch of the linux-pm.git tree with the
additional patchset at https://lkml.org/lkml/2013/1/3/460 applied.

Thanks,
Rafael


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

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

* Re: [PATCH 0/6] ACPI / PM: ACPI power management update
@ 2013-01-05  9:31 Sedat Dilek
  2013-01-05 21:59 ` Rafael J. Wysocki
  0 siblings, 1 reply; 13+ messages in thread
From: Sedat Dilek @ 2013-01-05  9:31 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: LKML, Linux ACPI

Hi Rafael,

against which Linux-kernel version is your patchset?
Linux v3.8-rc2?
Mambo number 5 [1] aka patch 5/6 does not apply cleanly.

Regards,
- Sedat -

[1] http://www.youtube.com/watch?v=QQ4Ht5xfD5E

P.S.: GIT AM and APPLY sessions

GIT AM...

wearefam@fambox:~/src/linux-kernel/linux$ git checkout Linux-v3.8-rc2
Already on 'Linux-v3.8-rc2'
wearefam@fambox:~/src/linux-kernel/linux$
wearefam@fambox:~/src/linux-kernel/linux$
wearefam@fambox:~/src/linux-kernel/linux$ GIT_BRANCH="acpi-pm-fixes" ;
git branch $GIT_BRANCH && git checkout $GIT_BRANCH
Switched to branch 'acpi-pm-fixes'
wearefam@fambox:~/src/linux-kernel/linux$
wearefam@fambox:~/src/linux-kernel/linux$ git am
../patches/acpi-pm-fixes/1-6-ACPI-PM-Change-the-way-power-transitions-to-D3cold-are-carried-out.patch
Applying: ACPI / PM: Change the way power transitions to D3cold are carried out
wearefam@fambox:~/src/linux-kernel/linux$
wearefam@fambox:~/src/linux-kernel/linux$ git am
../patches/acpi-pm-fixes/2-6-ACPI-PM-More-visible-function-for-retrieving-device-power-states.patch
Applying: ACPI / PM: More visible function for retrieving device power states
wearefam@fambox:~/src/linux-kernel/linux$
wearefam@fambox:~/src/linux-kernel/linux$ git am
../patches/acpi-pm-fixes/3-6-ACPI-PM-Common-string-representations-of-device-power-states.patch
Applying: ACPI / PM: Common string representations of device power states
wearefam@fambox:~/src/linux-kernel/linux$
wearefam@fambox:~/src/linux-kernel/linux$ git am
../patches/acpi-pm-fixes/4-6-ACPI-PM-Export-power-states-of-ACPI-devices-via-sysfs.patch
Applying: ACPI / PM: Export power states of ACPI devices via sysfs
wearefam@fambox:~/src/linux-kernel/linux$
wearefam@fambox:~/src/linux-kernel/linux$ git am
../patches/acpi-pm-fixes/5-6-ACPI-PM-Move-device-power-management-functions-to-device_pm.c.patch
Applying: ACPI / PM: Move device power management functions to device_pm.c
error: patch failed: include/acpi/acpi_bus.h:333
error: include/acpi/acpi_bus.h: patch does not apply
Patch failed at 0001 ACPI / PM: Move device power management functions
to device_pm.c
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".

Same with GIT APPLY...

[...]
wearefam@fambox:~/src/linux-kernel/linux$ git apply --check --verbose
../patches/acpi-pm-fixes/5*
Checking patch drivers/acpi/device_pm.c...
Checking patch include/acpi/acpi_bus.h...
error: while searching for:
acpi_status acpi_bus_get_status_handle(acpi_handle handle,
                                       unsigned long long *sta);
int acpi_bus_get_status(struct acpi_device *device);
int acpi_bus_set_power(acpi_handle handle, int state);
const char *acpi_power_state_string(int state);
int acpi_device_get_power(struct acpi_device *device, int *state);
int acpi_device_set_power(struct acpi_device *device, int state);
int acpi_bus_update_power(acpi_handle handle, int *state_p);
bool acpi_bus_power_manageable(acpi_handle handle);
bool acpi_bus_can_wakeup(acpi_handle handle);
#ifdef CONFIG_ACPI_PROC_EVENT
int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data);
int acpi_bus_generate_proc_event4(const char *class, const char *bid,
u8 type, int data);

error: patch failed: include/acpi/acpi_bus.h:333
error: include/acpi/acpi_bus.h: patch does not apply
Checking patch drivers/acpi/internal.h...
Hunk #1 succeeded at 43 (offset -18 lines).
Checking patch drivers/acpi/bus.c...
- EOT-

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

end of thread, other threads:[~2013-01-21 12:53 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-04 21:58 [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
2013-01-04 22:00 ` [PATCH 1/6] ACPI / PM: Change the way power transitions to D3cold are carried out Rafael J. Wysocki
2013-01-05  2:37   ` Zheng, Lv
2013-01-04 22:01 ` [PATCH 2/6] ACPI / PM: More visible function for retrieving device power states Rafael J. Wysocki
2013-01-04 22:02 ` [PATCH 3/6] ACPI / PM: Common string representations of " Rafael J. Wysocki
2013-01-04 22:03 ` [PATCH 4/6] ACPI / PM: Export power states of ACPI devices via sysfs Rafael J. Wysocki
2013-01-19 20:53   ` [Update][PATCH] " Rafael J. Wysocki
2013-01-21 12:59     ` Rafael J. Wysocki
2013-01-04 22:03 ` [PATCH 5/6] ACPI / PM: Move device power management functions to device_pm.c Rafael J. Wysocki
2013-01-04 22:04 ` [PATCH 6/6] ACPI / PM: Consolidate suspend-specific and hibernate-specific code Rafael J. Wysocki
2013-01-11 21:59 ` [PATCH 0/6] ACPI / PM: ACPI power management update Rafael J. Wysocki
2013-01-05  9:31 Sedat Dilek
2013-01-05 21:59 ` Rafael J. Wysocki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).