Skip to content

Commit 1c16580

Browse files
Wer-Wolfgroeck
authored andcommitted
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>
1 parent 205c730 commit 1c16580

3 files changed

Lines changed: 98 additions & 34 deletions

File tree

Documentation/hwmon/dell-smm-hwmon.rst

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ fan[1-4]_min RO Minimal Fan speed in RPM
3838
fan[1-4]_max RO Maximal Fan speed in RPM
3939
fan[1-4]_target RO Expected Fan speed in RPM
4040
pwm[1-4] RW Control the fan PWM duty-cycle.
41-
pwm1_enable WO Enable or disable automatic BIOS fan
41+
pwm[1-4]_enable RW/WO Enable or disable automatic BIOS fan
4242
control (not supported on all laptops,
4343
see below for details).
4444
temp[1-10]_input RO Temperature reading in milli-degrees
@@ -49,26 +49,40 @@ temp[1-10]_label RO Temperature sensor label.
4949
Due to the nature of the SMM interface, each pwmX attribute controls
5050
fan number X.
5151

52-
Disabling automatic BIOS fan control
53-
------------------------------------
54-
55-
On some laptops the BIOS automatically sets fan speed every few
56-
seconds. Therefore the fan speed set by mean of this driver is quickly
57-
overwritten.
58-
59-
There is experimental support for disabling automatic BIOS fan
60-
control, at least on laptops where the corresponding SMM command is
61-
known, by writing the value ``1`` in the attribute ``pwm1_enable``
62-
(writing ``2`` enables automatic BIOS control again). Even if you have
63-
more than one fan, all of them are set to either enabled or disabled
64-
automatic fan control at the same time and, notwithstanding the name,
65-
``pwm1_enable`` sets automatic control for all fans.
66-
67-
If ``pwm1_enable`` is not available, then it means that SMM codes for
68-
enabling and disabling automatic BIOS fan control are not whitelisted
69-
for your hardware. It is possible that codes that work for other
70-
laptops actually work for yours as well, or that you have to discover
71-
new codes.
52+
Enabling/Disabling automatic BIOS fan control
53+
---------------------------------------------
54+
55+
There exist two methods for enabling/disabling automatic BIOS fan control:
56+
57+
1. Separate SMM commands to enable/disable automatic BIOS fan control for all fans.
58+
59+
2. A special fan state that enables automatic BIOS fan control for a individual fan.
60+
61+
The driver cannot reliably detect what method should be used on a given
62+
device, so instead the following heuristic is used:
63+
64+
- use fan state 3 for enabling BIOS fan control if the maximum fan state
65+
setable by the user is smaller than 3 (default setting).
66+
67+
- use separate SMM commands if device is whitelisted to support them.
68+
69+
When using the first method, each fan will have a standard ``pwmX_enable``
70+
sysfs attribute. Writing ``1`` into this attribute will disable automatic
71+
BIOS fan control for the associated fan and set it to maximum speed. Enabling
72+
BIOS fan control again can be achieved by writing ``2`` into this attribute.
73+
Reading this sysfs attributes returns the current setting as reported by
74+
the underlying hardware.
75+
76+
When using the second method however, only the ``pwm1_enable`` sysfs attribute
77+
will be available to enable/disable automatic BIOS fan control globaly for all
78+
fans available on a given device. Additionally, this sysfs attribute is write-only
79+
as there exists no SMM command for reading the current fan control setting.
80+
81+
If no ``pwmX_enable`` attributes are available, then it means that the driver
82+
cannot use the first method and the SMM codes for enabling and disabling automatic
83+
BIOS fan control are not whitelisted for your device. It is possible that codes
84+
that work for other laptops actually work for yours as well, or that you have to
85+
discover new codes.
7286

7387
Check the list ``i8k_whitelist_fan_control`` in file
7488
``drivers/hwmon/dell-smm-hwmon.c`` in the kernel tree: as a first

drivers/hwmon/dell-smm-hwmon.c

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,13 @@ static int dell_smm_get_cur_state(struct thermal_cooling_device *dev, unsigned l
764764
if (ret < 0)
765765
return ret;
766766

767+
/*
768+
* A fan state bigger than i8k_fan_max might indicate that
769+
* the fan is currently in automatic mode.
770+
*/
771+
if (ret > cdata->data->i8k_fan_max)
772+
return -ENODATA;
773+
767774
*state = ret;
768775

769776
return 0;
@@ -851,14 +858,25 @@ static umode_t dell_smm_is_visible(const void *drvdata, enum hwmon_sensor_types
851858

852859
break;
853860
case hwmon_pwm_enable:
854-
if (auto_fan)
861+
if (auto_fan) {
862+
/*
863+
* The setting affects all fans, so only create a
864+
* single attribute.
865+
*/
866+
if (channel != 1)
867+
return 0;
868+
855869
/*
856870
* There is no command for retrieve the current status
857871
* from BIOS, and userspace/firmware itself can change
858872
* it.
859873
* Thus we can only provide write-only access for now.
860874
*/
861875
return 0200;
876+
}
877+
878+
if (data->fan[channel] && data->i8k_fan_max < I8K_FAN_AUTO)
879+
return 0644;
862880

863881
break;
864882
default:
@@ -928,14 +946,28 @@ static int dell_smm_read(struct device *dev, enum hwmon_sensor_types type, u32 a
928946
}
929947
break;
930948
case hwmon_pwm:
949+
ret = i8k_get_fan_status(data, channel);
950+
if (ret < 0)
951+
return ret;
952+
931953
switch (attr) {
932954
case hwmon_pwm_input:
933-
ret = i8k_get_fan_status(data, channel);
934-
if (ret < 0)
935-
return ret;
955+
/*
956+
* A fan state bigger than i8k_fan_max might indicate that
957+
* the fan is currently in automatic mode.
958+
*/
959+
if (ret > data->i8k_fan_max)
960+
return -ENODATA;
936961

937962
*val = clamp_val(ret * data->i8k_pwm_mult, 0, 255);
938963

964+
return 0;
965+
case hwmon_pwm_enable:
966+
if (ret == I8K_FAN_AUTO)
967+
*val = 2;
968+
else
969+
*val = 1;
970+
939971
return 0;
940972
default:
941973
break;
@@ -1022,16 +1054,32 @@ static int dell_smm_write(struct device *dev, enum hwmon_sensor_types type, u32
10221054

10231055
return 0;
10241056
case hwmon_pwm_enable:
1025-
if (!val)
1026-
return -EINVAL;
1027-
1028-
if (val == 1)
1057+
switch (val) {
1058+
case 1:
10291059
enable = false;
1030-
else
1060+
break;
1061+
case 2:
10311062
enable = true;
1063+
break;
1064+
default:
1065+
return -EINVAL;
1066+
}
10321067

10331068
mutex_lock(&data->i8k_mutex);
1034-
err = i8k_enable_fan_auto_mode(data, enable);
1069+
if (auto_fan) {
1070+
err = i8k_enable_fan_auto_mode(data, enable);
1071+
} else {
1072+
/*
1073+
* When putting the fan into manual control mode we have to ensure
1074+
* that the device does not overheat until the userspace fan control
1075+
* software takes over. Because of this we set the fan speed to
1076+
* i8k_fan_max when disabling automatic fan control.
1077+
*/
1078+
if (enable)
1079+
err = i8k_set_fan(data, channel, I8K_FAN_AUTO);
1080+
else
1081+
err = i8k_set_fan(data, channel, data->i8k_fan_max);
1082+
}
10351083
mutex_unlock(&data->i8k_mutex);
10361084

10371085
if (err < 0)
@@ -1082,9 +1130,9 @@ static const struct hwmon_channel_info * const dell_smm_info[] = {
10821130
),
10831131
HWMON_CHANNEL_INFO(pwm,
10841132
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
1085-
HWMON_PWM_INPUT,
1086-
HWMON_PWM_INPUT,
1087-
HWMON_PWM_INPUT
1133+
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
1134+
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
1135+
HWMON_PWM_INPUT | HWMON_PWM_ENABLE
10881136
),
10891137
NULL
10901138
};

include/uapi/linux/i8k.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
#define I8K_FAN_LOW 1
3737
#define I8K_FAN_HIGH 2
3838
#define I8K_FAN_TURBO 3
39+
/* Many machines treat this mode as some sort of automatic mode */
40+
#define I8K_FAN_AUTO 3
3941
#define I8K_FAN_MAX I8K_FAN_TURBO
4042

4143
#define I8K_VOL_UP 1

0 commit comments

Comments
 (0)