Commit 84baf172 authored by Srinivas Pandruvada's avatar Srinivas Pandruvada Committed by Rafael J. Wysocki

ACPI / fan: Fix error reading cur_state

On some platforms with ACPI4 variable speed fan, reading cur_state from
cooling device returns "invalid value" error. This confuses user space
applications.

This issue occurs as the current driver doesn't take account of
"FineGrainControl" from _FIF(Fan Information). When the "FineGrainControl"
is set, _FSL(FSL Set Level) takes argument as a percent, which doesn't
have to match from any control value from _FPS(Fan Performance States).
It is also possible that the Fan is not actually running at the requested
speed returning a lower speed.
On some platforms the BIOS is setting fan speed to a level during boot,
which will not have an exact match to _FPS control values. The current
implementation will treat this level as invalid value.

The simple change is to atleast return state corresponding to a maximum
control value in the _FPS compared to the current level.
Signed-off-by: default avatarSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent c8d2bc9b
...@@ -129,9 +129,19 @@ static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state) ...@@ -129,9 +129,19 @@ static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
control = obj->package.elements[1].integer.value; control = obj->package.elements[1].integer.value;
for (i = 0; i < fan->fps_count; i++) { for (i = 0; i < fan->fps_count; i++) {
if (control == fan->fps[i].control) /*
* When Fine Grain Control is set, return the state
* corresponding to maximum fan->fps[i].control
* value compared to the current speed. Here the
* fan->fps[] is sorted array with increasing speed.
*/
if (fan->fif.fine_grain_ctrl && control < fan->fps[i].control) {
i = (i > 0) ? i - 1 : 0;
break;
} else if (control == fan->fps[i].control) {
break; break;
} }
}
if (i == fan->fps_count) { if (i == fan->fps_count) {
dev_dbg(&device->dev, "Invalid control value returned\n"); dev_dbg(&device->dev, "Invalid control value returned\n");
status = -EINVAL; status = -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment