You want more frames, but the driver is playing it safe
You installed a modern AMD Radeon GPU, booted into Fedora, and noticed the hardware never hits its advertised boost clocks. The fan ramps up aggressively, the GPU temperature stays moderate, and your game runs smoothly but feels artificially capped. You suspect the driver is being overly conservative. You want to push the power limit, adjust the fan curve, or lock a higher performance state. The open-source stack gives you direct access to these controls, but they are hidden behind virtual filesystem paths and kernel parameters that require a specific setup to work safely.
What the amdgpu driver actually does with your GPU
Fedora ships with the amdgpu kernel driver for all modern AMD Radeon hardware. By default, the driver runs in an automatic power management mode. It constantly polls the GPU temperature, shader load, and power draw, then adjusts clock speeds and voltage on the fly. This keeps the card cool and stable for general desktop use, but it also caps performance during sustained gaming or rendering workloads. The driver exposes hardware controls through the sysfs virtual filesystem. These files live under /sys/class/drm/ and look like regular text files, but writing to them sends direct commands to the kernel driver. The catch is that sysfs changes vanish on reboot, and some advanced controls remain locked until you explicitly tell the kernel to unlock them. Think of sysfs like a control panel that resets every time you flip the power switch. You need a way to save your settings before the system restarts.
Reboot before you debug. Half the time the symptom is gone.
Unlock the hardware controls
The first step is enabling full hardware control. The amdgpu driver ships with a feature mask that disables certain low-level tuning options to prevent users from accidentally bricking their hardware. You can override this mask by passing a kernel parameter at boot. The parameter tells the driver to expose all programmable features, including voltage offsets and fine-grained clock control.
Here is how to apply the parameter to every installed kernel version on your system.
sudo grubby --update-kernel=ALL --args='amdgpu.ppfeaturemask=0xffffffff'
# grubby modifies the GRUB configuration safely across kernel updates
# --update-kernel=ALL ensures the flag persists when you install a new kernel
# 0xffffffff tells the driver to expose all programmable features
Reboot the machine after running this command. The change does not apply to a running kernel. You can verify the parameter took effect by checking the boot arguments.
cat /proc/cmdline
# Look for amdgpu.ppfeaturemask=0xffffffff in the output
# If it is missing, grubby failed to write the configuration
# The kernel ignores unknown parameters, so typos will silently fail
Trust the package manager for kernel updates. Manual GRUB edits drift when dnf upgrade --refresh installs a new kernel version. grubby handles the rotation automatically and keeps your boot configuration in sync with the installed kernels.
Adjust clocks and power through sysfs
With the feature mask unlocked, you can switch the driver out of automatic mode. The driver needs to know you are taking manual control before it will accept clock or voltage commands. The power management state file controls whether the driver scales frequencies automatically or holds a fixed state.
Here is how to force the GPU into manual performance mode.
echo manual | sudo tee /sys/class/drm/card0/device/power_dpm_force_performance_level
# tee writes to the sysfs file while preserving root permissions
# manual disables the driver's automatic clock scaling algorithm
# The driver will now hold whatever clock state you assign next
Power limits are exposed through the hardware monitoring subsystem. The path includes a wildcard because newer kernels rename the hwmon directory dynamically to avoid naming collisions with other sensors. You can read the current cap and the absolute maximum the hardware supports.
Here is how to check your current power ceiling.
cat /sys/class/drm/card0/device/hwmon/hwmon*/power1_cap
cat /sys/class/drm/card0/device/hwmon/hwmon*/power1_cap_max
# power1_cap shows the active limit in microwatts
# power1_cap_max shows the hardware's absolute ceiling
# Divide the output by 1000000 to convert to watts
Setting a custom limit requires writing the new value back to the same file. The value must stay below the maximum cap, or the driver will reject it silently. The driver applies the change immediately without a reboot.
Here is how to apply a new power limit.
echo 180000000 | sudo tee /sys/class/drm/card0/device/hwmon/hwmon*/power1_cap
# 180000000 represents 180 watts in microwatts
# The driver applies the change immediately without a reboot
# Exceeding the max cap will cause the write to fail
Sysfs changes are volatile. They disappear when the system reboots or when the driver reloads. If you need these settings to survive a restart, you must automate them with a systemd service or rely on a tool that handles persistence natively.
Run journalctl first. Read the actual error before guessing.
Make sysfs changes survive a reboot
Manual sysfs tuning is useful for quick tests, but it requires automation for daily use. You can create a simple systemd user service that writes your preferred values on boot. The service runs after the graphical session starts, ensuring the GPU driver is fully initialized.
Here is how to create a persistent tuning service.
mkdir -p ~/.config/systemd/user
# User services live in the XDG config directory
# systemd automatically scans this path for new unit files
# The directory must exist before you create the service file
Create a unit file named gpu-tune.service in that directory. Add the [Unit], [Service], and [Install] sections. Use ExecStart to run your echo commands. Enable the service with systemctl --user enable gpu-tune.service. The service will now run every time you log in. This approach keeps your configuration in your home directory, separate from system-wide files in /etc/. User services do not require root privileges to enable, and they survive kernel updates without manual intervention.
Snapshot the system before the upgrade. Future-you will thank you.
Use CoreCtrl for a graphical workflow
Managing sysfs files manually works for quick tests, but it is tedious for daily use. CoreCtrl is a desktop application that wraps these same sysfs controls in a graphical interface. It also handles persistence, per-application profiles, and automatic fan curve generation. The application reads the same hardware monitoring nodes the kernel exposes, but it presents them as sliders and graphs.
Here is how to install CoreCtrl and configure permissions.
sudo dnf install corectrl
# dnf pulls the package from the official Fedora repositories
# CoreCtrl requires direct access to GPU sysfs paths
# The package includes a desktop entry and system tray icon
The application needs permission to read and write GPU control files without prompting for a password every time. Fedora groups hardware access under the video group by default. Adding your user to this group grants the necessary read-write access to the DRM subsystem.
Here is how to grant your user account the necessary permissions.
sudo usermod -aG video $USER
# -aG appends the group without removing existing memberships
# $USER expands to your current login name
# Group changes require a fresh login session to take effect
Log out and log back in. Launch CoreCtrl from the application menu. The interface will detect your GPU and expose sliders for core clock, memory clock, voltage offset, and fan curves. Apply your settings and enable the built-in persistence toggle. CoreCtrl writes a systemd user service that restores your profile on boot. The application also supports per-game profiles that trigger automatically when a specific executable launches.
Firewall rules do not apply to local sysfs writes. Trust the package manager. Manual file edits drift, snapshots stay.
Verify the changes are actually applied
Tweaking GPU parameters can cause instability if pushed too far. You need to watch temperatures and clock speeds in real time to confirm the driver is actually applying your changes. The sysfs temperature sensor reports values in millidegrees Celsius. You must divide the output by 1000 to get the actual temperature.
Here is how to monitor GPU temperature from the terminal.
watch -n 1 cat /sys/class/drm/card0/device/hwmon/hwmon*/temp1_input
# watch refreshes the output every second
# temp1_input reports temperature in millidegrees Celsius
# Divide the number by 1000 to get the actual temperature
For a more complete dashboard, radeontop provides a live view of GPU utilization, clock speeds, and power draw. It reads directly from the same sysfs nodes CoreCtrl uses. The tool requires root access to read certain performance counters that track shader engine activity.
Here is how to install and run the monitoring tool.
sudo dnf install radeontop
sudo radeontop
# radeontop requires root to read certain performance counters
# The terminal interface updates in real time
# Press q to exit when you are done monitoring
Run a stress test or launch your game after applying changes. Watch the clock frequencies and temperature readings. If the GPU drops back to base clocks or the temperature spikes past 85 degrees Celsius, reduce the power limit or revert the voltage offset. Stability testing takes patience. A crash during a benchmark is better than a crash during an important render.
If the boot menu is gone, GRUB rescue is your friend, not your enemy.
Common pitfalls and what the error looks like
Overclocking on Linux differs from Windows because the driver does not hide hardware limits behind a proprietary control panel. You are talking directly to the kernel. This means mistakes show up immediately.
If you see bash: /sys/class/drm/card0/device/power_dpm_force_performance_level: Permission denied, you forgot to run the command with sudo or through tee. The sysfs files are owned by root for security reasons. The kernel refuses unprivileged writes to prevent accidental hardware damage.
If your desktop freezes or the display goes black after applying a voltage offset, the GPU failed to initialize the new state. Hold the power button to force a shutdown, boot into recovery mode, and remove the kernel parameter or reset the sysfs values to auto. The amdgpu driver will recover automatically once you revert to safe defaults.
Another common issue is losing settings after a kernel update. Fedora updates the kernel frequently. The grubby command handles the feature mask, but sysfs scripts or third-party udev rules may break if the driver changes internal paths. Always test your configuration after a dnf upgrade --refresh. The weekly maintenance command pulls the latest kernel and driver packages. Verify your GPU controls still respond before running heavy workloads.
SELinux will not block sysfs writes for the amdgpu driver, but it will log denials if you try to run custom scripts from restricted directories. Check journalctl -xe if a tool refuses to apply settings. The x flag adds explanatory context and the e flag jumps to the end of the log. Most permission issues resolve by moving scripts to /usr/local/bin/ or adjusting file contexts.
When to use manual sysfs vs CoreCtrl vs default
Use the default automatic mode when you run a mixed workload of web browsing, video playback, and occasional gaming. Use manual sysfs tuning when you need to test a specific power limit or clock state for a benchmark and do not want to install extra software. Use CoreCtrl when you want persistent profiles, per-game settings, and a graphical fan curve editor. Stick to the stock driver settings when you prioritize system stability over maximum frame rates.