hwmon: (dell-smm) Add support for automatic fan mode

Many machines treat fan state 3 as some sort of automatic mode,
which is superior to the separate SMM calls for switching to
automatic fan mode for two reasons:

- the fan control mode can be controlled for each fan separately
- the current fan control mode can be retrieved from the BIOS

On some machines however, this special fan state does not exist.
Fan state 3 acts like a regular fan state on such machines or
does not exist at all. Such machines usually use separate SMM calls
for enabling/disabling automatic fan control.

Add support for it. If the machine supports separate SMM calls
for changing the fan control mode, then the other interface is
ignored.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://lore.kernel.org/r/20250917181036.10972-4-W_Armin@gmx.de
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
pull/1354/merge
Armin Wolf 2025-09-17 20:10:35 +02:00 committed by Guenter Roeck
parent 205c730262
commit 1c1658058c
3 changed files with 95 additions and 31 deletions

View File

@ -38,7 +38,7 @@ fan[1-4]_min RO Minimal Fan speed in RPM
fan[1-4]_max RO Maximal Fan speed in RPM fan[1-4]_max RO Maximal Fan speed in RPM
fan[1-4]_target RO Expected Fan speed in RPM fan[1-4]_target RO Expected Fan speed in RPM
pwm[1-4] RW Control the fan PWM duty-cycle. pwm[1-4] RW Control the fan PWM duty-cycle.
pwm1_enable WO Enable or disable automatic BIOS fan pwm[1-4]_enable RW/WO Enable or disable automatic BIOS fan
control (not supported on all laptops, control (not supported on all laptops,
see below for details). see below for details).
temp[1-10]_input RO Temperature reading in milli-degrees temp[1-10]_input RO Temperature reading in milli-degrees
@ -49,26 +49,40 @@ temp[1-10]_label RO Temperature sensor label.
Due to the nature of the SMM interface, each pwmX attribute controls Due to the nature of the SMM interface, each pwmX attribute controls
fan number X. fan number X.
Disabling automatic BIOS fan control Enabling/Disabling automatic BIOS fan control
------------------------------------ ---------------------------------------------
On some laptops the BIOS automatically sets fan speed every few There exist two methods for enabling/disabling automatic BIOS fan control:
seconds. Therefore the fan speed set by mean of this driver is quickly
overwritten.
There is experimental support for disabling automatic BIOS fan 1. Separate SMM commands to enable/disable automatic BIOS fan control for all fans.
control, at least on laptops where the corresponding SMM command is
known, by writing the value ``1`` in the attribute ``pwm1_enable``
(writing ``2`` enables automatic BIOS control again). Even if you have
more than one fan, all of them are set to either enabled or disabled
automatic fan control at the same time and, notwithstanding the name,
``pwm1_enable`` sets automatic control for all fans.
If ``pwm1_enable`` is not available, then it means that SMM codes for 2. A special fan state that enables automatic BIOS fan control for a individual fan.
enabling and disabling automatic BIOS fan control are not whitelisted
for your hardware. It is possible that codes that work for other The driver cannot reliably detect what method should be used on a given
laptops actually work for yours as well, or that you have to discover device, so instead the following heuristic is used:
new codes.
- use fan state 3 for enabling BIOS fan control if the maximum fan state
setable by the user is smaller than 3 (default setting).
- use separate SMM commands if device is whitelisted to support them.
When using the first method, each fan will have a standard ``pwmX_enable``
sysfs attribute. Writing ``1`` into this attribute will disable automatic
BIOS fan control for the associated fan and set it to maximum speed. Enabling
BIOS fan control again can be achieved by writing ``2`` into this attribute.
Reading this sysfs attributes returns the current setting as reported by
the underlying hardware.
When using the second method however, only the ``pwm1_enable`` sysfs attribute
will be available to enable/disable automatic BIOS fan control globaly for all
fans available on a given device. Additionally, this sysfs attribute is write-only
as there exists no SMM command for reading the current fan control setting.
If no ``pwmX_enable`` attributes are available, then it means that the driver
cannot use the first method and the SMM codes for enabling and disabling automatic
BIOS fan control are not whitelisted for your device. It is possible that codes
that work for other laptops actually work for yours as well, or that you have to
discover new codes.
Check the list ``i8k_whitelist_fan_control`` in file Check the list ``i8k_whitelist_fan_control`` in file
``drivers/hwmon/dell-smm-hwmon.c`` in the kernel tree: as a first ``drivers/hwmon/dell-smm-hwmon.c`` in the kernel tree: as a first

View File

@ -764,6 +764,13 @@ static int dell_smm_get_cur_state(struct thermal_cooling_device *dev, unsigned l
if (ret < 0) if (ret < 0)
return ret; return ret;
/*
* A fan state bigger than i8k_fan_max might indicate that
* the fan is currently in automatic mode.
*/
if (ret > cdata->data->i8k_fan_max)
return -ENODATA;
*state = ret; *state = ret;
return 0; return 0;
@ -851,7 +858,14 @@ static umode_t dell_smm_is_visible(const void *drvdata, enum hwmon_sensor_types
break; break;
case hwmon_pwm_enable: case hwmon_pwm_enable:
if (auto_fan) if (auto_fan) {
/*
* The setting affects all fans, so only create a
* single attribute.
*/
if (channel != 1)
return 0;
/* /*
* There is no command for retrieve the current status * There is no command for retrieve the current status
* from BIOS, and userspace/firmware itself can change * from BIOS, and userspace/firmware itself can change
@ -859,6 +873,10 @@ static umode_t dell_smm_is_visible(const void *drvdata, enum hwmon_sensor_types
* Thus we can only provide write-only access for now. * Thus we can only provide write-only access for now.
*/ */
return 0200; return 0200;
}
if (data->fan[channel] && data->i8k_fan_max < I8K_FAN_AUTO)
return 0644;
break; break;
default: default:
@ -928,14 +946,28 @@ static int dell_smm_read(struct device *dev, enum hwmon_sensor_types type, u32 a
} }
break; break;
case hwmon_pwm: case hwmon_pwm:
ret = i8k_get_fan_status(data, channel);
if (ret < 0)
return ret;
switch (attr) { switch (attr) {
case hwmon_pwm_input: case hwmon_pwm_input:
ret = i8k_get_fan_status(data, channel); /*
if (ret < 0) * A fan state bigger than i8k_fan_max might indicate that
return ret; * the fan is currently in automatic mode.
*/
if (ret > data->i8k_fan_max)
return -ENODATA;
*val = clamp_val(ret * data->i8k_pwm_mult, 0, 255); *val = clamp_val(ret * data->i8k_pwm_mult, 0, 255);
return 0;
case hwmon_pwm_enable:
if (ret == I8K_FAN_AUTO)
*val = 2;
else
*val = 1;
return 0; return 0;
default: default:
break; break;
@ -1022,16 +1054,32 @@ static int dell_smm_write(struct device *dev, enum hwmon_sensor_types type, u32
return 0; return 0;
case hwmon_pwm_enable: case hwmon_pwm_enable:
if (!val) switch (val) {
return -EINVAL; case 1:
if (val == 1)
enable = false; enable = false;
else break;
case 2:
enable = true; enable = true;
break;
default:
return -EINVAL;
}
mutex_lock(&data->i8k_mutex); mutex_lock(&data->i8k_mutex);
err = i8k_enable_fan_auto_mode(data, enable); if (auto_fan) {
err = i8k_enable_fan_auto_mode(data, enable);
} else {
/*
* When putting the fan into manual control mode we have to ensure
* that the device does not overheat until the userspace fan control
* software takes over. Because of this we set the fan speed to
* i8k_fan_max when disabling automatic fan control.
*/
if (enable)
err = i8k_set_fan(data, channel, I8K_FAN_AUTO);
else
err = i8k_set_fan(data, channel, data->i8k_fan_max);
}
mutex_unlock(&data->i8k_mutex); mutex_unlock(&data->i8k_mutex);
if (err < 0) if (err < 0)
@ -1082,9 +1130,9 @@ static const struct hwmon_channel_info * const dell_smm_info[] = {
), ),
HWMON_CHANNEL_INFO(pwm, HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT | HWMON_PWM_ENABLE, HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
HWMON_PWM_INPUT, HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
HWMON_PWM_INPUT, HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
HWMON_PWM_INPUT HWMON_PWM_INPUT | HWMON_PWM_ENABLE
), ),
NULL NULL
}; };

View File

@ -36,6 +36,8 @@
#define I8K_FAN_LOW 1 #define I8K_FAN_LOW 1
#define I8K_FAN_HIGH 2 #define I8K_FAN_HIGH 2
#define I8K_FAN_TURBO 3 #define I8K_FAN_TURBO 3
/* Many machines treat this mode as some sort of automatic mode */
#define I8K_FAN_AUTO 3
#define I8K_FAN_MAX I8K_FAN_TURBO #define I8K_FAN_MAX I8K_FAN_TURBO
#define I8K_VOL_UP 1 #define I8K_VOL_UP 1