Kernel Failure Behavior and Service Failure Policy

Rough draft for review, 2026-08-23.

This document records the research spike on what the Linux kernel and the amdgpu driver do when hwmon sysfs reads or writes fail at runtime. It defines the failure policy for the fan-control service.

Motivation

The MI25 is a datacenter GPU whose BIOS cannot control the fan. Without fan control, it overheats and shuts down the server. The service must re-establish fan control if at all possible. Understanding the kernel failure modes determines whether the service retries, exits, or degrades.

Kernel failure taxonomy

Verified 2026-08-23 against the kernel sources and the live system.

-EBUSY: device busy or not ready

The amdgpu driver gates every hwmon access through amdgpu_pm_dev_state_check (amdgpu_pm.c). It returns -EBUSY when:

The sysfs show and store functions propagate this error to the reader or writer. A read or write during GPU reset or suspend fails with -EBUSY.

This is a transient condition. The GPU reset completes and the device resumes.

-ENODEV: device removed

kernfs returns -ENODEV when the sysfs attribute node has been deactivated (fs/kernfs/file.c, kernfs_get_active_of). This happens after device removal: amdgpu_pci_remove calls drm_dev_unplug, which unregisters the DRM device and its sysfs tree. A read or write after removal fails with -ENODEV.

This is a permanent condition for the removed device. The hwmon directory disappears.

-EINVAL: interface misuse

The pwm1 store path rejects writes that are not in manual mode (amdgpu_hwmon_set_pwm1, amdgpu_pm.c). It logs “manual fan speed control should be enabled first” and returns -EINVAL. This is a service sequencing error, not a hardware failure: write pwm1_enable=1 before pwm1.

The pp_power_profile_mode store path rejects writes unless the performance level is manual. This is documented in amdgpu_pm.c (DOC: pp_power_profile_mode): “To select a profile or create a custom profile, first select manual using power_dpm_force_performance_level.” Verified live on beast.lan: writing profile 5 fails with -EINVAL under forced-high and under auto; it succeeds after writing manual.

Silent no-op: bNoFan

The Vega 10 fan-control path checks bNoFan (vega10_thermal.c, vega10_fan_ctrl_set_fan_speed_pwm). If bNoFan is set, the write returns 0 without changing the fan. bNoFan comes from the VBIOS fan table (vega10_processpptables.c, ATOM_VEGA10_PP_FANPARAMETERS_NOFAN).

On the MI25 on beast.lan, the fan attributes exist, so bNoFan is false. But a future driver or a different card could set it. A pwm1 write that returns success without effect is a control failure.

-EOPNOTSUPP: interface not supported

Some amdgpu power interfaces return -EOPNOTSUPP when the ASIC or driver version does not implement them. The fan service does not depend on any of these.

Service failure policy

The policy follows from the taxonomy.

Transient failure (-EBUSY): retry, keep last good PWM

This covers GPU reset, suspend, and boot-time initialization.

Permanent failure (-ENODEV): exit nonzero

Sequencing error (-EINVAL on pwm1): re-assert manual mode

Silent no-op (bNoFan): treat as control failure

Startup discovery failure: exit nonzero after timeout

Interaction with the COMPUTE profile

The service writes power_dpm_force_performance_level = manual and pp_power_profile_mode = 5 (COMPUTE) at startup. Verified live on beast.lan: this sequence succeeds. The COMPUTE profile lowers the SMU busy set point from 70 to 30 (vega10_hwmgr.c profile table), so the SMU boosts clocks eagerly under compute load and idles low. This matches the homelab goal: quiet and low-power at idle, maximum performance when running an LLM. The profile is a runtime setting; the service must re-apply it at every startup, after every GPU reset, and whenever a -EBUSY sequence ends.

References