Skip to content

jvdillon/rtx-laptop-linux

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 

Repository files navigation

Nvidia RTX Laptop Linux Power Management

Get proper battery life on Linux laptops with NVIDIA RTX GPUs.

TL;DR: By default, NVIDIA GPUs stay awake and drain ~6W constantly. This guide enables D3cold power states so the GPU sleeps when idle, doubling battery life on hybrid graphics laptops (tested: 20W → 10W idle).

The Problem

Linux hybrid graphics laptops with NVIDIA RTX GPUs have terrible battery life out of the box. The GPU never enters deep sleep (D3cold) because:

  1. GNOME Shell uses NVIDIA for EGL rendering - libglvnd loads 10_nvidia.json before 50_mesa.json, so the desktop compositor keeps the GPU awake permanently.

  2. The NVIDIA driver has bugs - Sleep/shutdown hangs, CPU spin bugs, and missing power management features require workarounds.

  3. System services keep the GPU awake - nvidia-persistenced, nvidia-settings, and even Chrome probe the GPU at startup.

  4. TLP fights against you - Default RUNTIME_PM_ON_AC=on forces all devices to stay awake on AC power.

Quick Start

git clone https://github.com/jvdillon/rtx-laptop-linux.git
cd rtx-laptop-linux
sudo ./setup.sh
# Reboot required

The script will:

  1. Install NVIDIA drivers (or prompt to reinstall if present)
  2. Apply all power management fixes
  3. Configure systemd services for proper sleep/wake handling

What the Setup Does

1. Demote NVIDIA EGL Priority

libglvnd loads EGL vendors by filename order. Renaming 10_nvidia.json to 90_nvidia.json ensures Mesa (Intel/AMD integrated) loads first.

sudo mv /usr/share/glvnd/egl_vendor.d/{10,90}_nvidia.json

2. Force Mesa EGL System-Wide

Even with the priority fix, some apps probe NVIDIA. This environment variable forces Mesa for all desktop rendering:

# /etc/environment
__EGL_VENDOR_LIBRARY_FILENAMES=/usr/share/glvnd/egl_vendor.d/50_mesa.json

3. Disable NVIDIA DRM Modesetting

With modeset=1, nvidia_drm takes over the display, preventing Intel from driving the panel. This also causes Plymouth hangs during boot.

sudo sed -i 's/modeset=1/modeset=0/' /etc/modprobe.d/nvidia-graphics-drivers-kms.conf

4. Fix nv_open_q CPU Spin Bug

Driver bug: the nv_open_q kernel thread spins at 20-70% CPU when nonblocking open is enabled (default).

# /etc/modprobe.d/nvidia-graphics-drivers.conf
options nvidia NVreg_EnableNonblockingOpen=0

Reference: NVIDIA/open-gpu-kernel-modules#615

5. Enable Runtime PM via udev

The GPU needs power/control=auto to enter D3cold. This udev rule sets it for all NVIDIA 3D controllers:

# /etc/udev/rules.d/80-nvidia-pm.rules
ACTION=="add|change|bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", ATTR{power/control}="auto"

6. Wake GPU Before Shutdown/Sleep

Driver bug: when the GPU is in D3cold, the driver can't cleanly unload or prepare for system sleep. This causes hangs after "Reached target Reboot" or sleep failures with error -5.

A systemd service wakes the GPU before any shutdown/sleep target:

# /etc/systemd/system/nvidia-wake.service
[Unit]
Description=Wake NVIDIA GPU before shutdown/sleep to prevent hangs
DefaultDependencies=no
Before=shutdown.target reboot.target halt.target suspend.target hibernate.target hybrid-sleep.target

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo on > /sys/bus/pci/devices/0000:01:00.0/power/control; sleep 1'

[Install]
WantedBy=halt.target reboot.target shutdown.target suspend.target hibernate.target hybrid-sleep.target

7. Fix Hibernate Resume

Driver bug: when nvidia modules are in initramfs, they load BEFORE hibernate resume. The kernel then tries to freeze a freshly-loaded driver that was never properly initialized, causing pci_pm_freeze(): nv_pmops_freeze returns -5.

Fix: exclude nvidia from initramfs so modules load AFTER hibernate resume.

Ubuntu 25.04+ (dracut):

# /etc/dracut.conf.d/nvidia-exclude.conf
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "

Ubuntu 24.04 LTS (initramfs-tools):

# /etc/initramfs-tools/hooks/exclude-nvidia
# Hook script that removes nvidia modules from initramfs

Also adds early i915 KMS for external display during LUKS decrypt.

References:

8. Restore Runtime PM After Boot/Resume

The nvidia driver sets power/control=on when it initializes, and our wake service sets it before sleep. Both prevent D3cold after boot/resume.

Two systemd units restore power/control=auto:

# /etc/systemd/system/nvidia-power-control.service (after boot)
[Unit]
Description=Enable NVIDIA GPU runtime power management
After=multi-user.target tlp.service

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo auto > /sys/bus/pci/devices/0000:01:00.0/power/control'

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/nvidia-resume.service.d/restore-pm.conf (after resume)
[Service]
ExecStartPost=/bin/bash -c 'echo auto > /sys/bus/pci/devices/0000:01:00.0/power/control'

9. Disable nvidia-persistenced

This service keeps the driver loaded even when the GPU is unused, preventing D3cold. Disabling it enables on-demand loading.

Trade-off: first CUDA call has ~1s latency while the driver loads.

sudo systemctl disable nvidia-persistenced

10. Enable nvidia suspend/hibernate/resume Services

These official NVIDIA services handle saving/restoring GPU state across suspend and hibernate:

sudo systemctl enable nvidia-suspend nvidia-hibernate nvidia-resume

11. Disable nvidia-settings Autostart

nvidia-settings spawns at login and keeps /dev/nvidia* open, preventing D3cold.

# ~/.config/autostart/nvidia-settings-autostart.desktop
[Desktop Entry]
Type=Application
Hidden=true

12. Prevent Chrome from Waking GPU

Chrome probes /dev/nvidiactl at startup even when not using GPU acceleration. Force it to use Mesa:

sudo sed -i 's|^Exec=/usr/bin/google-chrome-stable|Exec=env __NV_PRIME_RENDER_OFFLOAD=0 __GLX_VENDOR_LIBRARY_NAME=mesa /usr/bin/google-chrome-stable|' \
    /usr/share/applications/google-chrome.desktop

13. Configure TLP (if installed)

TLP defaults to RUNTIME_PM_ON_AC=on which forces all devices awake on AC power:

sudo sed -i '/^#*RUNTIME_PM_ON_AC/d; $ a RUNTIME_PM_ON_AC="auto"' /etc/tlp.conf

14. Rebuild initramfs

Apply the initramfs changes (nvidia exclusion, early i915):

sudo update-initramfs -u  # Ubuntu 24.04
sudo dracut --force       # Ubuntu 25.04+

Verification

After rebooting, verify the GPU enters D3cold when idle:

# Should show "suspended" when GPU is idle
cat /sys/bus/pci/devices/0000:01:00.0/power/runtime_status

# nv_open_q should be ~0% CPU (or not running)
ps aux | grep '\[nv_open_q\]'

# Power draw should be 8-12W idle (without heavy apps)
cat /sys/class/power_supply/BAT*/power_now | awk '{print $1/1000000 " W"}'

To wake the GPU for CUDA work:

nvidia-smi  # GPU wakes on-demand

Troubleshooting

GPU won't enter suspended state

Check what's keeping it awake:

# List processes using nvidia devices
sudo fuser -v /dev/nvidia*

# Check if any GL apps are running
lsof /dev/dri/card*

Common culprits: Discord, Slack, VS Code (Electron apps), OBS.

System hangs on shutdown/reboot

The wake service may not be running:

sudo systemctl status nvidia-wake.service
sudo systemctl enable nvidia-wake.service

Hibernate resume fails

Check if nvidia modules are in initramfs:

lsinitramfs /boot/initrd.img-$(uname -r) | grep nvidia

If they appear, the dracut config didn't take effect:

sudo update-initramfs -u

Screen corruption after resume

Try adding to kernel command line:

nvidia.NVreg_PreserveVideoMemoryAllocations=1

Hybrid-sleep doesn't work

Known NVIDIA driver bug (nv_restore_user_channels fails). Use suspend or hibernate instead - hybrid-sleep is fundamentally broken with these drivers.

Finding Your GPU PCI Address

The setup script auto-detects your GPU PCI address. The examples in this README use 0000:01:00.0 for illustration.

To find yours manually:

lspci -D | grep -i nvidia
# Example output: 0000:01:00.0 3D controller: NVIDIA Corporation...

If you need to update the systemd services manually, edit:

  • /etc/systemd/system/nvidia-wake.service
  • /etc/systemd/system/nvidia-power-control.service
  • /etc/systemd/system/nvidia-resume.service.d/restore-pm.conf

Driver Installation (Ubuntu)

For reference, here's how to install the NVIDIA driver and CUDA toolkit on Ubuntu 24.04+:

# Remove any existing nvidia packages
sudo apt purge -y '^nvidia-.*' '^libnvidia-.*' '^cuda-.*' '^libcuda-.*'
sudo apt autoremove -y

# Add NVIDIA CUDA repository
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt update

# Install open driver + CUDA toolkit
sudo apt install -y nvidia-open cuda-toolkit

# Add CUDA to PATH (~/.bashrc)
export PATH="/usr/local/cuda/bin${PATH:+:${PATH}}"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"

Enabling Profiling

To use nsys and other NVIDIA profiling tools without root:

# Allow profiling for all users
echo "options nvidia NVreg_RestrictProfilingToAdminUsers=0" | \
    sudo tee /etc/modprobe.d/nvidia-profiling.conf
sudo update-initramfs -u

# Set perf_event_paranoid
echo "kernel.perf_event_paranoid=2" | sudo tee /etc/sysctl.d/99-perf.conf
sudo sysctl -p /etc/sysctl.d/99-perf.conf

References

Tested On

  • LG Gram Pro 16" 2025 (RTX 5050 Mobile) - Ubuntu 25.10, 25.04
  • Ubuntu 24.04 LTS supported (uses initramfs-tools instead of dracut)
  • Should work on any hybrid graphics laptop with RTX 20-series or newer

License

Apache 2.0

About

Howto for setting up Nvidia rtx-mobile in linux.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages