Acer Predator G5910: Linux won't power off (screen goes black, PC stays on)
Short version: the BIOS's ACPI _PTS method turns on an "SMI on sleep" trap, so Linux's final power-off write hands control to a BIOS routine that never finishes. Writing the S5 "sleep" command straight into the chipset register without running _PTS (what GRUB's halt does) works. The quick fix is a 5-line systemd-shutdown hook. The better fix is the small s5direct kernel module, which also keeps Wake-on-LAN working.
Symptoms
poweroff,shutdown -h nowor a short press of the power button: the video output stops, but fans, LEDs and the PSU stay on.- Only holding the power button for 5 seconds turns it off.
rebootworks fine. Powering on works fine.- The journal of the previous boot looks clean: it ends with
Reached target poweroff.target,systemd-shutdown: Syncing filesystems,Journal stopped. Nothing is stuck in userspace.
Hardware / firmware
| System | Acer Predator G5910 (desktop) |
|---|---|
| Chipset | Intel P67 (6-series / Cougar Point), Sandy Bridge CPU |
| BIOS | AMI, version P01-A4, dated 2011-12-22, UEFI boot |
| OS | Ubuntu 24.04 LTS, kernel 6.8.0 (also older 6.8 kernels) |
| ACPI values | PM1a control block at I/O port 0x404 (PMBASE 0x400), no PM1b, _S5 SLP_TYP = 7 |
The key test: GRUB can power it off
From the GRUB menu, press c and type halt: the machine turns off completely. So the motherboard and PSU are fine, and the failure is in the way Linux does it. On x86, GRUB's halt reads _S5 from the DSDT and writes SLP_TYP | SLP_EN directly into PM1a_CNT. It doesn't run the BIOS's _PTS method or anything else from ACPI.
What did not help
- Disabling wake-on-LAN (
ethtool -s <nic> wol d) and every wake source (/proc/acpi/wakeup, PCI/USBpower/wakeup) echo o > /proc/sysrq-trigger(kernel power-off, skipping userspace)- Changing the BIOS SATA mode from RAID to AHCI
- Kernel parameter
acpi_osi=! "acpi_osi=Windows 2009" - Booting without the NVIDIA driver; unloading
mei_me; unbinding the EHCI USB controllers - Booting with
mei, mei_me, e1000e, snd_hda_intel, lpc_ich, i2c_i801, iTCO_wdtand the GPU drivers all blacklisted - Disabling the SSD standby-on-shutdown (
/sys/class/scsi_disk/*/manage_shutdown = 0)
Root cause: _PTS enables an SMI trap
Before power-off, Linux runs the DSDT's _PTS (Prepare To Sleep) method. On this board it calls \_SB.PCI0.SBRG.SPTS, which sets PS1E, a field mapped to bit 4 of the PCH's SMI_EN register at PMBASE + 0x30 (port 0x430). That bit is SLP_SMI_EN: while it's set, writing SLP_EN doesn't put the chipset into S5. It raises an SMI, and the BIOS's SMI handler is supposed to finish the power-off. Under Linux that handler never does. Windows presumably meets whatever the handler expects.
Method (SPTS, 1, NotSerialized)
{
PS1S = One // SMI_STS bit 4: clear SLP_SMI_STS
PS1E = One // SMI_EN bit 4: SLP_SMI_EN, trap SLP_EN into SMI
SLPS = One
}
GRUB's halt and the shell hook below never run _PTS, so their write goes straight to the hardware and works. The kernel module clears SLP_SMI_EN just before its own write. That's how I confirmed this cause: without that line the module failed exactly like stock Linux, and with it the board powered off.
Better fix: the s5direct kernel module (works)
github.com/jy-roda/acer-predator-g5910-linux-poweroff-wol is a small public-domain module, installed with DKMS. It hooks into the kernel's power-off sequence after all drivers have shut down, clears SLP_SMI_EN, and does the same raw S5 write. Compared with the shell hook:
- the kernel's normal driver shutdown runs first (disks flushed, devices quiesced);
- the NIC gets armed and the chipset's wake bits get set, so Wake-on-LAN from power-off works;
- its install script keeps the shell hook as a fallback for when the module isn't loaded.
git clone https://github.com/jy-roda/acer-predator-g5910-linux-poweroff-wol.git
cd acer-predator-g5910-linux-poweroff-wol
sudo sh install.sh
Quick fix: a systemd-shutdown hook (works)
Create a systemd-shutdown hook. Executables in /usr/lib/systemd/system-shutdown/ run at the very end of shutdown, after all filesystems are unmounted or read-only, with the argument poweroff, reboot, halt or kexec.
sudo tee /usr/lib/systemd/system-shutdown/s5-direct.shutdown > /dev/null <<'EOF'
#!/bin/sh
# Acer Predator G5910: Linux's ACPI power-off leaves the board on, but GRUB's halt works.
# Do what GRUB does: write SLP_TYP=7 (from _S5) | SLP_EN into PM1a_CNT (port 0x404, from the FADT).
[ "$1" = poweroff ] || exit 0
sync
sleep 1
printf '\000\074' | dd of=/dev/port bs=1 seek=1028 count=2 2>/dev/null
EOF
sudo chmod 755 /usr/lib/systemd/system-shutdown/s5-direct.shutdown
Then test with sudo poweroff or one short press of the power button. Reboot is not affected. To undo, delete the file. The hook runs before the kernel's driver shutdown, so wake-on-LAN won't work with it. Use the module for that.
What the bytes mean
seek=1028= port0x404, the PM1a control register from the FADT.- Byte 1
0x00goes to0x404(low byte, also clears SCI_EN, the same as GRUB's 16-bit write). - Byte 2
0x3C(octal074) goes to0x405(high byte): SLP_TYP 7 in bits 10–12 plus SLP_EN in bit 13. As a 16-bit value:(7 << 10) | (1 << 13) = 0x3C00.
Using this on another board
Don't copy the numbers blindly. Writing to the wrong I/O port can do anything. Read your own values first:
sudo apt install acpica-tools
sudo acpidump -o acpi.dat && acpixtract -a acpi.dat
iasl -d facp.dat dsdt.dat
grep -E "PM1A Control Block Address|PM1B Control Block Address" facp.dsl
grep -A6 "Name (_S5" dsdt.dsl
- Port = the PM1A Control Block Address (
seek=takes it in decimal). - High byte =
(SLP_TYP << 2) | 0x20, where SLP_TYP is the first value of_S5. For example, 7 gives0x3C. - If PM1B Control is non-zero, it needs the same write with the second
_S5value. - Check whether your
_PTSsets an SMI-on-sleep bit (search the DSDT for what_PTScalls). If so, the module's approach, clearing it right before the write, may let you keep the normal kernel shutdown path. /dev/portmust be writable:cat /sys/kernel/security/lockdownhas to show[none]. With Secure Boot, the kernel lockdown blocks it.
Fallback if you can't write to /dev/port
Since GRUB's halt works, turn a power-off into a reboot into GRUB's power-off:
- Add a GRUB entry in
/etc/grub.d/40_custom:menuentry "Power off" --id poweroff { halt }, then runupdate-grub. - Add a service with
WantedBy=poweroff.targetandDefaultDependencies=nothat runsgrub-reboot poweroff. - Add a
system-shutdownhook that, forpoweroff, runssystemctl reboot --force --forceifgrub-editenv listshowsnext_entry=poweroff.
It works, but every power-off then takes an extra boot through GRUB. Note that update-grub runs every executable file in /etc/grub.d/, so don't leave backup copies there.