diff options
| -rw-r--r-- | drivers/hwmon/dell-smm-hwmon.c | 40 |
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; | |||
| 76 | static uint i8k_pwm_mult; | 76 | static uint i8k_pwm_mult; |
| 77 | static uint i8k_fan_max = I8K_FAN_HIGH; | 77 | static uint i8k_fan_max = I8K_FAN_HIGH; |
| 78 | static bool disallow_fan_type_call; | 78 | static bool disallow_fan_type_call; |
| 79 | static 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(®s) ? : regs.eax & 0xff; | 250 | return i8k_smm(®s) ? : 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(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; | 264 | return i8k_smm(®s) ? : (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(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; | 303 | return i8k_smm(®s) ? : (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[] = { | |||
| 772 | static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, | 785 | static 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 | */ | ||
| 1062 | static 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 | */ |
| 1044 | static int __init i8k_probe(void) | 1076 | static 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) |
