Suspend and Wake-up

On this page

Inability to sleep, waking up immediately, and device failure after resume are issues at different stages. System suspend and device runtime PM are different state machines; they should be diagnosed based on platform capabilities, stage dependencies, and wake-up protocols.

GoalRead Section
Supported modes and device phasesFirst two sections
Image recovery and on-demand suspendhibernate, runtime PM
Event races and diagnosticsWake-up, failure stages

Check what the current platform supports

cat /sys/power/state
cat /sys/power/mem_sleep

state lists the requestable states, such as freeze, mem, disk; mem_sleep lists the optional modes corresponding to mem, with the currently selected item marked in brackets. For example, s2idle [deep] means mem is currently set to deep, not that every machine supports deep. System Sleep States

MethodState Required for RecoveryMain Differences
suspend-to-idle (s2idle, freeze)Existing state in RAMSoftware-coordinated freezing, device suspend, and CPU idle; does not require traditional S3
suspend-to-RAM (commonly deep)State retained in RAMPlatform enters a deeper system sleep state; ACPI platforms usually correspond to S3
hibernation (disk)Memory image in persistent storageReads back the image on next boot, restoring the old kernel's execution state

There are also platform-optional states like shallow. Power consumption and recovery time are determined jointly by devices, firmware, image size, etc., and should not be guaranteed by interfaces as 1W, 100ms, or 10 seconds. s2idle does not mean "only shallow sleep": suitable platforms can achieve deeper whole-system low-power states through it.

Why suspend is divided into phases

System Suspend: Establish a quiescent point, then resume execution Preparation and Freezing Coordinate user space, kernel threads, and wake-up events 1 Device Suspend Phases Handle callbacks like suspend, late, noirq based on dependencies 2 Enter Selected System Sleep State s2idle and deep have different platform entry methods 3 Resume Devices and Thaw Restore dependencies after wake-up, handle failures, and let tasks continue 4 The diagram does not represent the entire source code call stack; device order, platform steps, and failure rollback must all be considered.

The system needs to prevent new work from continuously entering devices while retaining the facilities needed to complete cleanup. Devices usually need to stop new I/O and save state before entering later phases; during resume, dependencies are rebuilt first, and then upper layers re-initiate work.

Device PM callbacks include phases such as prepare/complete, suspend/resume, late/early, and noirq. noirq is not synonymous with "the driver can finally turn off all interrupts at will"; it is the phase where the PM core has coordinated device interrupt handling. Asynchronous suspend and device links also affect dependency execution, so one cannot infer order solely based on device names.

Freezing user tasks does not require them to release all user-space mutexes, nor does it turn arbitrary business transactions into consistent snapshots. For kernel locks and freezeable threads, avoid forming wait loops where "the frozen party holds resources needed for resume or suspend." Device PM

Hibernate: Saving Images and Restoring Old Execution Contexts

Hibernate requires creating a recoverable memory image and writing it persistently. It is not simply copying "all RAM" byte by byte: idle pages, pages that do not need saving, and reclaim results affect the image size, and the image may be compressed. It is also incorrect to uniformly say that all page cache is unconditionally skipped.

To write the image, devices may go through different paths such as freeze, thaw, and then entering the final power state. Therefore, the driver's freeze/thaw and poweroff/restore callbacks have independent semantics and cannot all be treated as aliases for suspend/resume.

Recovery is usually discovered and loaded by a newly started kernel or initramfs, which then switches back to the saved kernel state. Resume devices, swap file offsets, encrypted device unlocking, and boot-stage support must be coordinated; adding a resume= parameter does not guarantee success. It is also incorrect to rewrite relevant file systems from another running environment while the image exists and then expect the old cache to remain consistent after recovery. swsusp

The image contains sensitive state in memory; the storage and recovery chain should follow the system's existing encryption and trusted boot designs. Whether there is whole-system standby power consumption after power loss depends on hardware and is not guaranteed to be absolute zero watts by the term "hibernate."

Runtime PM: Usage Counts, Dependencies, and Driver States

Runtime PM coordinates the activity and suspend of a specific device during system operation. Usage counts are one protocol to prevent devices from suspending when they are still needed; they also involve sub-devices, dependencies, driver-allowed states, and pending requests; autosuspend_delay_ms is just one of the conditions.

Before a driver accesses a device, it should use appropriate synchronization to acquire and resume interfaces, such as pm_runtime_resume_and_get, and check for failures; after finishing usage, it should mark busy time and release usage references according to the protocol. One cannot ignore resume failures and continue accessing registers. Runtime PM

power/control set to auto allows runtime PM, while on usually prohibits runtime suspend; this does not equate to whether system sleep is allowed. PCI D3hot and D3cold also have different power supply and configuration access conditions; D3hot cannot be simplified as "device completely powered off but link maintained."

Which Work Segment Does a Usage Reference Cover?

The sequence for a synchronous device access is: successfully acquire the runtime reference and resume the device, access hardware, and finally release this reference. If resume fails, no usable device is obtained; one cannot continue I/O, nor can one treat the failure as a successful acquisition followed by blind release. The error path counting semantics of pm_runtime_resume_and_get() and pm_runtime_get_sync() are different; the latter does not automatically revoke the incremented usage count upon error. Runtime PM Helper Semantics

PathHardware Accessed?Usage Reference to Release in Current Call
resume-and-get failureNo0
Acquisition successful, I/O successfulYes1
Acquisition successful, I/O failedAttempted1
Acquisition successful, async I/O submitted but not completedDevice may still be workingReference should be released by the completion/cancel path according to ownership protocol

The model below only checks reference pairing; resume failures are indicated by return values, and transmission failures by exceptions. PM count reaching zero does not directly execute suspend, so it also does not incorrectly imply "the device is powered off when put returns."

class Usage:
    def __init__(self, resume_ok=True):
        self.resume_ok = resume_ok
        self.count = 0
        self.accesses = 0

    def resume_and_get(self):
        if not self.resume_ok:
            return False
        self.count += 1
        return True

    def put(self):
        assert self.count > 0
        self.count -= 1

    def io(self, fail=False):
        assert self.count > 0
        self.accesses += 1
        if fail:
            raise OSError("transfer failed")
        return "ok"

def transfer(pm, fail=False):
    if not pm.resume_and_get():
        return "resume failed"
    try:
        return pm.io(fail)
    finally:
        pm.put()

pm = Usage(False)
assert transfer(pm) == "resume failed" and (pm.count, pm.accesses) == (0, 0)
pm = Usage()
assert transfer(pm) == "ok" and (pm.count, pm.accesses) == (0, 1)
try:
    transfer(pm, fail=True)
except OSError:
    pass
else:
    raise AssertionError("Transmission error should be propagated")
assert (pm.count, pm.accesses) == (0, 2)
assert pm.resume_and_get() and pm.resume_and_get()
pm.put()
assert pm.count == 1  # One call ends, it won't consume another call's reference
pm.put()
assert pm.count == 0

In Linux 7.2, pm_runtime_put_autosuspend() updates last_busy itself before releasing the reference; the double-underscore version __pm_runtime_put_autosuspend() is not responsible for this time update. When reading the combination of "mark_last_busy + put" in old drivers, verify against the include/linux/pm_runtime.h of the target version. Autosuspend is also subject to constraints such as delay, active sub-devices, PM QoS, driver state, and pending requests.

If the transmission uses DMA, the hardware may still be accessing memory when the function returns "submission successful." The reference lifecycle should be extended to the completion or confirmed-stopped cancel path, ensuring only one release per path; releasing the reference solely in the submit function's finally would incorrectly apply this synchronous example to asynchronous devices.

After releasing the usage reference of a sub-device, attempt to suspend the parent device first, then proceed to suspend the sub-device. Zero usage count, elapsed wait period, quiet sub-devices, and driver allowance are conditions that need to be met separately.

Preparing the visual
Does the device sleep as soon as the usage count hits zero?

Putting to zero only removes one condition preventing suspend; it does not guarantee the device is already suspended. Resuming a sub-device requires its parent dependency to be available first; active sub-devices can also prevent the parent from suspending.

Wake-up: Separate Capabilities, Policies, and Actual Events

ConditionWhat to Confirm
Device CapabilityWhether it supports generating wake-up events
Policy PermissionWhether power/wakeup, etc., allow it
Actual PropagationWhether the event can pass through parent devices and the platform to the CPU

Enabling an attribute cannot replace the conditions of hardware wiring, firmware, and the entire dependency path.

New events during sleep preparation may require aborting the suspend. User space and the kernel can handle the race condition of "checked no events, but an event arrived before actual sleep" via protocols like wakeup_count. pm_wakeup_irq provides limited IRQ clues, not a complete ledger of all wake-up sources.

How wakeup_count Closes the "Check Then Sleep" Window

A coordinated attempt can be understood as: first read the count n when there are no active wake-up events, complete user space preparation, and then write n back; the write-back succeeds only if the count remains the same and no events are currently being processed. Successful write-back also enables subsequent checks; new events can abort this suspend. Reading may also wait for currently processing events to finish; it is not always a simple statistical read that returns immediately.

Position of New EventWhy the Original Sleep Judgment Cannot Be Used
Processed and finished after read, before write-backCount changes from n to n+1, write-back of n fails
Still processing at write-backEven if finished count hasn't grown, active events cause write-back to fail
After write-back success, before suspend checkCheck finds new count or active events, aborts this transition
A Single Sleep Attempt Requires Two Event Checks, Before and After Read Count n Wait for active events to finish Write Back n Compare count and active status Check During Suspend Abort this transition if changed Event Window ① Event Window ② ① Causes write-back failure; ② Causes subsequent suspend check to find pending Illustrates the coordination protocol; actual sleep entry and events after entering sleep still depend on platform wake-up mechanisms.

The following simulates atomic checkpoints during a single attempt. finished represents the number of model wake-up activities that have ended, active represents the number currently being processed; these are not raw interrupt counts. The real kernel also includes locks, packed counts, blocking waits, and additional abort sources; the pending check here only compares states and does not replicate the side effect of the kernel clearing the check-enable bit after discovering an event.

class WakeupGate:
    def __init__(self):
        self.finished = 0
        self.active = 0
        self.saved = None

    def begin(self):
        self.active += 1

    def end(self):
        assert self.active > 0
        self.active -= 1
        self.finished += 1

    def read(self):
        if self.active:
            raise BlockingIOError("Real blocking read needs to wait for activity to end")
        return self.finished

    def save(self, observed):
        self.saved = None
        if self.active or observed != self.finished:
            return False
        self.saved = observed
        return True

    def pending(self):
        assert self.saved is not None
        return self.active > 0 or self.finished != self.saved

# Finished between read and write: count change is detected.
gate = WakeupGate()
n = gate.read()
gate.begin(); gate.end()
assert not gate.save(n)

# Still processing: cannot just compare finished count.
gate = WakeupGate()
n = gate.read()
gate.begin()
assert gate.finished == n and not gate.save(n)
try:
    gate.read()
except BlockingIOError:
    pass
else:
    raise AssertionError("Stable read for this model cannot be given during active events")

# After write-back: changes are detected during activity and after processing ends.
gate = WakeupGate()
assert gate.save(gate.read()) and not gate.pending()
gate.begin()
assert gate.pending()
gate.end()
assert gate.pending()
# After processing new events, restart a coordinated attempt.
assert gate.save(gate.read()) and not gate.pending()

Passing the check only indicates that this checkpoint meets the conditions; it does not mean interrupts will not arrive afterwards. Subsequent PM checks and platform wake-up mechanisms must still handle events close to the actual sleep entry, or even after entering sleep; capabilities, policies, and propagation paths must still hold. Therefore, one cannot write not pending() in the model as "unconditionally close wake-up and sleep." Interface contracts can be found in the wakeup_count entry of Documentation/ABI/testing/sysfs-power in the kernel, and the implementation is located in drivers/base/power/wakeup.c.

Locate by Failure Stage

First record the actual mem_sleep, then locate the stage:

PhenomenonTroubleshooting Starting Point
Cannot enterWhether freezing, device callbacks, and dependencies are completed
Wakes up immediately upon entryActual wake-up events and races during preparation
Cannot wake upCapability, policy, and platform propagation path
Single device failure after resumeCorresponding resume callback and resource reconstruction

The device mentioned in the last log entry is not necessarily the root cause.

journalctl -k -b
cat /sys/power/pm_wakeup_irq

Whether attributes exist and log permissions depend on the environment. Combine with tracepoints like power:suspend_resume to observe stage durations; when enabling tracing, use the tracefs path actually mounted on the machine, rather than treating trace_pipe as a file in any current directory.

Systems supporting CONFIG_PM_DEBUG can use pm_test for layered testing of freezer, devices, and other stages to narrow down the fault scope before the platform actually enters sleep. Tests will actually freeze tasks or suspend devices, so they should be executed in a test environment with recovery means; the read commands listed on this page do not trigger sleep themselves. Debugging Documentation

pm_trace uses RTC to store trace fingerprints, which has the side effect of affecting the clock and is not suitable as the first debugging command without explanation. Driver errors should be confirmed by combining callback return values, dependencies, and repeated tests; one cannot determine the root cause solely based on a hash match.