Ubuntu: watchdog driver in /etc/modules-load.d is silently not loaded (sp5100_tco, iTCO_wdt)
On Ubuntu 24.04 with the HWE 7.0 kernel I wanted systemd's RuntimeWatchdogSec to pet the AMD FCH hardware watchdog (sp5100_tco), so a hung laptop-turned-server reboots itself. I put sp5100_tco in /etc/modules-load.d/watchdog.conf and set RuntimeWatchdogSec=30s in /etc/systemd/system.conf.d/watchdog.conf. After a reboot, lsmod showed no sp5100_tco, /dev/watchdog0 was missing, and the journal had no 'Using hardware watchdog' line. systemd-modules-load.service reported success and logged no error for the module. A manual sudo modprobe sp5100_tco loaded it at once and created /dev/watchdog0, so the driver and the firmware were both fine. Most guides say modules-load.d is the standard way to load a module at boot.
Root cause: Ubuntu's kernel packages ship /lib/modprobe.d/blacklist_linux_<version>.conf, which blacklists every watchdog driver (blacklist sp5100_tco, blacklist iTCO_wdt, softdog, and so on). systemd-modules-load loads modules through libkmod with the blacklist honored, so modules from modules-load.d that are on the list get skipped without an error. An explicit modprobe <name> ignores blacklist lines; they only affect alias and autoload lookups. That's why loading by hand works.
Check: grep -l sp5100 /lib/modprobe.d/*.
Fix: load it with an explicit modprobe early in boot, for example a oneshot unit:
# /etc/systemd/system/hw-watchdog.service
[Unit]
Description=Load hardware watchdog
DefaultDependencies=no
After=systemd-modules-load.service
Before=sysinit.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/modprobe sp5100_tco
[Install]
WantedBy=sysinit.targetRun systemctl enable hw-watchdog. You don't need daemon-reexec: PID 1 (systemd 255) opened /dev/watchdog0 as soon as the device appeared, and the journal shows Using hardware watchdog 'SP5100 TCO timer'. Overriding the blacklist with an install line or deleting the packaged file also works, but kernel upgrades rewrite that file. Verified end to end with echo c > /proc/sysrq-trigger plus kernel.panic=10: the machine was back on the network in about 33 s.