Environment
GPU: AMD RX 580 (Polaris10, 0x1002:0x67DF)
Driver: amdgpu 3.64.0
Kernel: Linux cachyos-x8664 7.0.9-1-cachyos
IP block: smu_v1_0_0 (powerplay)
Problem
Writing space-separated state indices to /sys/class/drm/cardN/device/pp_dpm_sclk in manual mode no longer constrains the GPU clock on Polaris hardware. The write is accepted by the kernel without error (exit 0, tee prints the value), but the driver silently rejects the SMU message and the GPU continues boosting to its maximum state.
Every write to pp_dpm_sclk produces the following kernel message:
amdgpu 0000:01:00.0: last message was failed ret is 255
ret=255 (0xFF) is an SMU firmware error indicating the state mask command was refused. The sysfs interface reports success while the underlying SMU transaction fails.
Steps to reproduce
echo manual | tee /sys/class/drm/cardN/device/power_dpm_force_performance_level
echo "0 1 2 3 4 5" | tee /sys/class/drm/cardN/device/pp_dpm_sclk
cat /sys/class/drm/cardN/device/pp_dpm_sclk
Expected: states 6 and 7 masked, GPU clock limited to state 5. Actual: all states remain active, GPU continues to use state 7. journalctl -k shows last message was failed ret is 255 on each write.
Analysis
This interface previously worked correctly and regressed at some point. The powerplay layer sends a soft state mask command to the SMU firmware; on affected Polaris parts the firmware rejects it with 0xFF but the sysfs write path does not propagate the error to userspace, returning 0 instead. The result is a silent no-op that is difficult to diagnose.
Workaround
Use the overdrive clock table interface instead. Enable it by adding amdgpu.ppfeaturemask=0xffffffff to kernel parameters, then cap individual DPM states directly using the full <state> <freq> <mv> syntax required by Polaris’s 8-entry OD table:
echo "s 6 1257 1150" | tee /sys/class/drm/cardN/device/pp_od_clk_voltage
echo "s 7 1257 1150" | tee /sys/class/drm/cardN/device/pp_od_clk_voltage
echo "c" | tee /sys/class/drm/cardN/device/pp_od_clk_voltage
Expected behaviour
Writes to pp_dpm_sclk in manual mode should constrain GPU clock states as documented. If the SMU rejects the command, the error should be surfaced to userspace (non-zero write return) rather than silently discarded.