If you find any mistakes here or anywhere else on my website, email website@CoryHufford.com.
August 13, 2026
Several years ago I bought an AMD RX 7900 XTX GPU. Since then, across many Linux kernel and driver versions and two distributions (Pop OS and, currently, EndeavourOS), I've had occasional GPU driver crashes during GPU-intensive tasks. The crashes cause these symptoms, in order:
I've done some sporadic troubleshooting of the issue over the years, and the
only thing that seems to eliminate the crashes completely is manually setting
the performance level of the GPU. You can get or set the GPU performance level
by reading or writing a power_dpm_force_performance_level file in
/sys/class/drm/. This directory contains a card[0-9]
subdirectory for each AMD GPU; since I also have an AMD CPU with an integrated
GPU, I have card0/ and card1 subdirectories. Each of
these contains a device/ subdirectory with files for getting and
setting various GPU parameters. The file structure, only including things
relevant to setting the performance level, looks like:
/sys/class/drm/
|- card0/
| |- device/
| |- device
| |- power_dpm_force_performance_level
| |- vendor
|
|- card1/
|- device/
|- device
|- power_dpm_force_performance_level
|- vendor
Note that the numbers assigned to devices in /sys/class/drm/ are
not stable and can change on reboot. For identifying which GPU is
card0 and which is card1, the vendor and
device files can be used. These files contain hexadecimal PCI IDs,
and the PCI ID Repository has tables of
known IDs. AMD's vendor ID is 1002 and AMD device ID 744c is for consumer Navi
31 GPUs (7900 XT/XTX/GRE and 7900M).
The power_dpm_force_performance_level file can be read to get
the current performance level and written to to set the performance level. Valid
values, according to the
Arch
wiki at the time of writing, are:
autolowhighmanualprofile_standardprofile_min_sclkprofile_min_mclkprofile_peakOn my machine, auto is the default mode and the problematic one.
Setting the performance level to low or high prevents
the crashes described above.
Below is the Bash script I use to identify the correct GPU and toggle its performance level. Use it at your own risk.
#!/usr/bin/env bash
set -euo pipefail
VENDOR_ID="0x1002" # AMD
DEVICE_ID="0x744c" # Consumer Navi 31 (RX 7900 XT/XTX/GRE, RX 7900M)
target=""
for card in /sys/class/drm/card[0-9]*; do
dev="${card}/device"
[[ -r "${dev}/vendor" && -r "${dev}/device" ]] || continue
if [[ \
"$(cat "${dev}/vendor")" == "${VENDOR_ID}" && \
"$(cat "${dev}/device")" == "${DEVICE_ID}" \
]]; then
target="${dev}/power_dpm_force_performance_level"
echo "Found GPU at ${card}"
break
fi
done
if [[ -z "${target}" || ! -e "${target}" ]]; then
echo "GPU not found, or the performance level file is missing" >&2
exit 1
fi
current="$(cat "${target}")"
case "${current}" in
high) next="low" ;;
*) next="high" ;;
esac
echo "Current: ${current}"
echo "Next : ${next}"
read -rp "Change? [y/N] " reply
if [[ "${reply}" =~ ^[Yy]([Ee][Ss])?$ ]]; then
echo "${next}" | sudo tee "${target}" > /dev/null
echo "Now: $(cat "${target}")"
fi
I don't do much Bash scripting, so to help me read this script in the future, a summary of some of the commands and Bash features used follows.
The options for
the set builtin used are:
-e-o <option-name>pipefail makes a pipeline fail if any
command in it fails (normally only the status of the last command is
considered)-uThe Bash conditional expressions used are:
-e <file><file> exists-r <file><file> exists and is readable-z <string><string> is zeroThe -r argument for read prevents backslashes from
escaping any characters. -p is just to provide a prompt.