summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorPali Rohár <pali.rohar@gmail.com>2016-06-18 00:54:47 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-07-27 09:47:37 -0700
commit3bb6a5196da9c8135b8758c6fe98d59fb4d9daf0 (patch)
tree66eb07fdd7d2379752d323ec9e27e76ae7c8bf89 /drivers/hwmon
parent9a3d983a442aaaaa1b2c64f1c6b4b9d086db5a78 (diff)
hwmon: (dell-smm) Cache fan_type() calls and change fan detection
commit 5ce91714b0d8c0a3ff9b858966721f508351cf4c upstream. On more Dell machines (e.g. Dell Precision M3800) fan_type() call is too expensive (CPU is too long in SMM mode) and cause kernel to hang. This is bug in Dell SMM or BIOS. This patch caches type for each fan (as it should not change) and changes the way how fan presense is detected. First it try function fan_status() as was before commit f989e55452c7 ("i8k: Add support for fan labels"). And if that fails fallback to fan_type(). *_status() functions can fail in case fan is not currently accessible (e.g. present on GPU which is currently turned off). Reported-by: Tolga Cakir <cevelnet@gmail.com> Signed-off-by: Pali Rohár <pali.rohar@gmail.com> Link: https://bugzilla.kernel.org/show_bug.cgi?id=112021 Tested-by: Tolga Cakir <cevelnet@gmail.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/dell-smm-hwmon.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index 497efa03d989..a9356a3dea92 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -237,7 +237,7 @@ static int i8k_get_fan_speed(int fan)
/*
* Read the fan type.
*/
-static int i8k_get_fan_type(int fan)
+static int _i8k_get_fan_type(int fan)
{
struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
@@ -248,6 +248,17 @@ static int i8k_get_fan_type(int fan)
return i8k_smm(&regs) ? : regs.eax & 0xff;
}
+static int i8k_get_fan_type(int fan)
+{
+ /* I8K_SMM_GET_FAN_TYPE SMM call is expensive, so cache values */
+ static int types[2] = { INT_MIN, INT_MIN };
+
+ if (types[fan] == INT_MIN)
+ types[fan] = _i8k_get_fan_type(fan);
+
+ return types[fan];
+}
+
/*
* Read the fan nominal rpm for specific fan speed.
*/
@@ -777,13 +788,17 @@ static int __init i8k_init_hwmon(void)
if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;
- /* First fan attributes, if fan type is OK */
- err = i8k_get_fan_type(0);
+ /* First fan attributes, if fan status or type is OK */
+ err = i8k_get_fan_status(0);
+ if (err < 0)
+ err = i8k_get_fan_type(0);
if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;
- /* Second fan attributes, if fan type is OK */
- err = i8k_get_fan_type(1);
+ /* Second fan attributes, if fan status or type is OK */
+ err = i8k_get_fan_status(1);
+ if (err < 0)
+ err = i8k_get_fan_type(1);
if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;