
拯救者 Y9000P 2025 装 Linux 之后散热和噪音失衡,是社区里反复出现的抱怨。同一台机器,Windows 下 Legion Zone 一切正常,换到 Linux 就变成两种极端:要么风扇一直高转吵得没法专心,要么长时间编译、训练时 CPU 和 GPU 撞温度墙降频。硬件没坏,问题多半出在电源与风扇策略这一层。

先搞清楚问题出在哪
Windows 上 Lenovo Vantage / Legion Zone 通过 WMI 接口跟 EC(嵌入式控制器)通信,一键切换安静 / 均衡 / 野兽三档,背后同时调的是 PL1/PL2、GPU 动态加速、风扇曲线和键盘灯。Linux 这边没有对应的官方实现,开源社区的做法是 johnfanv2 维护的 LenovoLegionLinux 内核模块(模块名 legion-laptop),把一部分 WMI 接口翻译成 sysfs 文件。但主流发行版默认不加载它,所以「Linux 端没有官方 Legion Zone 替代」这句话是成立的。
另一层是 ACPI 风扇策略本身。Y9000P 2025 的 EC 固件在 Windows 端会综合 CPU Package 功率和 GPU Hot Spot 温度做加权控制,Linux 默认往往只读 CPU 一个数据源。某些早期 BIOS 下 ACPI 返回的 fan control 字段还可能存在兼容问题,pwm 写进去实际没生效——社区里「脚本写了风扇不转」的帖子,大多是这个原因。
再有一层是发行版自带的策略。Ubuntu 24.04、Debian 12、Fedora 40 这些默认装的 thermald 用的是 Intel 通用 thermal-conf.xml,对高功耗游戏本偏保守;power-profiles-daemon 的三档(power-saver / balanced / performance)也没把风扇曲线接进来。两边都不管,机器就处在策略真空里。
具体到表现,大致能分三类:
- 中段转速周期性波动,听着像高频啸叫,通常跟 pwm 写入频率过低或 dc-mode 切换有关;
- 温度还没上来风扇就拉到高转速,说明风扇曲线没被正确读取;
- 长时间编译或训练时撞温度墙降频,多半是 BIOS EC 没把 Windows 端的温控策略下发到 Linux。
这三类里,前两类靠调 pwm 就能缓解,第三类要动的是策略层,下面分开说。
动手之前先跑一组基线
写脚本之前先有对照数据,否则改完也不知道是变好还是变坏。
# 装压力测试工具
sudo apt install stress-ng s-tui
# CPU 压力
stress-ng --cpu $(nproc) --timeout 600 --metrics-brief
# 同时监控
s-tui # 终端热力图
nvidia-smi # GPU 端单独看温度与功耗
记录 10 分钟内 CPU Package 最高温度、CPU 实际功耗、GPU Hot Spot 和风扇 RPM 范围。CPU 功耗推荐走 RAPL:cat /sys/class/powercap/intel-rapl:0/energy_uj 读出来的是累计能量,要间隔几秒采样两次做差分再除以时间才是瞬时功耗,直接把这个数字当功耗值是常见的踩坑点。
确认温度与风扇读数
sensors # 查看 CPU 温度
nvidia-smi # 查看 GPU 温度与功耗
ls /sys/class/hwmon/ # 列出可用的 hwmon 设备
for d in /sys/class/hwmon/hwmon*; do echo "$d: $(cat $d/name 2>/dev/null)"; done
满载时记录 CPU Package id 0、CPU Tdie、GPU Edge、GPU Hot Spot,以及 fan1_input、fan2_input(CPU 风扇和 GPU 风扇有可能挂在两个不同的 hwmon 下)。hwmon 编号每台机器都不一样,下面这组只是常见情况的示意,别照抄:
hwmon4 = acpitz(CPU Package 虚拟读数)
hwmon5 = nvme(一般不参与风扇策略)
hwmon6 = nvidia(独显 GPU)
hwmon7 = coretemp(CPU 真实温度)
风扇 pwm 节点具体落在哪个 hwmon 下,以本机 sensors 和 /sys/class/hwmon/*/name 的输出为准。盲目沿用别人的编号,脚本会「看起来在工作」,实际写的是别的设备。
风扇策略脚本
新建 /usr/local/bin/y9000p-fan.sh:
#!/bin/bash
# 读取 CPU Package 温度,去掉小数部分
CPU_TEMP=$(sensors | awk '/Package id 0/ {print $4}' | tr -d '+°C' | cut -d. -f1)
# 读取 GPU 温度
GPU_TEMP=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits)
# 取大值作为决策依据
HIGH_TEMP=$(( CPU_TEMP > GPU_TEMP ? CPU_TEMP : GPU_TEMP ))
# 风扇 PWM 节点(按实际 hwmon 编号修改)
FAN_CPU="/sys/class/hwmon/hwmon7/pwm1"
FAN_GPU="/sys/class/hwmon/hwmon7/pwm2"
# 关键前提:先切到手动模式
echo 1 > "${FAN_CPU}_enable"
echo 1 > "${FAN_GPU}_enable"
case $HIGH_TEMP in
9[0-9]|[1-9][0-9][0-9])
# 90℃ 以上:全速
echo 255 > "$FAN_CPU"
echo 255 > "$FAN_GPU"
;;
7[5-9]|8[0-9])
# 75-89℃:较高转速
echo 180 > "$FAN_CPU"
echo 180 > "$FAN_GPU"
;;
6[5-9]|7[0-4])
# 65-74℃:中等转速
echo 120 > "$FAN_CPU"
echo 120 > "$FAN_GPU"
;;
*)
# 65℃ 以下:交还给主板自动曲线
echo 2 > "${FAN_CPU}_enable"
echo 2 > "${FAN_GPU}_enable"
;;
esac
sensors 输出的温度带小数点,$(( )) 只认整数,所以上面用 cut -d. -f1 先把小数截掉,不然脚本第一行就会报语法错误。阈值本身要按自己机器的实测曲线调,这里给的数字只是示意。
还有一个细节值得单独说:不少主板把 pwm=0 解释成「停转」,温度在阈值附近抖一下,风扇就会停了又启,反而更吵也更伤电机。低温段切回 pwmX_enable=2(自动)比直接写 0 稳得多。
用 udev 固定 hwmon 路径
hwmon 编号每次启动都会变,最稳的做法是按属性做软链接。新建 /etc/udev/rules.d/99-y9000p-hwmon.rules:
SUBSYSTEM=="hwmon", KERNEL=="hwmon*", ATTR{name}=="coretemp", SYMLINK+="hwmon-cpu"
SUBSYSTEM=="hwmon", KERNEL=="hwmon*", ATTR{name}=="nvidia", SYMLINK+="hwmon-gpu"
这里插一句,udev 的 SYMLINK 默认落在 /dev 下,链接指向 sysfs 里的 hwmon 目录,所以脚本里应该写 /dev/hwmon-cpu/pwm1,而不是 /sys/dev/hwmon-cpu/pwm1——后者这个路径根本不存在。这是这条规则最容易写错的地方,写错了 systemd 服务会一直重启但看不出原因。规则生效后,把脚本里的 FAN_CPU、FAN_GPU 换成 /dev/hwmon-cpu/pwm1 和 /dev/hwmon-gpu/pwm1 就行。
交给 systemd 托管
单独写一个循环守护脚本 /usr/local/bin/y9000p-fan-daemon.sh:
#!/bin/bash
while true; do
/usr/local/bin/y9000p-fan.sh
sleep 30
done
新建 /etc/systemd/system/y9000p-fan.service:
systemd 服务单元配置(Y9000P 2025 Fan Profile Service)
[Unit]
Description=Y9000P 2025 Fan Profile Service
After=multi-user.target nvidia-persistenced.service
Wants=nvidia-persistenced.service
After=suspend.target hibernate.target
[Service]
Type=simple
ExecStart=/usr/local/bin/y9000p-fan-daemon.sh
Restart=always
RestartSec=5
User=root
ExecStartPre=/bin/sleep 3
[Install]
WantedBy=multi-user.target
[Unit]、[Service]、[Install] 三段头一个都不能少,缺了 [Install] 段,systemctl enable 会报「No such file or directory」这类让人摸不着头脑的错误。
然后启用并验证:
sudo chmod +x /usr/local/bin/y9000p-fan.sh
sudo chmod +x /usr/local/bin/y9000p-fan-daemon.sh
sudo systemctl daemon-reload
sudo systemctl enable --now y9000p-fan.service
sudo systemctl status y9000p-fan.service
journalctl -u y9000p-fan.service -f
验证时盯三个点:sensors 看风扇 RPM 是否随温度变化;读 pwm1 和 pwm1_enable 看写入值有没有被内核接受(不同主板对 0 的定义不一样,有的是主板接管,有的是停转);跑 10 分钟 stress-ng 后 CPU 最高温度是否不再撞墙。
几个容易踩的坑
- 写入 pwm 没生效。很多主板默认
pwm1_enable = 2(自动模式),必须先echo 1 > pwm1_enable切手动再写 pwm 值。脚本里不处理这一步,journalctl 里只会安静地显示「写入成功」。 - 温度读数错位。有些机器的
Package id 0读的是 Tdie 而非真实核心温度,可以换Tctl或Tdie字段,或者直接用turbostat取核心温度。 - 睡眠唤醒后服务失效。Y9000P 2025 在 s2idle 唤醒后 hwmon 路径会重新生成,
[Unit]里加After=suspend.target hibernate.target还不够,[Service]里的ExecStartPre=/bin/sleep 3就是为了等 udev 重新加载。 - thermald 和自写脚本打架。先
sudo systemctl disable --now thermald,否则两套策略争抢 pwm 写入,风扇会呈现「呼吸式」抖动。 - BIOS 升级后失效。联想会不定期推 BIOS 更新,EC 行为可能跟着变,升级完记得重新校准阈值。
这五条里,第一条和第四条出现的频率最高,基本是第一次写风扇脚本必踩的。第三条比较隐蔽,因为服务状态看起来是 active 的,只有跑久了才会发现风扇不再响应。
现成方案值不值得用
觉得手写脚本太糙,可以看看 NBFC for Linux(nbfc-linux)。它移植了 Windows 端 NoteBook FanControl 的配置生态,Arch 系可以从 AUR 装(yay -S nbfc-linux),其它发行版一般要自己编译。它的配置库以老机型为主,Y9000P 2025 这种新机器多半没有现成 Model,装完先跑 nbfc list 确认,没有匹配项就按 EC 抓到的曲线自己写一份 XML,比硬套别人的配置靠谱。
社区讨论更多的是 legion-laptop 内核模块。它把 Legion Zone 的 WMI 接口翻译成 sysfs 文件,调曲线比粗暴写 pwm 优雅得多,前提是 DKMS 模块已加载且跟当前内核版本匹配,直接 modprobe 一般不会成功。至于 thinkpad_acpi 的 fan_control 接口,那是 ThinkPad 专用的,Y9000P 不是 ThinkPad,别把它当兜底方案。
最后
Linux 端没有 Legion Zone 这种一键面板,systemd 服务是相对干净的接管方式,但也绝不是装好就能忘的银弹。建议先用 sensors 把温度曲线跑一周再定阈值,网上传的「万能曲线」多数是特定 BIOS 版本下的产物,照搬容易翻车。这块官方文档确实少,社区维护的 NBFC、legion-laptop 内核模块、lm_sensors 是几条相对成熟的路子,优先从它们入手,遇到兼容性死角再考虑写自定义服务。
机器刚到手的话,顺序建议是:先刷到最新 BIOS,再装 lm_sensors 配好 legion-laptop(内核版本支持的话),最后才考虑要不要上自定义 systemd。顺序反了,会发现脚本写得再漂亮也跑不出 Windows 那种安静又凉快的体验。
你装 Linux 后用什么方案压散热?评论区聊聊。
如需选购适合的笔记本电脑,可参考 Thinkpad深圳报价。