Realtek Rtl8125b Aspm

Enabling ASPM on a Realtek RTL8125B 2.5GbE NIC in Proxmox/Linux

If you’re running a home server or a Proxmox node and you want to add 2.5GbE networking without spending a lot of money, the Realtek RTL8125B is a pretty popular option. It’s inexpensive, widely available, and comes in a few different form factors, including standard PCIe and M.2 A+E, which is the slot that normally sits empty once you’ve pulled out the Wi-Fi card. Handy if you’ve run out of PCIe slots.

On Linux and Proxmox, the card will get picked up automatically by the r8169 driver, which is the kernel’s built-in driver for a wide range of Realtek NICs. However, not only is there a significant performance deficit compared to the dedicated r8125 driver, there’s also a significant catch worth knowing about.

Lenovo 2.5gbe
Realtek RTL8125B PCIe 1×2.5GbE NIC installed in a Lenovo M720q micro PC.

ASPM (Active State Power Management)

The main practical difference between the generic r8169 driver and Realtek’s dedicated r8125 driver comes down to power management. Specifically, ASPM (Active State Power Management) which is the mechanism that allows PCIe devices to drop into low-power states when they’re not doing much.

In r8169, ASPM support is disabled by default for the RTL8125 chip. The reason goes back to early hardware revisions of the card, which had stability issues when entering low-power states while linked at 2.5GbE. Realtek’s fix was to disable ASPM for affected cards, but the re-enable never made it back into r8169 for the newer, fixed revisions. The real-world consequence of this is that if you’re running an Intel CPU, your processor won’t be able to reach C-states beyond C2 or C3 at idle.

lscpi output for Realtek RTL8125 NIC using r8169 driver showing ASPM Disabled
root@hostname:~# lspci -knn | grep -iA3 net

01:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller [10ec:8125] (rev 05)
        Subsystem: Realtek Semiconductor Co., Ltd. Device [10ec:0123]
        Kernel driver in use: r8169
        Kernel modules: r8169
        
        
root@hostname:~# lspci -vv | awk '/ASPM/{print $0}' RS= | grep --color -P '(^[a-z0-9:.]+|ASPM;|Disabled;|Enabled;)'

00:01.0 PCI bridge: Intel Corporation 6th-10th Gen Core Processor PCIe Controller (x16) (rev 07) (prog-if 00 [Normal decode])
                LnkCtl: ASPM L1 Disabled; RCB 64 bytes, LnkDisable- CommClk+
01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
                LnkCtl: ASPM L1 Disabled; RCB 64 bytes, LnkDisable- CommClk+

The r8125 driver, by contrast, supports ASPM out of the box. So the fix is either to swap drivers or to manually re-enable ASPM, which is exactly what the rest of this post covers.

Option 1: Manually Enable ASPM on r8169 Driver

If you’d rather stick with the built-in r8169 driver and just fix the ASPM issue, you can do that by poking the setting directly through the kernel’s sysfs interface. No extra drivers needed. First, find your device’s PCI address:

Bash
#Find your device's PCI address
lspci | grep -i realtek

You’re looking for something like “03:00.0 Ethernet controller: Realtek….” That 03:00.0 part is your device ID. Once you have it, you can enable L1 ASPM with:

Bash
#Enabling L1 ASPM, replacing 0000:03:00.0 with your actual device path.
echo 1 > /sys/bus/pci/devices/0000:03:00.0/link/l1_aspm

The catch with this approach is that it doesn’t survive a reboot. To make it persistent, we can create a simple onestop systemd service:

Bash
#Create a service file
nano /etc/systemd/system/aspm-rtl8125.service


#Paste the following into this file
[Unit]
Description=Enable ASPM L1 for Realtek RTL8125B
After=network.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo 1 > /sys/bus/pci/devices/0000:03:00.0/link/l1_aspm'
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

We’ll reload the systemd daemon to recognise the new file, then enable it so it runs on every boot:

Bash
systemctl daemon-reload

systemctl enable --now aspm-rtl8125.service

An alterative way to implement this option is with a bash script, first developed by Matt Gadient, which we can run at reboot in our crontab:

Bash
#!/bin/bash

# Warning: Use at your own risk. Created to aid with the Realtek C-State issues mentioned at:
# https://mattgadient.com/7-watts-idle-on-intel-12th-13th-gen-the-foundation-for-building-a-low-power-server-nas/

# INSTRUCTIONS:

# Rename this to end in .sh, then run it, maybe like this:
#     mv RTL8125-ASPM.sh.txt RTL8125-ASPM.sh
#     chmod +x RTL8125-ASPM.sh
#     ./RTL8125-ASPM.sh

# This will attempt to enable ASPM L1 on a Realtek RTL8125 and/or RTL8168, as recent Linux kernels
# disable L1 on most Realtek Ethernet adapters due to issues experienced by some
# users. This must be run as sudo/root. If it doesn't cause issues, run after each boot.

# You may need to change RTLDEVID from 0x8125 to the device ID of your Realtek network card.
# One way to find it is to run lspci, find the PCI ID of your Realtek Ethernet (example: 03:00.0),
# and then (using the 03:00.0 example above) type:
#    cat /sys/bus/pci/devices/0000\:03\:00.0/device
RTLVENID="0x10ec"
RTLDEVID="0x8125"
RTLDEVIDB="0x8168"

PCIDEVICES=$(ls /sys/bus/pci/devices/ | sort -u)
RTLFOUND=0
echo ""
echo "Checking for Realtek LAN and enabling ASPM L1"
for i in $PCIDEVICES; do
	DEVICEID=$(cat /sys/bus/pci/devices/$i/device)
	if [[ $DEVICEID == *"$RTLDEVID"* || $DEVICEID == *"$RTLDEVIDB"* ]]; then
		VENDORID=$(cat /sys/bus/pci/devices/$i/vendor)
		if [[ $VENDORID == *"$RTLVENID"* ]]; then
			echo " -Enabling L1 on /sys/bus/pci/devices/$i/link/l1_aspm"
			echo 1 > /sys/bus/pci/devices/$i/link/l1_aspm
			RTLFOUND=1
		fi
	fi
done
if [[ $RTLFOUND -eq 0 ]]; then
	echo " -Unable to find a matching PCI device with vendor id $RTLVENID and device id $RTLDEVID."
fi

Option 2: Install the r8125 DKMS driver

The cleaner long-term fix is to replace r8169 with Realtek’s dedicated r8125 driver. Since it compiles as a kernel module, you will have to recompile it every kernel update. Using the DKMS version, specifically awesometic’s well-maintained package on GitHub, means the driver will automatically rebuild itself whenever your kernel updates.

There are three ways to install it, and they’re listed here in order of recommendation.

Method A: Launchpad PPA (recommended)

This is the easiest and most maintainable approach. The PPA will keep the driver up to date alongside your other packages:

Bash
#Add the Launchpad PPA
sudo add-apt-repository ppa:awesometic/ppa

#Then install the package using apt tool
sudo apt install realtek-r8125-dkms

Method B: Debian package

If you’d rather not add a PPA, you can grab the latest .deb directly from the releases page on GitHub and install it manually:

Bash
#Install dkms
apt update && apt install -y dkms

#Download the latest .deb package from Github
wget https://github.com/awesometic/realtek-r8125-dkms/releases/download/9.016.01-1/realtek-r8125-dkms_9.016.01-1_amd64.deb

#Install
dpkg -i realtek-r8125-dkms_9.016.01-1_amd64.deb

#If dependency error occurs, try to fix that with apt command
apt install --fix-broken

Method C: dkms-install.sh

If you want to clone the repo and install directly from source, there’s a handy install script included:

Bash
git clone https://github.com/awesometic/realtek-r8125-dkms.git

cd realtek-r8125-dkms

sudo ./dkms-install.sh

Note: there’s also an autorun.sh in the repo, but that’s Realtek’s original script and it only installs the driver for the currently running kernel. It’s not a proper DKMS install, so it won’t survive a kernel update. Stick with dkms-install.sh unless you have a specific reason not to.

Blacklisting r8169 driver.

Whichever method you used, the driver won’t actually take over on its own yet. After installation, check whether r8169 is still loaded:

root@hostname:~# dkms status
realtek-r8125/9.016.01, 6.17.13-2-pve, amd64: installed


root@hostname:~# lspci -knn | grep -iA3 net
01:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller [10ec:8125] (rev 05)
        Subsystem: Realtek Semiconductor Co., Ltd. Device [10ec:0123]
        Kernel driver in use: r8169
        Kernel modules: r8169, r8125

If it shows up, you’ll need to blacklist it so r8125 can take priority. The repo’s README has a clean one-liner for this:

Bash
sudo tee -a /etc/modprobe.d/blacklist-r8169.conf > /dev/null <<EOT
# To use r8125 driver explicitly
blacklist r8169
EOT

Then update your initramfs and reboot:

Bash
sudo update-initramfs -u

sudo reboot

After coming back up, confirm the right driver is in use:

root@hostname:~# dkms status
realtek-r8125/9.016.01, 6.17.13-2-pve, amd64: installed


root@hostname:~# lspci -knn | grep -iA3 net
01:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller [10ec:8125] (rev 05)
        Subsystem: Realtek Semiconductor Co., Ltd. Device [10ec:0123]
        Kernel driver in use: r8125
        Kernel modules: r8169, r8125

Conclusion

Neither of these fixes is particularly complicated, but the payoff is real, especially if you’re running a home server or a Proxmox node that’s on 24/7. A NIC driver quietly blocking your CPU from reaching its deeper idle states is exactly the kind of thing that’s easy to miss, and equally easy to fix once you know it’s there.

If you just want something working quickly with minimal changes to your setup, the sysfs approach in Option 1 is perfectly fine. It’s two commands plus a systemd service and you’re done. If you’re thinking longer term, or you’d rather not have a brittle PCI address sitting in a service file, Option 2 with the DKMS driver is the tidier solution. The PPA route in particular means you can largely forget about it once it’s installed.

root@hostname:~# lspci -vv | awk '/ASPM/{print $0}' RS= | grep --color -P '(^[a-z0-9:.]+|ASPM;|Disabled;|Enabled;)'

00:01.0 PCI bridge: Intel Corporation 6th-10th Gen Core Processor PCIe Controller (x16) (rev 07) (prog-if 00 [Normal decode])
                LnkCtl: ASPM L1 Enabled; RCB 64 bytes, LnkDisable- CommClk+
01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8125 2.5GbE Controller (rev 05)
                LnkCtl: ASPM L1 Enabled; RCB 64 bytes, LnkDisable- CommClk+

Either way, once ASPM is working correctly you should see your CPU spending meaningful time in C6 and beyond at idle, rather than being stuck in the shallower states. How much of a difference that makes to your power draw will depend on your specific hardware, but on a modern Intel platform it’s not unusual to see idle consumption drop by a few watts. Over the course of a year running continuously, that adds up to something worth caring about.

Leave a Reply

Your email address will not be published. Required fields are marked *