Commit 261cba2d authored by Zhang Rui's avatar Zhang Rui Committed by Rafael J. Wysocki
Browse files

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 9bcb8118 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: default avatarZhang Rui <rui.zhang@intel.com>
Tested-by: default avatarkatabami <katabami@lavabit.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 05bce79e
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -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)