Some shitass tool to replace other shitass tools that don't get the job done of stopping a laptop from heat death.
Find a file
2026-04-21 02:30:14 +02:00
sleep init 2026-04-20 23:42:50 +02:00
systemd init 2026-04-20 23:42:50 +02:00
deploy.sh disable competing legiond 2026-04-20 23:52:53 +02:00
legion-thermal-gov tighten recovery band 2026-04-21 02:30:14 +02:00
README.md init 2026-04-20 23:42:50 +02:00
thermal-cap-ac.yaml fan bounce tuning 2026-04-21 02:27:07 +02:00

legion_thermals

Thermal management for the Lenovo Legion with AMD Ryzen 9 7945HX on Linux.

Targets sustained CPU temperatures at or below 85°C with fans capped at 3500 RPM, without relying on ryzenadj (which the Lenovo EC resets within seconds).

How it works

Two independent layers:

1. Thermal governor (legion-thermal-gov) A daemon that polls k10temp Tctl every 500ms and walks scaling_max_freq up or down proportionally. The Linux cpufreq layer enforces this limit — the firmware EC has no mechanism to override it.

  • Normal overshoot (>82°C): steps down 400 MHz × overshoot multiplier (up to 1.6 GHz/s)
  • Emergency (>88°C): drops 1.2 GHz in a single step
  • Recovery (<77°C): rises slowly at 100 MHz/tick so temps don't immediately spike again
  • Also sets energy_performance_preference to balance_power on all cores at startup, which softens the initial all-core boost ramp before the governor can react

2. Fan curve (thermal-cap-ac.yaml) Written directly to the EC via legion_cli. Hard-capped at 3500 RPM. Uses 5°C hysteresis at every band transition and slow deceleration throughout to prevent fan hunting.

Platform profile is set to balanced on boot, giving the EC a moderate TDP baseline to work from.

Files

legion-thermal-gov              Governor daemon → /usr/local/bin/
thermal-cap-ac.yaml             Fan curve preset → /etc/legion_linux/
systemd/
  legion-thermal-gov.service    Runs the governor on boot
  legion-fancurve.service       Applies fan curve + platform profile on boot and resume
sleep/
  legion-resume                 Re-applies fan curve after suspend → /lib/systemd/system-sleep/
deploy.sh                       Installs everything

External dependencies

1. lenovolegionlinux (DKMS + CLI)

Provides the legion_laptop kernel module and legion_cli tool.

The package is in Ubuntu 26.04 (Resolute). On Ubuntu 24.04 / Linux Mint 22.x, install the .deb files directly from Launchpad:

https://launchpad.net/ubuntu/+source/lenovolegionlinux/0.0.20+ds-1.1

Download and install these three packages for amd64:

  • lenovolegionlinux-dkms_0.0.20+ds-1.1_amd64.deb
  • legiond_0.0.20+ds-1.1_amd64.deb
  • python3-legion-linux_0.0.20+ds-1.1_all.deb
sudo apt-get install -y dkms linux-headers-$(uname -r) python3-pyqt5 python3-yaml python3-argcomplete
sudo dpkg -i lenovolegionlinux-dkms_*.deb legiond_*.deb python3-legion-linux_*.deb

2. Kernel requirements

  • Kernel 6.x recommended (6.17+ confirmed working)
  • amd_pstate=active must be the active driver:
    cat /sys/devices/system/cpu/amd_pstate/status   # should print "active"
    
    If it shows passive or guided, add amd_pstate=active to your kernel cmdline in /etc/default/grub and run sudo update-grub.

3. Required system packages

sudo apt-get install -y dkms linux-headers-$(uname -r)

Installation

git clone <this-repo> /home/user/Code/legion_thermals
cd /home/user/Code/legion_thermals
./deploy.sh

deploy.sh will re-invoke itself with sudo if not already root.

Monitoring

# Live governor log (freq adjustments)
journalctl -u legion-thermal-gov -f

# Live temp + freq cap
watch -n 0.5 "
  echo CPU: \$(( \$(cat /sys/class/hwmon/hwmon4/temp1_input) / 1000 ))°C
  echo Cap: \$(( \$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq) / 1000 ))MHz
  echo Fan1: \$(cat /sys/class/hwmon/hwmon9/fan1_input) RPM
  echo Fan2: \$(cat /sys/class/hwmon/hwmon9/fan2_input) RPM
"

Note: hwmon4 (k10temp) and hwmon9 (legion_hwmon) indices may differ after a reboot. Run grep -l k10temp /sys/class/hwmon/*/name and grep -l legion /sys/class/hwmon/*/name to find the correct indices.

Tuning

All tuning knobs are variables at the top of legion-thermal-gov. Edit the file then restart the service:

sudo nano /usr/local/bin/legion-thermal-gov
sudo systemctl restart legion-thermal-gov
Variable Default Effect
TARGET_TEMP 82000 Start throttling above this (millidegrees)
RECOVER_TEMP 77000 Only recover freq below this
CRITICAL_TEMP 88000 Emergency 1.2 GHz drop threshold
FREQ_CEILING 4500000 Max allowed frequency in kHz
FREQ_FLOOR 1800000 Min allowed frequency in kHz
FREQ_STEP 400000 Normal step size per tick (kHz)
FREQ_STEP_CRITICAL 1200000 Emergency step size (kHz)
FREQ_RECOVER 100000 Recovery step size per tick (kHz)
INTERVAL 0.5 Poll interval in seconds

Fan curve is edited in thermal-cap-ac.yaml. After editing, redeploy it:

sudo cp thermal-cap-ac.yaml /etc/legion_linux/
sudo legion_cli fancurve-write-preset-to-hw thermal-cap-ac --preset-dir /etc/legion_linux

Uninstalling

sudo systemctl disable --now legion-thermal-gov.service legion-fancurve.service
sudo rm /usr/local/bin/legion-thermal-gov
sudo rm /etc/systemd/system/legion-thermal-gov.service
sudo rm /etc/systemd/system/legion-fancurve.service
sudo rm /lib/systemd/system-sleep/legion-resume
sudo rm /etc/legion_linux/thermal-cap-ac.yaml
sudo rm /etc/modules-load.d/legion.conf
sudo systemctl daemon-reload