diff options
author | Guenter Roeck <linux@roeck-us.net> | 2015-01-12 08:32:00 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-01-25 12:17:58 -0500 |
commit | 564132d9d62b3151dc6573da794378b5bf0cea17 (patch) | |
tree | bfecf5fc4a7f7a9ec0b698e2d8f54976d2fe5245 /drivers/char | |
parent | 83d514d76278e85cc74c472dd51687c8eb4faff0 (diff) |
i8k: Rework error retries
Instead of returning a previous value if the SMM code returns
an error when trying to read a temperature, retry once.
If that fails again, return -ENODATA. Also return -ENODATA if an
attempt is made to read the GPU temperature but the GPU is
currently turned off.
Drop the I8K_TEMPERATURE_BUG definition and handle the related bug
unconditionally.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Pali Rohár <pali.rohar@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/i8k.c | 47 |
1 files changed, 24 insertions, 23 deletions
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 1854faba8ae6..0e332fcd8fc3 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Hwmon integration: | 6 | * Hwmon integration: |
7 | * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de> | 7 | * Copyright (C) 2011 Jean Delvare <jdelvare@suse.de> |
8 | * Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net> | 8 | * Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
11 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
22 | 22 | ||
23 | #include <linux/delay.h> | ||
23 | #include <linux/module.h> | 24 | #include <linux/module.h> |
24 | #include <linux/types.h> | 25 | #include <linux/types.h> |
25 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -59,8 +60,6 @@ | |||
59 | #define I8K_POWER_AC 0x05 | 60 | #define I8K_POWER_AC 0x05 |
60 | #define I8K_POWER_BATTERY 0x01 | 61 | #define I8K_POWER_BATTERY 0x01 |
61 | 62 | ||
62 | #define I8K_TEMPERATURE_BUG 1 | ||
63 | |||
64 | static DEFINE_MUTEX(i8k_mutex); | 63 | static DEFINE_MUTEX(i8k_mutex); |
65 | static char bios_version[4]; | 64 | static char bios_version[4]; |
66 | static struct device *i8k_hwmon_dev; | 65 | static struct device *i8k_hwmon_dev; |
@@ -300,39 +299,41 @@ static int i8k_get_temp_type(int sensor) | |||
300 | /* | 299 | /* |
301 | * Read the cpu temperature. | 300 | * Read the cpu temperature. |
302 | */ | 301 | */ |
303 | static int i8k_get_temp(int sensor) | 302 | static int _i8k_get_temp(int sensor) |
304 | { | 303 | { |
305 | struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, }; | 304 | struct smm_regs regs = { |
306 | int rc; | 305 | .eax = I8K_SMM_GET_TEMP, |
307 | int temp; | 306 | .ebx = sensor & 0xff, |
307 | }; | ||
308 | 308 | ||
309 | #ifdef I8K_TEMPERATURE_BUG | 309 | return i8k_smm(®s) ? : regs.eax & 0xff; |
310 | static int prev[4] = { I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1 }; | 310 | } |
311 | #endif | ||
312 | regs.ebx = sensor & 0xff; | ||
313 | rc = i8k_smm(®s); | ||
314 | if (rc < 0) | ||
315 | return rc; | ||
316 | 311 | ||
317 | temp = regs.eax & 0xff; | 312 | static int i8k_get_temp(int sensor) |
313 | { | ||
314 | int temp = _i8k_get_temp(sensor); | ||
318 | 315 | ||
319 | #ifdef I8K_TEMPERATURE_BUG | ||
320 | /* | 316 | /* |
321 | * Sometimes the temperature sensor returns 0x99, which is out of range. | 317 | * Sometimes the temperature sensor returns 0x99, which is out of range. |
322 | * In this case we return (once) the previous cached value. For example: | 318 | * In this case we retry (once) before returning an error. |
323 | # 1003655137 00000058 00005a4b | 319 | # 1003655137 00000058 00005a4b |
324 | # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees | 320 | # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees |
325 | # 1003655139 00000054 00005c52 | 321 | # 1003655139 00000054 00005c52 |
326 | */ | 322 | */ |
327 | if (temp > I8K_MAX_TEMP) { | 323 | if (temp == 0x99) { |
328 | temp = prev[sensor]; | 324 | msleep(100); |
329 | prev[sensor] = I8K_MAX_TEMP+1; | 325 | temp = _i8k_get_temp(sensor); |
330 | } else { | ||
331 | prev[sensor] = temp; | ||
332 | } | 326 | } |
327 | /* | ||
328 | * Return -ENODATA for all invalid temperatures. | ||
329 | * | ||
330 | * Known instances are the 0x99 value as seen above as well as | ||
331 | * 0xc1 (193), which may be returned when trying to read the GPU | ||
332 | * temperature if the system supports a GPU and it is currently | ||
333 | * turned off. | ||
334 | */ | ||
333 | if (temp > I8K_MAX_TEMP) | 335 | if (temp > I8K_MAX_TEMP) |
334 | return -ENODATA; | 336 | return -ENODATA; |
335 | #endif | ||
336 | 337 | ||
337 | return temp; | 338 | return temp; |
338 | } | 339 | } |