Problem

Ziel: Lüfterkurve der Radeon RX 7900 XT (RDNA3) unter CachyOS/Arch Linux temperaturgesteuert über ein Python-Script regeln. Ruhiger Betrieb im Leerlauf, aggressives Kühlen bei Last.

Fehlerbild

Der klassische hwmon-Weg (/sys/class/hwmon/hwmon2/pwm1) schlug vollständig fehl:

  • pwm1_enable = 1 (manual) schreiben → Write OK, aber sofort zurück auf 2
  • pwm1 schreiben → EINVAL (weil enable=2 = Auto)
  • fan1_targetENODATA
  • fan1_enable → springt zurück auf 0
  • power_dpm_force_performance_level=manual → Write OK, liest sofort auto zurück
  • rocm-smi --setfan → „Not supported on the given system“

Analyse

Die RX 7900 XT nutzt den AMD SMU 13.0.4 (Navi31, RDNA3). Das pp_features-Interface zeigt Bit 30 als FAN_CONTROL: enabled. Versuche, dieses Feature zur Laufzeit zu deaktivieren (echo "30 0" > pp_features), scheiterten mit EINVAL.

Ursache: Der SMU-Firmware-Chip auf RDNA3-Karten übernimmt nach GPU-Init die vollständige autonome Steuerung von pwm1_enable. Jeder Schreibversuch auf den Standard-hwmon-Pfad wird von der Firmware sofort rückgängig gemacht.

Lösungsweg

Die Lösung ist das OverDrive-Interface (gpu_od), das speziell für RDNA3 im amdgpu-Treiber implementiert ist:

/sys/devices/pci.../gpu_od/fan_ctrl/fan_curve
/sys/devices/pci.../gpu_od/fan_ctrl/fan_zero_rpm_enable
/sys/devices/pci.../gpu_od/fan_ctrl/fan_minimum_pwm
/sys/devices/pci.../pp_od_clk_voltage   ← commit mit "c"

Über dieses Interface programmiert man eine 5-Punkte-Kurve direkt in die SMU-Firmware. Die Firmware übernimmt die Kurve und regelt den Lüfter anhand der Hotspot-Temperatur selbstständig — korrekt, stabil, ohne Konflikte mit dem Kernel.

Änderungen & Fix

fancurve.service (/usr/local/bin/fancurve, Python-Daemon):

  • Schreibt beim Start die 5-Punkte-Kurve in gpu_od/fan_ctrl und committed
  • Überwacht alle 30 s ob die Kurve noch aktiv ist (nach Resume/Driver-Reset)
  • Stellt beim Stopp die Firmware-Standardkurve wieder her (echo "r" > pp_od_clk_voltage)
Kurve (Hotspot °C → Lüfter-Duty %):
30°C → 23%   55°C → 23%   72°C → 45%   83°C → 65%   95°C → 90%

fanmon (/usr/local/bin/fanmon) — interaktives TUI-Script:

  • Zeigt alle Sensoren: GPU (Junction/Edge/Memory/Fan), CPU (k10temp), Gehäuse-Lüfter (nct6687), NVMe
  • Live-Balken mit Farbkodierung (grün/gelb/rot)
  • Kurven-Editor: Taste e → Punkte per Pfeil-/Zifferntasten anpassen → Enter speichert direkt in Firmware + patcht Daemon

Überlebt Updates?

WasSicher?Grund
Paket-Updates (pacman)✅ Ja/usr/local/bin/ und /etc/systemd/system/ nicht unter pacman
Kernel-Update minor✅ Jagpu_od-Interface stabil seit amdgpu ≥ 6.6
Reboot / Suspend-Resume✅ Jafancurve.service re-applyed automatisch
coolercontrol-Update⚠️ Prüfenconfig.toml könnte überschrieben werden → amdgpu ggf. neu deaktivieren
Kernel Major / amdgpu-Pfad-Änderung⚠️ SeltenGPU_DEV-Pfad in fancurve.py und fanmon.py ggf. anpassen

Fazit

Der Standard-hwmon-Weg funktioniert bei RDNA3 grundsätzlich nicht — der SMU 13.0.4 verhindert das auf Firmware-Ebene. Die korrekte Methode ist gpu_od/fan_ctrl (OverDrive-Interface), das eine direkte Programmierung der Firmware-Kurve erlaubt. Einmal gesetzt, steuert die Firmware den Lüfter selbst nach der eigenen Kurve — stabil, ohne dauernde Schreibversuche vom Host.

⬇ Downloads

Alle Dateien für diesen Post — direkt einsatzbereit auf CachyOS / Arch Linux.

🐍
fancurve.py
Python-Daemon · RDNA3 OD-Firmware Kurve · systemd-kompatibel · Hysteresis + Auto-Reapply
⬇ Download
⚙️
fancurve.service
systemd Unit · Autostart, Restart on-failure, sauberes Stopp mit Kurven-Reset
⬇ Download
📊
fanmon.py
TUI Monitor · GPU/CPU/Gehäuse Temps + RPM · Kurven-Editor (Taste e) · Keine externen Abhängigkeiten
⬇ Download
📋
Installation (Schnellstart)
sudo install -m755 fancurve.py /usr/local/bin/fancurve && sudo install -m644 fancurve.service /etc/systemd/system/ && sudo systemctl enable --now fancurve