ACPI / thermal: _TMP and _CRT/_HOT/_PSV/_ACx dependency fix
authorZhang Rui <rui.zhang@intel.com>
Tue, 27 Nov 2012 19:42:11 +0000 (20:42 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 27 Nov 2012 19:42:11 +0000 (20:42 +0100)
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>
drivers/acpi/thermal.c

index 804204d41999d0af951086f25b37a2f7ee783a90..6e8cc16b54c151f3388d57e3325772b2d8db8e53 100644 (file)
@@ -984,6 +984,38 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
        }
 }
 
+/*
+ * On some platforms, the AML code has dependency about
+ * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx.
+ * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after
+ *    /_CRT/_HOT/_PSV/_ACx, or else system will be power off.
+ * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0
+ *    if _TMP has never been evaluated.
+ *
+ * As this dependency is totally transparent to OS, evaluate
+ * all of them once, in the order of _CRT/_HOT/_PSV/_ACx,
+ * _TMP, before they are actually used.
+ */
+static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz)
+{
+       acpi_handle handle = tz->device->handle;
+       unsigned long long value;
+       int i;
+
+       acpi_evaluate_integer(handle, "_CRT", NULL, &value);
+       acpi_evaluate_integer(handle, "_HOT", NULL, &value);
+       acpi_evaluate_integer(handle, "_PSV", NULL, &value);
+       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+               char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
+               acpi_status status;
+
+               status = acpi_evaluate_integer(handle, name, NULL, &value);
+               if (status == AE_NOT_FOUND)
+                       break;
+       }
+       acpi_evaluate_integer(handle, "_TMP", NULL, &value);
+}
+
 static int acpi_thermal_get_info(struct acpi_thermal *tz)
 {
        int result = 0;
@@ -992,6 +1024,8 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
        if (!tz)
                return -EINVAL;
 
+       acpi_thermal_aml_dependency_fix(tz);
+
        /* Get trip points [_CRT, _PSV, etc.] (required) */
        result = acpi_thermal_get_trip_points(tz);
        if (result)