diff options
author | Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> | 2016-10-04 22:51:40 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-10-10 02:20:43 +0200 |
commit | 84baf1725dc532d9746df2d216c1921154767109 (patch) | |
tree | 764c9d49ecfc2d33c5c195b91c2bdaff584ab830 /drivers/acpi/fan.c | |
parent | Linux 4.8 (diff) | |
download | linux-84baf1725dc532d9746df2d216c1921154767109.tar.xz linux-84baf1725dc532d9746df2d216c1921154767109.zip |
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: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/fan.c')
-rw-r--r-- | drivers/acpi/fan.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 384cfc3083e1..6cf4988206f2 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -129,8 +129,18 @@ static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state) control = obj->package.elements[1].integer.value; 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; + } } if (i == fan->fps_count) { dev_dbg(&device->dev, "Invalid control value returned\n"); |