| From 5ce91714b0d8c0a3ff9b858966721f508351cf4c Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali.rohar@gmail.com> |
| Date: Sat, 18 Jun 2016 00:54:47 +0200 |
| Subject: hwmon: (dell-smm) Cache fan_type() calls and change fan detection |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Pali Rohár <pali.rohar@gmail.com> |
| |
| 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> |
| |
| --- |
| drivers/hwmon/dell-smm-hwmon.c | 25 ++++++++++++++++++++----- |
| 1 file changed, 20 insertions(+), 5 deletions(-) |
| |
| --- 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(®s) ? : 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; |
| |