Monosoul's Dev Blog A blog to write down dev-related stuff I face
How to control ThinkPad P14s fan speed in Linux

How to control ThinkPad P14s’ fan speed in Linux

Recently I got a new laptop for work – Lenovo ThinkPad P14s (Gen 2). I prefer running Linux on my working machines, and this one is not an exclusion. While using it I noticed that the fan speed is sometimes too high for no reason creating undesirable noise. Here’s how to control ThinkPad P14s’ fan speed in Linux using a nice tool – thinkfan.

The steps described below are valid for Ubuntu 21.10, but probably shouldn’t be much different for any other distrib.

TL;DR

Time needed: 5 minutes.

Here’s how to set everything up

  1. Enable fan control

    echo 'options thinkpad_acpi fan_control=1' | sudo tee /lib/modprobe.d/thinkpad_acpi.conf

  2. Install thinkfan package

    sudo apt install thinkfan

  3. Create a new thinkfan configuration file

    sudo touch /etc/thinkfan.conf

  4. Put the following lines into /etc/thinkfan.conf

    sensors:
      # GPU
      - tpacpi: /proc/acpi/ibm/thermal
        indices: [1]
      # CPU
      - hwmon: /sys/class/hwmon
        name: coretemp
        indices: [2, 3, 4, 5]
      # Chassis
      - hwmon: /sys/class/hwmon
        name: thinkpad
        indices: [3, 5, 6, 7]
      # SSD
      - hwmon: /sys/class/hwmon
        name: nvme
        indices: [1, 2, 3]
        correction: [-5, 0, 0]
      # MB
      - hwmon: /sys/class/hwmon
        name: acpitz
        indices: [1]

    fans:
      - tpacpi: /proc/acpi/ibm/fan

    levels:
      - [0, 0, 37]
      - [1, 35, 42]
      - [2, 40, 45]
      - [3, 43, 47]
      - [4, 45, 52]
      - [5, 50, 57]
      - [6, 55, 72]
      - [7, 70, 82]
      - ["level full-speed", 77, 32767]

  5. Configure thinkfan to use the newly created file

    echo 'THINKFAN_ARGS="-c /etc/thinkfan.conf"' | sudo tee -a /etc/default/thinkfan

  6. Enable thinkfan service

    sudo systemctl enable thinkfan

  7. Reboot

    sudo reboot

With this configuration the fan will be kept at a reasonably quiet level while still allowing you to use the ThinkPad on top of your laps. 🙂

Configuration deep dive

If you’re interested in what exactly all the above-mentioned configuration options do, welcome to this deep dive section.

Sensors section

Sensors section of the configuration file describes all the thermal sensors thinkfan will use to keep an eye on the temperature.

‼️ IMPORTANT‼️: avoid using nvml option (temperatures read from proprietary nVidia GPU driver).

Using nvml prevents the GPU from switching to suspend power state, causing battery drain and high temperatures.

Here’s what we have there:

  • hwmon – specifies a generic temperature sensor. We use it to monitor CPU, SSD, WLAN and other devices’ temperature. A you can see, we have multiple hwmon entries having different names in the configuration file, here’s what they are:
    • tpacpi (#GPU) – this array of sensors represents pretty much the same temperatures as the one below (the chassis one), but with a little difference: the sensors are never missing here even if the device is offline (like GPU for example). Instead such sensors show negative values here. And this is what we’re using the sensor with index 1 for – to measure the GPU temperature.
      Technically, thinkfan should support devices that can be removed/suspended, but there’s a bug preventing it from working properly in daemon mode.
    • coretemp (#CPU) – measures CPU temperature. My ThinkPad P14s has 4 physical cores, therefore there are 5 sensors available: 1 sensor for the whole package + 1 sensor per core. Since there are sensors for every core, it feels redundant to use the package sensor as well, therefore we ignore it with this option:
      indices: [2, 3, 4, 5]
      Notice we skip sensor having index 1.
    • thinkpad (#Chassis) – measures CPU, GPU and chassis temperature. In my case sensor with index 8 is unavailable and sensor with index 4 always return 0, therefore I excluded them. Sensors 1 and 2 report CPU and GPU temperatures respectively, and since I already have other sensors to monitor CPU and GPU, I’ve excluded them as well. After all exclusions, this is what we have in the configuration:
      indices: [3, 5, 6, 7]
    • nvme – measures SSD temperature. There are 3 sensors available, where the first one is a composite sensor. I’ve noticed that during light internet browsing temperature of that sensor was typically higher than CPU temperature (I suppose because of browser using cache), while during heavy load CPU was hotter. Therefore I decided to correct this sensor’s temperature by -5 degrees to prevent the fan spinning up when it’s not really needed. So, we use all sensors available:
      indices: [1, 2, 3]
      And correct the temperature of the first sensor by -5 degrees:
      correction: [-5, 0, 0]
    • acpitz – measures motherboard temperature (or at least this is what I expect it to measure, not 100% sure about it). Has only 1 sensor that we use as is.

Fans section

ThinkPad P14s only has one fan, therefore not much to configure in that section. It has only 1 entry:

tpacpi: /proc/acpi/ibm/fan

It specifies the path to the interface to control fan. By the way, make sure you did the first step of TL;DR section in order to be able to control the fan speed.

Levels section

In this section we configure the fan speed and temperature levels to enable this fan speed. Thinkfan has 2 modes of fan speed configuration – simple and detailed.

In simple mode thinkfan will use the highest temperature of all sensors to determine fan speed, while with detailed mode you can configure fan speed on per sensor basis.

I use the simple mode here, since ThinkPad P14s is a relatively small device and one component heating up contributes to the heating of the whole device, so using the highest temperature of all sensors work well.

Each entry of this section is an array of 3 values, where:

  • first item – is the fan speed level to use;
  • second item – is the temperature at which thinkfan should drop the fan speed to the previous level;
  • third item – is the temperature at which thinkfan should step up the fan speed to the next level.

Let’s take a few entries as an example to better understand what happens there:

- [1, 35, 42]
- [2, 40, 45]

When the temperature reaches 42°C, thinkfan will change the fan speed to level 2. Once the temperature drops down to 40 degrees thinkfan will change the fan speed to level 1.

Having a bit of overlapping between ramp up and drop down make the speed changes a bit smoother.

Check fan speeds available

To check what fan speeds you can use with your laptop, you can run the following command:

cat /proc/acpi/ibm/fan

The output should look somewhat like this:

status:         enabled
speed:          3370
level:          4
commands:       level <level> (<level> is 0-7, auto, disengaged, full-speed)
commands:       enable, disable
commands:       watchdog <timeout> (<timeout> is 0 (off), 1-120 (seconds))

Bonus

If you’re also using ThinkPad P14s (Gen 2) with Intel CPU, you might have noticed that it doesn’t support S3 sleep state. You can technically turn it on in the BIOS, but I found it not working well. For example, the touchscreen didn’t work after laptop wakes up. Therefore I decided to stick with the default S2idle (used for Windows 10 and Linux by default).

Apart from power saving issues of that sleep state (we are not going to discuss those in this article), there’s another rather annoying issue: the fan doesn’t power off after you close the laptop lid and it enters the sleep state.

Luckily, if you already have thinkfan installed, it can help you with that issue as well!

Apart from thinkfan.service systemd unit, thinkfan provides a few extra units:

  • thinkfan-sleep.service – executed when the system is going to sleep;
  • thinkfan-wakeup.service – executed when the system is waking up from sleep.

We’re going to use those units to disable the fan when the system goes to sleep and to enable when it wakes up.

thinkfan-sleep.service

First, let’s change thinkfan-sleep.service.

sudo nano /lib/systemd/system/thinkfan-sleep.service

You should put a new line at the end of Service block:
ExecStart=/usr/bin/bash -c '/usr/bin/echo disable > /proc/acpi/ibm/fan'

So the file would look like that:

[Unit]
Description=Notify thinkfan of imminent sleep
Before=sleep.target

[Service]
Type=oneshot
ExecStart=/usr/bin/pkill -x -winch thinkfan
# Hack: Since the signal handler races with the sleep, we need to delay a bit
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/bash -c '/usr/bin/echo disable > /proc/acpi/ibm/fan'

[Install]
WantedBy=sleep.target

thinkfan-wakeup.service

Now, let’s change thinkfan-wakeup.service.

sudo nano /lib/systemd/system/thinkfan-wakeup.service

You should put a new line into Service block, right after Type=oneshot, but before ExecStart=...:
ExecStart=/usr/bin/bash -c '/usr/bin/echo enable > /proc/acpi/ibm/fan'

So the file would look like that:

[Unit]
Description=Reload thinkfan after waking up from suspend
After=sysinit.target
After=suspend.target
After=suspend-then-hibernate.target
After=hybrid-sleep.target
After=hibernate.target

[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c '/usr/bin/echo enable > /proc/acpi/ibm/fan'
ExecStart=/usr/bin/pkill -x -usr2 thinkfan

[Install]
WantedBy=sleep.target

Apply the changes

Now to apply the changes run:

sudo systemctl daemon-reload

And you’re good. Now whenever your laptop goes to sleep, even in s2idle state the fan will be turned off.

Summary

Thanks to the flexibility of Linux we can control the fan speed however we want, regardless of the factory setup.

I hope this wasn’t too hard and you got a better understanding of how to set thinkfan up.

If you were able to come up with fan speed settings that you like more, please, do let me know about your configs in the comment section below.

Thank you and happy hacking!

Like it? Share it!

Leave a comment

Your email address will not be published.

27 thoughts on “How to control ThinkPad P14s’ fan speed in Linux”

    • Andrei Nevedomskii
        • Andrei Nevedomskii
    • Andrei Nevedomskii
    • Andrei Nevedomskii
      • Andrei Nevedomskii
          • Andrei Nevedomskii
              • Andrei Nevedomskii
                  • Andrei Nevedomskii
    • Andrei Nevedomskii
        • Andrei Nevedomskii
            • Andrei Nevedomskii