You close your laptop lid, toss it in your bag, and head home. The next morning you open it up to find a dead battery and a warm chassis. Sound familiar?
I've been running Linux as my daily driver for years, and this particular problem has bitten me on every single laptop I've owned since roughly 2020. The root cause is almost always the same, and once you understand it, the fix takes about five minutes.
Why Your Laptop Isn't Actually Sleeping
Modern laptops increasingly ship with what Intel calls "Modern Standby" (formerly S0ix or s2idle) instead of traditional S3 deep sleep. The difference matters a lot.
S3 (deep sleep): The CPU is powered off. RAM stays powered. Everything else shuts down. Power draw is minimal — think single-digit milliwatts.
s2idle (Modern Standby): The CPU enters a low-power idle state but stays partially on. The system can wake for network events, notifications, and background tasks. Power draw is significantly higher.
The problem? Many laptop manufacturers have removed S3 support entirely from their ACPI tables. The firmware simply doesn't advertise it as an option. Linux sees only s2idle as available and uses it by default — and on many machines, the s2idle implementation is poorly optimized for Linux, leading to excessive battery drain.
Diagnosing the Problem
First, check what sleep states your system actually supports:
cat /sys/power/mem_sleep
# Output like: [s2idle] deep
# The bracketed value is the current default
# If you only see [s2idle], S3 is not available
If you see both s2idle and deep, you're in luck — the fix is straightforward. If you only see s2idle, keep reading because we can still improve things significantly.
Next, check what's actually happening during suspend. Install powertop if you haven't already:
sudo apt install powertop # Debian/Ubuntu
sudo pacman -S powertop # Arch
sudo dnf install powertop # Fedora
# Run it after a suspend/resume cycle to see power draw
sudo powertop
You can also check the suspend log directly:
# Look at what happened during the last suspend
journalctl -b 0 | grep -i "suspend\|sleep\|freeze"
Fix 1: Switch to S3 Deep Sleep (If Available)
If your system supports deep sleep but defaults to s2idle, you can switch it:
# Temporary switch (resets on reboot)
echo deep | sudo tee /sys/power/mem_sleep
# Permanent fix via kernel parameter
# Edit your bootloader config (GRUB example)
sudo nano /etc/default/grub
# Add mem_sleep_default=deep to GRUB_CMDLINE_LINUX_DEFAULT
# Example:
# GRUB_CMDLINE_LINUX_DEFAULT="quiet splash mem_sleep_default=deep"
# Regenerate GRUB config
sudo update-grub # Debian/Ubuntu
sudo grub-mkconfig -o /boot/grub/grub.cfg # Arch/Fedora
For systemd-boot users (common on Arch and Pop!_OS):
# Edit your loader entry
sudo nano /boot/loader/entries/arch.conf
# Append to the options line:
# options ... mem_sleep_default=deep
Reboot and verify with cat /sys/power/mem_sleep — you should see s2idle [deep] now.
Fix 2: Optimize s2idle (When S3 Isn't Available)
If your firmware only supports s2idle, you need to make sure the low-power states are actually being reached. This is where most of the pain lives.
Check if your CPU is reaching deep package C-states during suspend:
# Install turbostat
sudo apt install linux-tools-common linux-tools-$(uname -r)
# Check C-state residency (run before and after suspend)
sudo turbostat --show Core,CPU,Pkg%pc2,Pkg%pc3,Pkg%pc6,Pkg%pc8,Pkg%pc9,Pk%pc10 sleep 1
If Pk%pc10 shows 0% during what should be sleep, something is blocking deep idle. Common culprits:
- USB devices keeping the controller awake
- Thunderbolt/USB4 controller not entering low-power
- WiFi card not supporting proper power save
- NVMe drive not entering deepest sleep state
For USB wakeup issues, you can disable wakeup on specific devices:
# List devices that can trigger wakeup
cat /proc/acpi/wakeup
# Disable a specific device (e.g., XHC1 for USB controller)
echo XHC1 | sudo tee /proc/acpi/wakeup
# To make it persistent, create a systemd service
sudo tee /etc/systemd/system/disable-usb-wakeup.service << 'EOF'
[Unit]
Description=Disable USB wakeup triggers
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo XHC1 > /proc/acpi/wakeup"
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable disable-usb-wakeup.service
Fix 3: The Nuclear Option — Hibernate Instead
If s2idle keeps draining your battery and S3 isn't available, hibernate (suspend-to-disk) is rock solid and uses zero power. The tradeoff is slower resume times, but honestly on a modern NVMe drive it's like 5-8 seconds.
Make sure you have a swap partition or swap file at least as large as your RAM:
# Check current swap
swapon --show
# If using a swap file, find its offset for the resume parameter
sudo filefrag -v /swapfile | head -4
# Note the first physical offset value
# Add resume parameters to kernel command line
# GRUB_CMDLINE_LINUX_DEFAULT="... resume=/dev/sdX2 resume_offset=XXXXX"
# (use your swap partition or swap file location)
You can also set up suspend-then-hibernate, which suspends first for quick resume, then automatically hibernates after a timeout:
# Edit systemd sleep config
sudo nano /etc/systemd/sleep.conf
# Add these lines:
# [Sleep]
# SuspendMode=suspend
# HibernateMode=shutdown
# HibernateDelaySec=7200 # hibernate after 2 hours of suspend
# Change the lid close action
sudo nano /etc/systemd/logind.conf
# HandleLidSwitch=suspend-then-hibernate
sudo systemctl restart systemd-logind
This is honestly my preferred setup. Close the lid for a quick coffee break and it suspends normally. Leave it overnight and it hibernates before the battery dies.
Prevention Tips
- Check sleep support before buying hardware. Search the Arch Wiki for your laptop model — it has the best hardware compatibility documentation in the Linux ecosystem.
-
Keep your firmware updated. Manufacturers occasionally push BIOS updates that improve Linux sleep behavior. Use
fwupdmgrto check:
sudo fwupdmgr refresh
sudo fwupdmgr get-updates
- Watch your kernel version. New kernels frequently add better power management for recent hardware. If you're on an LTS kernel and having issues, try a newer mainline kernel.
- Check the kernel bug tracker. Search for your specific laptop model plus "s2idle" or "suspend." Chances are someone has already reported and potentially fixed your exact issue.
The Bigger Picture
This whole situation exists because the industry is moving toward Windows-centric sleep models that assume tight firmware-OS integration. Linux support is catching up, but it's a game of whack-a-mole with each new hardware generation.
The good news is that it's genuinely getting better. The kernel's s2idle implementation improves with every release, and more hardware vendors are working directly with upstream Linux developers. If you're on relatively recent hardware with a 6.x+ kernel, you might find that s2idle works perfectly out of the box.
But if it doesn't, now you know exactly where to look and what to fix. No more dead batteries in the morning.
Top comments (0)