Optimizing the Nvidia dGPU on Manjaro

manjaro 26 / published / guide #59 / ≈ 6 min read

Manjaro on a laptop with both an Intel iGPU and an Nvidia dGPU (the typical "Optimus" setup) has one annoying default: the discrete card never fully sleeps. The driver itself idles down to power-state P8, but the PCI link stays at D0 forever, and the card keeps drawing a couple of watts even when nothing is using it. On battery, that's real. This guide turns on the missing piece — PCI runtime power management — so the dGPU actually reaches the lowest sleep state (D3cold, ~0 W). It also covers the right way to run an app on the dGPU on demand, and the wrong way that breaks on Wayland.

Who this is for: a Manjaro laptop using video-hybrid-intel-nvidia-prime (the mhwd profile installed automatically on Intel+Nvidia notebooks). Desktops with only an Nvidia card don't need any of this — there's no other GPU to fall back to.

Step 1: Confirm the mhwd profile

Check what mhwd installed and which driver each card is using:

mhwd --listinstalled
inxi -G                                # which renderer is active

If you see video-hybrid-intel-nvidia-prime in the list and inxi -G shows Intel as the active renderer with the Nvidia card present but idle, you're in the right setup. If mhwd --listinstalled shows the bare video-nvidia driver instead, that profile runs everything on the dGPU all the time — runtime PM doesn't apply to it.

Step 2: Verify the driver-side power-management knob

The Nvidia driver has a runtime-PM mode that has to be opted into via a module option. mhwd usually does this for you, but check:

grep -r NVreg_DynamicPowerManagement /etc/modprobe.d/ /usr/lib/modprobe.d/

You should see options nvidia NVreg_DynamicPowerManagement=0x02 somewhere. If it's missing, add it and rebuild the initramfs:

echo 'options nvidia NVreg_DynamicPowerManagement=0x02' 
  | sudo tee /etc/modprobe.d/nvidia-pm.conf
sudo mkinitcpio -P

Reboot afterwards so the new module option takes effect.

Step 3: Install the udev rule

This is the missing piece. Without it, Linux never tells the dGPU's PCI link that it's allowed to autosuspend. The rule flips power/control from on to auto on each Nvidia function as soon as its driver binds at boot.

Use sudoedit rather than a heredoc — pasting these long lines through a heredoc can silently line-wrap and quietly break the file. Each rule must be one physical line:

sudoedit /etc/udev/rules.d/80-nvidia-pm.rules

Paste these exactly six lines:

ACTION=="bind",   SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="bind",   SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="bind",   SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", TEST=="power/control", ATTR{power/control}="on"

The three classes are the three PCI functions of a typical dGPU: 0x030000 is the VGA controller, 0x030200 is the 3D controller, 0x040300 is the HDA audio function that drives HDMI/DisplayPort audio.

Verify the file is exactly six lines — if it's more, your terminal wrapped one of them and the rule will silently not match:

wc -l /etc/udev/rules.d/80-nvidia-pm.rules
# expect: 6

Step 4: Reboot and verify

The rule fires on driver bind, which only happens at boot. Setting power/control=auto on an already-running device doesn't initialise Nvidia's runtime-PM machinery — you have to reboot.

After reboot, let the machine sit idle for ten seconds, then check four things:

cat /sys/bus/pci/devices/0000:01:00.0/power/control
# expect: auto

cat /sys/bus/pci/devices/0000:01:00.0/power/runtime_status
# expect: suspended

cat /proc/driver/nvidia/gpus/0000:01:00.0/power | grep "Video Memory"
# expect: Video Memory: Off

nvidia-smi --query-gpu=pstate,power.draw --format=csv
# expect: P8, ~0 W (and nvidia-smi may refuse to talk to the card at all
# when it is suspended — that is the real success signal)

The Video Memory: Off line is the one that matters. runtime_status: suspended means Linux thinks the device is asleep; Video Memory: Off confirms the card actually reached D3cold rather than just driver-side idle.

One quirk: cat /sys/bus/pci/devices/0000:01:00.0/power/autosuspend_delay_ms returning Input/output error is normal. Nvidia's driver manages its own suspend timing instead of using the generic PCI autosuspend timer.

Step 5: Run an app on the dGPU on demand

Now that the card sleeps, you need a way to wake it for the apps that should use it (games, CUDA, Blender, video editors). The right tool is prime-run:

sudo pacman -S nvidia-prime
prime-run glxinfo | grep "OpenGL renderer"      # should mention Nvidia, not Intel
prime-run blender                                # any app you want on the dGPU

Under the hood, prime-run sets a few environment variables (__NV_PRIME_RENDER_OFFLOAD=1, __GLX_VENDOR_LIBRARY_NAME=nvidia, and friends) so OpenGL and Vulkan calls go to the Nvidia card. When the app exits, the card goes back to sleep on its own.

Step 6: Don't use optimus-manager on Wayland

The older optimus-manager tool used to be the standard answer for hybrid graphics in the X11 era. On Wayland it's broken: its state machine waits for an Xorg start that never comes, so the daemon hangs in pending_post_xorg_start and the Qt UI fatals when you open it. prime-run is the modern replacement and works fine on Wayland.

If you already have optimus-manager installed, migrate off it cleanly:

sudo systemctl disable --now optimus-manager.service
sudo pacman -Rns optimus-manager optimus-manager-qt
sudo rm -f /etc/X11/xorg.conf.d/10-optimus-manager.conf
sudo rm -rf /var/lib/optimus-manager /var/log/optimus-manager
sudo find /etc /usr/lib -name "*optimus-manager*"     # confirm nothing remains

Substitute optimus-manager-git in the -Rns line if you installed the AUR -git variant.

Further tweaks worth a pass

Not Nvidia-specific, but they tend to come up in the same "make this laptop quieter" sweep:

  • Stale /etc/modules-load.d/ entries. If systemctl --failed shows systemd-modules-load.service in red, look at the files under /etc/modules-load.d/ — one of them is asking the kernel to load a module the kernel rejects. A common culprit on MSI laptops is a leftover msi-ec.conf. Delete the offending file, run sudo systemctl restart systemd-modules-load.service, and re-check systemctl --failed.
  • NetworkManager-wait-online.service blocks network-online.target for up to 30 seconds on boot. Most server-style daemons (docker, mariadb, sshd) have their own reconnect logic and don't need it. sudo systemctl disable --now NetworkManager-wait-online.service shaves a noticeable chunk off boot time on a laptop that connects to Wi-Fi after login anyway.
  • Btrfs noatime mount option. The Btrfs default of relatime writes access-time updates on every read past a threshold. Add noatime to your Btrfs entries in /etc/fstab, then sudo mount -o remount / (and the same for any other Btrfs mounts). Slightly less SSD wear, slightly faster reads.

What NOT to install

  • optimus-manager on Wayland — see step 6.
  • tlp / auto-cpufreq — both conflict with power-profiles-daemon, which is what KDE's battery widget integrates with on a default Manjaro install. Pick one. PPD is the modern recommendation; the other two are vestiges from before KDE picked up native PPD support.
  • thermald — superseded by the kernel's own intel_pstate thermal handling on any reasonably recent kernel. Only worth installing if you actually observe sustained thermal throttling.

That's the whole pass. On a typical Intel+Nvidia laptop expect ~2–3 W of continuous savings on battery, and the dGPU only wakes when you actively ask for it via prime-run.

← back to index