aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali.rohar@gmail.com>2018-01-27 11:28:34 -0500
committerGuenter Roeck <linux@roeck-us.net>2018-01-27 12:34:03 -0500
commitf480ea90b9dd7dfcf9031c82abc294f86d7db435 (patch)
tree76a926f08f16739761c971dcddbb32d68a2144e2
parent836ad11235d04f7a6fcd41b1abceaeacc70153c0 (diff)
hwmon: (dell-smm) Disable fan support for Dell Inspiron 7720
Calling fan related SMM functions implemented by Dell BIOS firmware on Dell Inspiron 7720 freeze kernel for about 500ms. Until Dell fixes it we need to disable fan support for Dell Inspiron 7720 as it makes system unusable. Via "force" module param fan support can be enabled. Reported-by: vova7890@mail.ru Signed-off-by: Pali Rohár <pali.rohar@gmail.com> Link: https://bugzilla.kernel.org/show_bug.cgi?id=195751 Cc: stable@vger.kernel.org # v4.0+, will need backport Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--drivers/hwmon/dell-smm-hwmon.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index aef4f8317ae2..3f8b4e482b64 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -76,6 +76,7 @@ static uint i8k_fan_mult = I8K_FAN_MULT;
76static uint i8k_pwm_mult; 76static uint i8k_pwm_mult;
77static uint i8k_fan_max = I8K_FAN_HIGH; 77static uint i8k_fan_max = I8K_FAN_HIGH;
78static bool disallow_fan_type_call; 78static bool disallow_fan_type_call;
79static bool disallow_fan_support;
79 80
80#define I8K_HWMON_HAVE_TEMP1 (1 << 0) 81#define I8K_HWMON_HAVE_TEMP1 (1 << 0)
81#define I8K_HWMON_HAVE_TEMP2 (1 << 1) 82#define I8K_HWMON_HAVE_TEMP2 (1 << 1)
@@ -242,6 +243,9 @@ static int i8k_get_fan_status(int fan)
242{ 243{
243 struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, }; 244 struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
244 245
246 if (disallow_fan_support)
247 return -EINVAL;
248
245 regs.ebx = fan & 0xff; 249 regs.ebx = fan & 0xff;
246 return i8k_smm(&regs) ? : regs.eax & 0xff; 250 return i8k_smm(&regs) ? : regs.eax & 0xff;
247} 251}
@@ -253,6 +257,9 @@ static int i8k_get_fan_speed(int fan)
253{ 257{
254 struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; 258 struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
255 259
260 if (disallow_fan_support)
261 return -EINVAL;
262
256 regs.ebx = fan & 0xff; 263 regs.ebx = fan & 0xff;
257 return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult; 264 return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
258} 265}
@@ -264,7 +271,7 @@ static int _i8k_get_fan_type(int fan)
264{ 271{
265 struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, }; 272 struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
266 273
267 if (disallow_fan_type_call) 274 if (disallow_fan_support || disallow_fan_type_call)
268 return -EINVAL; 275 return -EINVAL;
269 276
270 regs.ebx = fan & 0xff; 277 regs.ebx = fan & 0xff;
@@ -289,6 +296,9 @@ static int i8k_get_fan_nominal_speed(int fan, int speed)
289{ 296{
290 struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, }; 297 struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };
291 298
299 if (disallow_fan_support)
300 return -EINVAL;
301
292 regs.ebx = (fan & 0xff) | (speed << 8); 302 regs.ebx = (fan & 0xff) | (speed << 8);
293 return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult; 303 return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
294} 304}
@@ -300,6 +310,9 @@ static int i8k_set_fan(int fan, int speed)
300{ 310{
301 struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; 311 struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
302 312
313 if (disallow_fan_support)
314 return -EINVAL;
315
303 speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed); 316 speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);
304 regs.ebx = (fan & 0xff) | (speed << 8); 317 regs.ebx = (fan & 0xff) | (speed << 8);
305 318
@@ -772,6 +785,8 @@ static struct attribute *i8k_attrs[] = {
772static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, 785static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
773 int index) 786 int index)
774{ 787{
788 if (disallow_fan_support && index >= 8)
789 return 0;
775 if (disallow_fan_type_call && 790 if (disallow_fan_type_call &&
776 (index == 9 || index == 12 || index == 15)) 791 (index == 9 || index == 12 || index == 15))
777 return 0; 792 return 0;
@@ -1039,6 +1054,23 @@ static const struct dmi_system_id i8k_blacklist_fan_type_dmi_table[] __initconst
1039}; 1054};
1040 1055
1041/* 1056/*
1057 * On some machines all fan related SMM functions implemented by Dell BIOS
1058 * firmware freeze kernel for about 500ms. Until Dell fixes these problems fan
1059 * support for affected blacklisted Dell machines stay disabled.
1060 * See bug: https://bugzilla.kernel.org/show_bug.cgi?id=195751
1061 */
1062static struct dmi_system_id i8k_blacklist_fan_support_dmi_table[] __initdata = {
1063 {
1064 .ident = "Dell Inspiron 7720",
1065 .matches = {
1066 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1067 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Inspiron 7720"),
1068 },
1069 },
1070 { }
1071};
1072
1073/*
1042 * Probe for the presence of a supported laptop. 1074 * Probe for the presence of a supported laptop.
1043 */ 1075 */
1044static int __init i8k_probe(void) 1076static int __init i8k_probe(void)
@@ -1060,6 +1092,12 @@ static int __init i8k_probe(void)
1060 i8k_get_dmi_data(DMI_BIOS_VERSION)); 1092 i8k_get_dmi_data(DMI_BIOS_VERSION));
1061 } 1093 }
1062 1094
1095 if (dmi_check_system(i8k_blacklist_fan_support_dmi_table)) {
1096 pr_warn("broken Dell BIOS detected, disallow fan support\n");
1097 if (!force)
1098 disallow_fan_support = true;
1099 }
1100
1063 if (dmi_check_system(i8k_blacklist_fan_type_dmi_table)) { 1101 if (dmi_check_system(i8k_blacklist_fan_type_dmi_table)) {
1064 pr_warn("broken Dell BIOS detected, disallow fan type call\n"); 1102 pr_warn("broken Dell BIOS detected, disallow fan type call\n");
1065 if (!force) 1103 if (!force)