aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)