stefan's blag and stuff

Blog – 2020-09-05 – The Thinkpad X220 fan

I own a Thinkpad X220 and the fan is sometimes annoying me. Even when the system is idle, a load average around 0.2 and the CPU is scaled down to the lowest frequency, the fan is spinning at a hearable noise.

So I wondered whether it's possible to tune the cooling algorithm and software control the fan. Short answer: yes, it's possible.

A quick internet search brings up sites and projects like:

The Thinkwiki describes the procfs interface /proc/acpi/ibm/, but the linux kernel driver should also support the newer sysfs interface. A quick look into the kernel sources thinkpad_acpi.c shows that it really supports the new sysfs fan and temperature controls.

On my system the fan can be queried and controlled by the sys files

$ ls /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon3
device  fan1_input  name  power  pwm1  pwm1_enable  subsystem  uevent

And the temperature can be read from the two sysfs directories

$ ls /sys/devices/virtual/thermal/thermal_zone0
available_policies  k_d   mode     power              temp               uevent
device              k_i   offset   slope              trip_point_0_temp
hwmon1              k_po  passive  subsystem          trip_point_0_type
integral_cutoff     k_pu  policy   sustainable_power  type

$ ls /sys/devices/virtual/thermal/thermal_zone1
available_policies  k_po    power              temp               trip_point_1_type
integral_cutoff     k_pu    slope              trip_point_0_temp  type
k_d                 offset  subsystem          trip_point_0_type  uevent
k_i                 policy  sustainable_power  trip_point_1_temp

I don't know where the two temperature sensors are located on the mainboard, but most of the time they report a similar value:

$ cat /sys/devices/virtual/thermal/thermal_zone0/temp
$ cat /sys/devices/virtual/thermal/thermal_zone1/temp

To be able to software control the fan, you have to set a kernel module parameter thinkpad_acpi.fan_control:

$ cat /etc/default/grub
GRUB_CMDLINE_LINUX="init=/usr/lib/systemd/systemd thinkpad_acpi.fan_control=1"
$ sudo grub-mkconfig -o /boot/grub/grub.cfg
$ reboot

Just a safe guard to avoid accidentally damaging your system. You have to explicitly opt-in for that feature.

Reading the kernel sources of the driver provides a very good overview about the capabilities of the fan controls exposed in the sysfs:

 * SYSFS fan layout: hwmon compatible (device)
 * pwm*_enable:
 *      0: "disengaged" mode
 *      1: manual mode
 *      2: native EC "auto" mode (recommended, hardware default)
 * pwm*: set speed in manual mode, ignored otherwise.
 *      0 is level 0; 255 is level 7. Intermediate points done with linear
 *      interpolation.
 * fan*_input: tachometer reading, RPM
 * SYSFS fan layout: extensions
 * fan_watchdog (driver):
 *      fan watchdog interval in seconds, 0 disables (default), max 120

So there are three operation modes: disengaged, manual and auto. We only consider the modes manual and auto in this text. The hardware supports seven different levels that are mapped into the integer range 0 to 255. The mapping is:

 level 0   ->  value   0
 level 1   ->  value  36
 level 2   ->  value  72
 level 3   ->  value 109
 level 4   ->  value 145
 level 5   ->  value 182
 level 6   ->  value 218
 level 7   ->  value 255

You can exercise the sysfs interface with shell commands. So experiments are easy:

# Set the fan into manual mode
$ echo 1 > /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon3/pwm1_enable

# Set the fan speed to level 5
$ echo 182 > /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon3/pwm1

# Spin down the fan completely
$ echo 0 > /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon3/pwm1

# Switch back to auto mode
$ echo 2 > /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon3/pwm1_enable

When playing with fan settings it is a good backup to keep an eye the CPU temperature. Otherwise the system may get too hot. To do this just use something like

$ while true; do \
    cat /sys/devices/virtual/thermal/thermal_zone0/temp; \
    sleep 1; \

in a second shell.

Question: Which fan speed level is which RPM value?

The actual fan speed in RPMs can be queried from the file

$ cat /sys/devices/platform/thinkpad_hwmon/hwmon/hwmon3/fan1_input

So my first question was: What is the fan speed in RPMs when I set a specific fan level?

After some python scripting, logging and gnuplot magic, I got this output data

  | Fan level |  Median
0 |       0   |      0
1 |      36   |   1948
2 |      72   |   3112
3 |     109   |   3642
4 |     145   |   3642
5 |     182   |   4017
6 |     218   |   4026
7 |     255   |   4609

and this graph:

The interesting observation is that the seven fan levels actually map to only five different RPM values. Fan levels three and four and fan levels five and six, actually correspond to the same RPM values 3642 and ~4020.

Question: How does auto mode algorithm works?

After knowing more about the hardware capabilities of the fan the next question is the behavior of the fan in auto mode. How and which fan level does it choose?

My basic assumption is that it's a linear function bound to the temperature of the system.

When the fan is in auto mode it's not possible to read back the fan level. Reading from the sys file


yields always the same value, even when I hear that the fan is changing it's speed level. So I tried to indirectly observe the speed level from the RPM value.

After some additional logging of the system under idle and high load conditions (portage updates) and gnuplotting, I got the following graph:

There are again five clusters clearly visible. I didn't expected the clusters to be sharp, because the algorithm and the fan needs some time to react to the temperature changes and ramp up or down the speed.

Even so there are five clusters, not every cluster is equal in the amount of datapoints. There are two big and three smaller clusters. The big clusters are RPM values 3642 and 4609. This can be an artifact from the testing conditions. The system was either in a high load condition (compiling software projects) or idle.

What stands out is the fact that even when the system was idle, the fan speed remained at levels three or four (= RPM value 3642). There are a lot of datapoints for these fan levels even so the temperature of the system is less than 50°C. The lower fan levels (zero, one and two) are hardly used.

This result also fits my day to day observations. For example currently the fan spins hearable with 3654 RPMs (levels 3 and 4), even so CPU temperature is around ~50°C.

Back to the question: Does the auto algorithm use a linear function to set the fan level? For now I don't have a definite answer. The graph does not show it. Maybe there are also other system properties that the algorithm takes into consideration.


When the hardware is controlling the fan speed level in auto mode, it does not utilize the lower fan speed levels in my setup. It would be really nice, if the fan would spin down to the lowest mode possible to keep the temperature. It does not have spin down completely. Even the lowest spinning mode, level one (=RPM value 1948), is not hearable.

Using a userspace software daemon to control the fan and implement this better behavior, is a task for another story.