|
@@ -76,6 +76,7 @@ static uint i8k_fan_mult = I8K_FAN_MULT;
|
|
|
static uint i8k_pwm_mult;
|
|
|
static uint i8k_fan_max = I8K_FAN_HIGH;
|
|
|
static bool disallow_fan_type_call;
|
|
|
+static bool disallow_fan_support;
|
|
|
|
|
|
#define I8K_HWMON_HAVE_TEMP1 (1 << 0)
|
|
|
#define I8K_HWMON_HAVE_TEMP2 (1 << 1)
|
|
@@ -242,6 +243,9 @@ static int i8k_get_fan_status(int fan)
|
|
|
{
|
|
|
struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
|
|
|
|
|
|
+ if (disallow_fan_support)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
regs.ebx = fan & 0xff;
|
|
|
return i8k_smm(®s) ? : regs.eax & 0xff;
|
|
|
}
|
|
@@ -253,6 +257,9 @@ static int i8k_get_fan_speed(int fan)
|
|
|
{
|
|
|
struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
|
|
|
|
|
|
+ if (disallow_fan_support)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
regs.ebx = fan & 0xff;
|
|
|
return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult;
|
|
|
}
|
|
@@ -264,7 +271,7 @@ static int _i8k_get_fan_type(int fan)
|
|
|
{
|
|
|
struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
|
|
|
|
|
|
- if (disallow_fan_type_call)
|
|
|
+ if (disallow_fan_support || disallow_fan_type_call)
|
|
|
return -EINVAL;
|
|
|
|
|
|
regs.ebx = fan & 0xff;
|
|
@@ -289,6 +296,9 @@ static int i8k_get_fan_nominal_speed(int fan, int speed)
|
|
|
{
|
|
|
struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };
|
|
|
|
|
|
+ if (disallow_fan_support)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
regs.ebx = (fan & 0xff) | (speed << 8);
|
|
|
return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult;
|
|
|
}
|
|
@@ -300,6 +310,9 @@ static int i8k_set_fan(int fan, int speed)
|
|
|
{
|
|
|
struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
|
|
|
|
|
|
+ if (disallow_fan_support)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);
|
|
|
regs.ebx = (fan & 0xff) | (speed << 8);
|
|
|
|
|
@@ -772,6 +785,8 @@ static struct attribute *i8k_attrs[] = {
|
|
|
static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
|
|
|
int index)
|
|
|
{
|
|
|
+ if (disallow_fan_support && index >= 8)
|
|
|
+ return 0;
|
|
|
if (disallow_fan_type_call &&
|
|
|
(index == 9 || index == 12 || index == 15))
|
|
|
return 0;
|
|
@@ -1038,6 +1053,23 @@ static const struct dmi_system_id i8k_blacklist_fan_type_dmi_table[] __initconst
|
|
|
{ }
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * On some machines all fan related SMM functions implemented by Dell BIOS
|
|
|
+ * firmware freeze kernel for about 500ms. Until Dell fixes these problems fan
|
|
|
+ * support for affected blacklisted Dell machines stay disabled.
|
|
|
+ * See bug: https://bugzilla.kernel.org/show_bug.cgi?id=195751
|
|
|
+ */
|
|
|
+static struct dmi_system_id i8k_blacklist_fan_support_dmi_table[] __initdata = {
|
|
|
+ {
|
|
|
+ .ident = "Dell Inspiron 7720",
|
|
|
+ .matches = {
|
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
|
|
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Inspiron 7720"),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ { }
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Probe for the presence of a supported laptop.
|
|
|
*/
|
|
@@ -1060,6 +1092,12 @@ static int __init i8k_probe(void)
|
|
|
i8k_get_dmi_data(DMI_BIOS_VERSION));
|
|
|
}
|
|
|
|
|
|
+ if (dmi_check_system(i8k_blacklist_fan_support_dmi_table)) {
|
|
|
+ pr_warn("broken Dell BIOS detected, disallow fan support\n");
|
|
|
+ if (!force)
|
|
|
+ disallow_fan_support = true;
|
|
|
+ }
|
|
|
+
|
|
|
if (dmi_check_system(i8k_blacklist_fan_type_dmi_table)) {
|
|
|
pr_warn("broken Dell BIOS detected, disallow fan type call\n");
|
|
|
if (!force)
|