[PATCH 1/5] i8k: Fix non-SMP operation

Subsystems: char and misc drivers, the rest

STALE4426d REVIEWED: 1 (0M)

1 review trailer.

5 messages, 1 author, 2014-06-21 · open the first message on its own page

[PATCH 1/5] i8k: Fix non-SMP operation

From: Guenter Roeck <linux@roeck-us.net>
Date: 2014-06-21 15:09:12

Commit f36fdb9f0266 (i8k: Force SMM to run on CPU 0) adds support
for multi-core CPUs to the driver. Unfortunately, that causes it
to fail loading if compiled without SMP support, at least on
32 bit kernels. Kernel log shows "i8k: unable to get SMM Dell
signature", and function i8k_smm is found to return -EINVAL.

Testing revealed that the culprit is the missing return value check
of set_cpus_allowed_ptr.

Fixes: f36fdb9f0266 (i8k: Force SMM to run on CPU 0)
Reported-by: Jim Bos <jim876-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
Tested-by: Jim Bos <jim876-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
Cc: stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org # 3.14+
Signed-off-by: Guenter Roeck <redacted>
---
 drivers/char/i8k.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index d915707..93dcad0 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -138,7 +138,9 @@ static int i8k_smm(struct smm_regs *regs)
 	if (!alloc_cpumask_var(&old_mask, GFP_KERNEL))
 		return -ENOMEM;
 	cpumask_copy(old_mask, &current->cpus_allowed);
-	set_cpus_allowed_ptr(current, cpumask_of(0));
+	rc = set_cpus_allowed_ptr(current, cpumask_of(0));
+	if (rc)
+		goto out;
 	if (smp_processor_id() != 0) {
 		rc = -EBUSY;
 		goto out;
-- 
1.9.1

[PATCH 2/5] i8k: Drop all labels

From: Guenter Roeck <linux@roeck-us.net>
Date: 2014-06-21 15:09:17

Labels are known to be wrong for several Dell laptops.
For example, a single fan may be shown as right fan when in reality
it sits on the left side of the chassis. Drop all labels to avoid
such inaccuracies. Users can select labels in the sensors configuration
file instead if desired.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
 drivers/char/i8k.c | 47 +++++++++++++----------------------------------
 1 file changed, 13 insertions(+), 34 deletions(-)
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 93dcad0..14ca8f0 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -544,20 +544,6 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev,
 	return err < 0 ? -EIO : count;
 }
 
-static ssize_t i8k_hwmon_show_label(struct device *dev,
-				    struct device_attribute *devattr,
-				    char *buf)
-{
-	static const char *labels[3] = {
-		"CPU",
-		"Left Fan",
-		"Right Fan",
-	};
-	int index = to_sensor_dev_attr(devattr)->index;
-
-	return sprintf(buf, "%s\n", labels[index]);
-}
-
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);
 static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);
@@ -570,41 +556,34 @@ static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
 			  I8K_FAN_RIGHT);
 static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
 			  i8k_hwmon_set_pwm, I8K_FAN_RIGHT);
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 0);
-static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1);
-static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2);
 
 static struct attribute *i8k_attrs[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,	/* 0 */
-	&sensor_dev_attr_temp1_label.dev_attr.attr,	/* 1 */
-	&sensor_dev_attr_temp2_input.dev_attr.attr,	/* 2 */
-	&sensor_dev_attr_temp3_input.dev_attr.attr,	/* 3 */
-	&sensor_dev_attr_temp4_input.dev_attr.attr,	/* 4 */
-	&sensor_dev_attr_fan1_input.dev_attr.attr,	/* 5 */
-	&sensor_dev_attr_pwm1.dev_attr.attr,		/* 6 */
-	&sensor_dev_attr_fan1_label.dev_attr.attr,	/* 7 */
-	&sensor_dev_attr_fan2_input.dev_attr.attr,	/* 8 */
-	&sensor_dev_attr_pwm2.dev_attr.attr,		/* 9 */
-	&sensor_dev_attr_fan2_label.dev_attr.attr,	/* 10 */
+	&sensor_dev_attr_temp2_input.dev_attr.attr,	/* 1 */
+	&sensor_dev_attr_temp3_input.dev_attr.attr,	/* 2 */
+	&sensor_dev_attr_temp4_input.dev_attr.attr,	/* 3 */
+	&sensor_dev_attr_fan1_input.dev_attr.attr,	/* 4 */
+	&sensor_dev_attr_pwm1.dev_attr.attr,		/* 5 */
+	&sensor_dev_attr_fan2_input.dev_attr.attr,	/* 6 */
+	&sensor_dev_attr_pwm2.dev_attr.attr,		/* 7 */
 	NULL
 };
 
 static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
 			      int index)
 {
-	if ((index == 0 || index == 1) &&
-	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
+	if (index == 0 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
 		return 0;
-	if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
+	if (index == 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
 		return 0;
-	if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
+	if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
 		return 0;
-	if (index == 4 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
+	if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
 		return 0;
-	if (index >= 5 && index <= 7 &&
+	if (index >= 4 && index <= 5 &&
 	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
 		return 0;
-	if (index >= 8 && index <= 10 &&
+	if (index >= 6 && index <= 7 &&
 	    !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
 		return 0;
 
-- 
1.9.1

[PATCH 3/5] i8k: Add support for configurable maximum fan speed value

From: Guenter Roeck <linux@roeck-us.net>
Date: 2014-06-21 15:09:20

Newer Dell systems provide more granular fan speed selection.
Add support for it.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
 drivers/char/i8k.c | 49 ++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 42 insertions(+), 7 deletions(-)
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 14ca8f0..0b69da0 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -65,6 +65,8 @@ static char bios_version[4];
 static struct device *i8k_hwmon_dev;
 static u32 i8k_hwmon_flags;
 static int i8k_fan_mult;
+static int i8k_pwm_mult;
+static int i8k_fan_max = I8K_FAN_HIGH;
 
 #define I8K_HWMON_HAVE_TEMP1	(1 << 0)
 #define I8K_HWMON_HAVE_TEMP2	(1 << 1)
@@ -97,6 +99,10 @@ static int fan_mult = I8K_FAN_MULT;
 module_param(fan_mult, int, 0);
 MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
 
+static int fan_max = I8K_FAN_HIGH;
+module_param(fan_max, int, 0);
+MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed");
+
 static int i8k_open_fs(struct inode *inode, struct file *file);
 static long i8k_ioctl(struct file *, unsigned int, unsigned long);
 
@@ -276,7 +282,7 @@ static int i8k_set_fan(int fan, int speed)
 {
 	struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
 
-	speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
+	speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed);
 	regs.ebx = (fan & 0xff) | (speed << 8);
 
 	return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
@@ -521,7 +527,7 @@ static ssize_t i8k_hwmon_show_pwm(struct device *dev,
 	status = i8k_get_fan_status(index);
 	if (status < 0)
 		return -EIO;
-	return sprintf(buf, "%d\n", clamp_val(status * 128, 0, 255));
+	return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255));
 }
 
 static ssize_t i8k_hwmon_set_pwm(struct device *dev,
@@ -535,7 +541,7 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev,
 	err = kstrtoul(buf, 10, &val);
 	if (err)
 		return err;
-	val = clamp_val(DIV_ROUND_CLOSEST(val, 128), 0, 2);
+	val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max);
 
 	mutex_lock(&i8k_mutex);
 	err = i8k_set_fan(index, val);
@@ -638,6 +644,27 @@ static int __init i8k_init_hwmon(void)
 	return 0;
 }
 
+struct i8k_config_data {
+	int fan_mult;
+	int fan_max;
+};
+
+enum i8k_configs {
+	DELL_STUDIO,
+	DELL_XPS_M140,
+};
+
+static const struct i8k_config_data i8k_config_data[] = {
+	[DELL_STUDIO] = {
+		.fan_mult = 1,
+		.fan_max = I8K_FAN_HIGH,
+	},
+	[DELL_XPS_M140] = {
+		.fan_mult = 1,
+		.fan_max = I8K_FAN_HIGH,
+	},
+};
+
 static struct dmi_system_id i8k_dmi_table[] __initdata = {
 	{
 		.ident = "Dell Inspiron",
@@ -708,7 +735,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Studio"),
 		},
-		.driver_data = (void *)1,	/* fan multiplier override */
+		.driver_data = (void *)&i8k_config_data[DELL_STUDIO],
 	},
 	{
 		.ident = "Dell XPS M140",
@@ -716,7 +743,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 			DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"),
 		},
-		.driver_data = (void *)1,	/* fan multiplier override */
+		.driver_data = (void *)&i8k_config_data[DELL_XPS_M140],
 	},
 	{ }
 };
@@ -756,9 +783,17 @@ static int __init i8k_probe(void)
 	}
 
 	i8k_fan_mult = fan_mult;
+	i8k_fan_max = fan_max ? : I8K_FAN_HIGH;	/* Must not be 0 */
 	id = dmi_first_match(i8k_dmi_table);
-	if (id && fan_mult == I8K_FAN_MULT && id->driver_data)
-		i8k_fan_mult = (unsigned long)id->driver_data;
+	if (id && id->driver_data) {
+		const struct i8k_config_data *conf = id->driver_data;
+
+		if (fan_mult == I8K_FAN_MULT && conf->fan_mult)
+			i8k_fan_mult = conf->fan_mult;
+		if (fan_max == I8K_FAN_HIGH && conf->fan_max)
+			i8k_fan_max = conf->fan_max;
+	}
+	i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
 
 	return 0;
 }
-- 
1.9.1

[PATCH 5/5] i8k: Add support for Dell Precision 490 and Latitude D520

From: Guenter Roeck <linux@roeck-us.net>
Date: 2014-06-21 15:09:26

Both systems need non-standard parameters for fan multiplier
and maximum fan speed.

Signed-off-by: Guenter Roeck <redacted>
---
 drivers/char/i8k.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 0b69da0..65525c7 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -650,11 +650,21 @@ struct i8k_config_data {
 };
 
 enum i8k_configs {
+	DELL_LATITUDE_D520,
+	DELL_PRECISION_490,
 	DELL_STUDIO,
 	DELL_XPS_M140,
 };
 
 static const struct i8k_config_data i8k_config_data[] = {
+	[DELL_LATITUDE_D520] = {
+		.fan_mult = 1,
+		.fan_max = I8K_FAN_TURBO,
+	},
+	[DELL_PRECISION_490] = {
+		.fan_mult = 1,
+		.fan_max = I8K_FAN_TURBO,
+	},
 	[DELL_STUDIO] = {
 		.fan_mult = 1,
 		.fan_max = I8K_FAN_HIGH,
@@ -688,6 +698,14 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
 		},
 	},
 	{
+		.ident = "Dell Latitude D520",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D520"),
+		},
+		.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],
+	},
+	{
 		.ident = "Dell Latitude 2",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -709,6 +727,15 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
 		},
 	},
 	{
+		.ident = "Dell Precision 490",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME,
+				  "Precision WorkStation 490"),
+		},
+		.driver_data = (void *)&i8k_config_data[DELL_PRECISION_490],
+	},
+	{
 		.ident = "Dell Precision",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-- 
1.9.1

[PATCH 4/5] i8k: uapi: Introduce define for new highest fan speed

From: Guenter Roeck <linux@roeck-us.net>
Date: 2014-06-21 15:09:48

Some Dell laptops support fan speeds of {0, 1, 2, 3} instead of {0, 1, 2}.
Add a define for it.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
 include/uapi/linux/i8k.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/i8k.h b/include/uapi/linux/i8k.h
index 1c45ba5..133d02f 100644
--- a/include/uapi/linux/i8k.h
+++ b/include/uapi/linux/i8k.h
@@ -34,7 +34,8 @@
 #define I8K_FAN_OFF		0
 #define I8K_FAN_LOW		1
 #define I8K_FAN_HIGH		2
-#define I8K_FAN_MAX		I8K_FAN_HIGH
+#define I8K_FAN_TURBO		3
+#define I8K_FAN_MAX		I8K_FAN_TURBO
 
 #define I8K_VOL_UP		1
 #define I8K_VOL_DOWN		2
-- 
1.9.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help