[ 21/38] ACPI / PM: Fix corner case in acpi_bus_update_power()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



3.9-stable review patch.  If anyone has any objections, please let me know.

------------------

From: "Rafael J. Wysocki" <rafael.j.wysocki@xxxxxxxxx>

commit 91bdad0b6237c25a7bf8fd4604d0cc64a2005a23 upstream.

The role of acpi_bus_update_power() is to update the given ACPI
device object's power.state field to reflect the current physical
state of the device (as inferred from the configuration of power
resources and _PSC, if available).  For this purpose it calls
acpi_device_set_power() that should update the power resources'
reference counters and set power.state as appropriate.  However,
that doesn't work if the "new" state is D1, D2 or D3hot and the
the current value of power.state means D3cold, because in that
case acpi_device_set_power() will refuse to transition the device
from D3cold to non-D0.

To address this problem, make acpi_bus_update_power() call
acpi_power_transition() directly to update the power resources'
reference counters and only use acpi_device_set_power() to put
the device into D0 if the current physical state of it cannot
be determined.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
 drivers/acpi/device_pm.c |   23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -295,14 +295,27 @@ int acpi_bus_update_power(acpi_handle ha
 	if (result)
 		return result;
 
-	if (state == ACPI_STATE_UNKNOWN)
+	if (state == ACPI_STATE_UNKNOWN) {
 		state = ACPI_STATE_D0;
-
-	result = acpi_device_set_power(device, state);
-	if (!result && state_p)
+		result = acpi_device_set_power(device, state);
+		if (result)
+			return result;
+	} else {
+		if (device->power.flags.power_resources) {
+			/*
+			 * We don't need to really switch the state, bu we need
+			 * to update the power resources' reference counters.
+			 */
+			result = acpi_power_transition(device, state);
+			if (result)
+				return result;
+		}
+		device->power.state = state;
+	}
+	if (state_p)
 		*state_p = state;
 
-	return result;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(acpi_bus_update_power);
 


--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]