aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2012-11-27 14:42:11 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-27 14:42:11 -0500
commit261cba2deb7d3bebd180c35d5dbf8961f6e9afc4 (patch)
tree60a9d395401edc63011f7c1ce7f1ddedb04895df
parent05bce79e6d24ee6eb2beddf0f6314358404d472f (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>
-rw-r--r--drivers/acpi/thermal.c34
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 */
999static 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
987static int acpi_thermal_get_info(struct acpi_thermal *tz) 1019static 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)