Skip to content

Commit

Permalink
hwmon: (dell-smm) Cache fan_type() calls and change fan detection
Browse files Browse the repository at this point in the history
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 f989e55 ("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
Cc: stable@vger.kernel.org # v4.0+, will need backport
Tested-by: Tolga Cakir <cevelnet@gmail.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
  • Loading branch information
Pali Rohár authored and Guenter Roeck committed Jun 23, 2016
1 parent 2744d2f commit 5ce9171
Showing 1 changed file with 20 additions and 5 deletions.
25 changes: 20 additions & 5 deletions drivers/hwmon/dell-smm-hwmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,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, };

Expand All @@ -249,6 +249,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.
*/
Expand Down Expand Up @@ -782,13 +793,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;

Expand Down

0 comments on commit 5ce9171

Please sign in to comment.