diff options
author | Zhang Rui <rui.zhang@intel.com> | 2012-11-27 14:42:11 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2012-11-27 14:42:11 -0500 |
commit | 261cba2deb7d3bebd180c35d5dbf8961f6e9afc4 (patch) | |
tree | 60a9d395401edc63011f7c1ce7f1ddedb04895df /drivers/acpi/thermal.c | |
parent | 05bce79e6d24ee6eb2beddf0f6314358404d472f (diff) |
ACPI / thermal: _TMP and _CRT/_HOT/_PSV/_ACx dependency fix
On some platforms, _TMP and _CRT/_HOT/_PSV/_ACx have dependency.
And there is no way for OS to detect this dependency.
commit 9bcb8118965ab4631a65ee0726e6518f75cda6c5 shows us a problem
that _TMP must be evaluate after _CRT/_HOT/_PSV/_ACx, or else
firmware will shutdown the system.
But the machine in https://bugzilla.kernel.org/show_bug.cgi?id=43284
shows us that _PSV would return valid value only if _TMP has been
evaluated once.
With this patch, all of the control methods will be evaluated once,
in the _CRT/_HOT/_PSV/_CRT/_TMP order, before they are actually used.
[rjw: Added a local variable for the handle and modified the loop
slightly.]
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Tested-by: katabami <katabami@lavabit.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/thermal.c')
-rw-r--r-- | drivers/acpi/thermal.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 804204d41999..6e8cc16b54c1 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
@@ -984,6 +984,38 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) | |||
984 | } | 984 | } |
985 | } | 985 | } |
986 | 986 | ||
987 | /* | ||
988 | * On some platforms, the AML code has dependency about | ||
989 | * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx. | ||
990 | * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after | ||
991 | * /_CRT/_HOT/_PSV/_ACx, or else system will be power off. | ||
992 | * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0 | ||
993 | * if _TMP has never been evaluated. | ||
994 | * | ||
995 | * As this dependency is totally transparent to OS, evaluate | ||
996 | * all of them once, in the order of _CRT/_HOT/_PSV/_ACx, | ||
997 | * _TMP, before they are actually used. | ||
998 | */ | ||
999 | static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz) | ||
1000 | { | ||
1001 | acpi_handle handle = tz->device->handle; | ||
1002 | unsigned long long value; | ||
1003 | int i; | ||
1004 | |||
1005 | acpi_evaluate_integer(handle, "_CRT", NULL, &value); | ||
1006 | acpi_evaluate_integer(handle, "_HOT", NULL, &value); | ||
1007 | acpi_evaluate_integer(handle, "_PSV", NULL, &value); | ||
1008 | for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { | ||
1009 | char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; | ||
1010 | acpi_status status; | ||
1011 | |||
1012 | status = acpi_evaluate_integer(handle, name, NULL, &value); | ||
1013 | if (status == AE_NOT_FOUND) | ||
1014 | break; | ||
1015 | } | ||
1016 | acpi_evaluate_integer(handle, "_TMP", NULL, &value); | ||
1017 | } | ||
1018 | |||
987 | static int acpi_thermal_get_info(struct acpi_thermal *tz) | 1019 | static int acpi_thermal_get_info(struct acpi_thermal *tz) |
988 | { | 1020 | { |
989 | int result = 0; | 1021 | int result = 0; |
@@ -992,6 +1024,8 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) | |||
992 | if (!tz) | 1024 | if (!tz) |
993 | return -EINVAL; | 1025 | return -EINVAL; |
994 | 1026 | ||
1027 | acpi_thermal_aml_dependency_fix(tz); | ||
1028 | |||
995 | /* Get trip points [_CRT, _PSV, etc.] (required) */ | 1029 | /* Get trip points [_CRT, _PSV, etc.] (required) */ |
996 | result = acpi_thermal_get_trip_points(tz); | 1030 | result = acpi_thermal_get_trip_points(tz); |
997 | if (result) | 1031 | if (result) |