Linux Wakeup Source Fundamentals-Free Linux Device Drivers Course

Linux Wakeup Source Fundamentals

PREV_LEC | NEXT_LEC

Linux Wakeup Source Fundamentals

How a Linux device tells the kernel “wake the system up for me” — the wakeup_source data model, the activation lifecycle, and the sysfs knobs that control it

Kernel 6.x Verified
struct wakeup_source
device_init_wakeup()

Every Linux system that suspends has to answer one question reliably: once we’re asleep, what is allowed to wake us back up? That answer is implemented through a single kernel abstraction — the Linux wakeup source. A wakeup source is not a GPIO, not an IRQ number, and not a device by itself; it is a bookkeeping object the power management core uses to track “something is currently justifying keeping the system awake, or has recently justified aborting a suspend attempt.” This lecture is part of our free linux kernel development course and builds directly on the previous lecture about system sleep PM callbacks — here we go one level deeper, into what actually happens between an interrupt firing and the kernel deciding a suspend transition must be aborted or a resume must happen.

What You Will Learn

  • What a wakeup source is in PM terminology, and how it differs from a wakeup event
  • The full activate → deactivate lifecycle and why an active wakeup source blocks suspend
  • The real fields of struct wakeup_source as defined in current mainline Linux, and what each one tells you when debugging a suspend-that-won’t-suspend bug
  • Exactly what device_init_wakeup() does — and the parts of wakeup enablement it deliberately leaves for the driver to do separately
  • How the power/wakeup sysfs attribute separates hardware capability from runtime policy

Prerequisites

  • Comfortable with the Linux driver model: struct device, struct dev_pm_ops, probe/remove
  • Have read the previous lecture in this series on system sleep PM callbacks (suspend()/resume(), the noirq/late phases) — this lecture assumes you already know when those callbacks run
  • Basic familiarity with Linux interrupt handling (request_irq(), threaded IRQs)

What Is a Wakeup Source in Linux Power Management?

In the Linux PM subsystem, a “wakeup source” is an instance of struct wakeup_source, a small object that represents anything capable of aborting system suspend or triggering a resume. Most of the time a wakeup source is tied one-to-one to a struct device — a GPIO button, a UART’s RX line, an RTC alarm, a network controller’s magic-packet detector — but the abstraction is deliberately more general than “device.” The kernel also creates wakeup sources for things that aren’t devices at all, such as wake locks used by Android-style opportunistic suspend, or timers used purely for internal bookkeeping. Every wakeup source is registered in a global list the suspend core walks whenever it needs to answer two questions: “is anything active right now that should abort this suspend attempt?” and, after resume, “which source actually caused this wakeup?” That second question matters more than people expect — being able to say this specific GPIO button woke the box up, rather than just something woke the box up, is what makes wakeup-source-level debugging possible at all.

Wakeup Source vs Wakeup Event

A wakeup event is the trigger — almost always an interrupt line firing, though it can also be a timer expiring or an explicit driver call. A wakeup source is the accounting object that the event acts on. When an interrupt configured as a wake IRQ fires, the kernel doesn’t suspend/resume the system directly from the interrupt handler; instead the event is reported against a wakeup source via pm_wakeup_event() (or the lower-level pm_wakeup_ws_event()), which marks that source active for a bounded window of time. The suspend core then reacts to the source’s active/inactive state, not to the raw interrupt. This indirection is what lets the kernel correctly handle races — an interrupt that fires a few microseconds before suspend() would otherwise complete still gets to abort the transition, because the wakeup source stays active long enough for the core to notice it.

The Activate / Deactivate Lifecycle of a Wakeup Source

Conceptually every wakeup source moves through the same two-state lifecycle, and understanding this cycle is the single most useful thing for debugging “my device won’t let the system suspend” bugs.

Wakeup Source Activation Lifecycle

probe() calls device_init_wakeup() → wakeup_source registered, starts INACTIVE
↓
Wake IRQ fires → pm_wakeup_event() / __pm_stay_awake() → source becomes ACTIVE → event_count++, active_count++
↓
While ACTIVE → any in-progress or new suspend attempt is aborted → prevent_sleep_time accumulates
↓
Driver work finishes → __pm_relax() called (directly, or automatically after the pm_wakeup_event() timeout) → source returns to INACTIVE → total_time and max_time updated

The critical rule here is: while even one registered wakeup source is active, the suspend core will not allow the transition to complete. This is enforced in the suspend/freeze path itself — before the kernel commits to entering a sleep state, it checks whether any wakeup source is currently active, and if so it aborts and retries (or gives up, depending on how the request was made). This is exactly why a driver that forgets to call the deactivating half of this pair — forgets to relax a source it activated — can silently prevent the whole system from ever suspending again, with no error message anywhere except a wakeup source that never returns to zero active time.

Inside struct wakeup_source: The Data Model

The fields of struct wakeup_source, as defined in include/linux/pm_wakeup.h in current mainline Linux, are exactly the numbers you want when you’re trying to work out which wakeup source is responsible for a suspend failure or an unexpected resume. Several of them are exposed directly as per-device sysfs statistics files, which is where you’ll actually read them in practice.

FieldTypeWhat it tells you when debugging
event_countunsigned longHow many times this source has signaled a wakeup event in total. A number that keeps climbing while the system is supposedly idle tells you this source’s IRQ is firing far more often than expected — a noisy line, bad debounce, or a mis-wired GPIO.
active_countunsigned longHow many times the source transitioned from inactive to active. Compare this against event_count: if active_count is much lower, most events are arriving while the source is already active, meaning a single busy period is generating repeated events rather than distinct wake-ups.
total_timektime_tCumulative time this source has spent active across its whole life. A source with a large total_time relative to system uptime is a strong candidate for “the thing that’s killing your battery life” — it’s holding the system awake a large fraction of the time.
max_timektime_tThe single longest continuous active period. A high max_time usually points at a handler that’s slow to call __pm_relax() — either genuinely slow work, or a bug where relax is only called on one code path and gets skipped on others.
prevent_sleep_timektime_tTotal time this specific source has been the reason autosleep (or an explicit suspend request) was blocked. This is the field to check first when the system “won’t go to sleep” — it directly answers “how much of the blame belongs to this source.”
wakeup_countunsigned longHow many times this source’s activation actually aborted an in-progress suspend transition, as opposed to just being active while the system was already running. This is what separates a source that’s merely busy from one that has genuinely interrupted sleep.

In practice you rarely dereference this struct directly from driver code — the numbers above are surfaced automatically once device_init_wakeup() has registered the source, both through /sys/devices/.../power/wakeup_* files per device and in aggregate via /sys/kernel/debug/wakeup_sources if pm debugfs is enabled. Reading those files is the fastest way to find which wakeup source is misbehaving on a real board, and the second lecture in this pair walks through exactly those files with real commands.

device_init_wakeup(): What It Actually Does

This is the function almost every wakeup-capable driver calls once, in probe(), and it is worth being precise about its contract because it is smaller than most people assume.

When called as device_init_wakeup(dev, true), it does three things:

  • Sets dev->power.can_wakeup = true via device_set_wakeup_capable() — this is the hardware/firmware-level statement “this device is physically able to wake the system,” and it is what gates whether the power/wakeup sysfs file even appears for this device.
  • Calls device_wakeup_enable(), which allocates and registers a struct wakeup_source against the device (via wakeup_source_register()) and sets the initial policy to “enabled” — meaning, by default, a device marked wakeup-capable at init time is also immediately enabled to actually wake the system, not just capable of it.
  • Wires up the per-device sysfs statistics attributes (wakeup_count, wakeup_active_count, wakeup_total_time_ms, and the rest of the fields from the table above) so they become visible under that device’s power/ directory.

What it does not do is just as important: device_init_wakeup() never touches an interrupt line. It has no idea which IRQ, if any, is the one that should be treated as this device’s wake signal, and it does not call request_irq(), enable_irq_wake(), or anything IRQ-specific. All it produces is a registered, named wakeup_source object and the capability/policy bookkeeping around it — an empty accounting slot with nothing yet plugged into it. Actually connecting a real interrupt to that wakeup source is a separate step, using the wake-IRQ API covered with a worked example in the next lecture in this pair.

The power/wakeup Sysfs Attribute: Capability vs Policy

Once device_init_wakeup() has run for a device, userspace gets a single, deceptively simple control file: /sys/devices/.../power/wakeup, containing either the string enabled or disabled. It is essential to understand that this file controls policy, not capability — and the two are tracked as genuinely separate flags inside struct device.power.

Capability vs Policy

power.can_wakeup — CAPABILITY — set once by device_init_wakeup()/device_set_wakeup_capable(), reflects what the hardware is physically able to do
↓ if true, exposes
/sys/devices/…/power/wakeup — the sysfs file only exists at all when can_wakeup is true
↓ user writes enabled/disabled
power.should_wakeup / the wakeup_source’s enabled state — POLICY — read by device_may_wakeup() at suspend time to decide whether this source is armed

The kernel-level check that everything else builds on is device_may_wakeup(), defined as dev->power.can_wakeup && !!dev->power.wakeup — both the capability flag and the policy/enabled wakeup_source pointer must be true. Capability answers “can this device ever wake the system.” Policy answers “should it, right now, on this particular suspend.” A device can be fully capable of waking the system (e.g. a GPIO button wired to a wake-capable IRQ controller) yet have wakeup disabled by policy — perhaps because the system integrator wants a headless server to ignore a stray button press during sleep. Writing echo enabled > power/wakeup flips the policy bit on; it never changes whether the hardware is capable, because that was fixed at driver-probe time and reflects a physical fact about the board.

Common Mistakes and Troubleshooting

  • Forgetting to call device_init_wakeup() at all. Without it, power/wakeup never appears in sysfs, and any later call to a wake-IRQ helper against that device fails or is silently a no-op, because there’s no registered wakeup_source to attach the IRQ to.
  • Assuming device_init_wakeup() enables the actual IRQ. It only creates the accounting object. If you never separately configure the interrupt as a wake source, the device is “capable” in sysfs but will never actually wake anything.
  • Never calling the deactivating half of an activate/deactivate pair. Any driver code path that calls __pm_stay_awake()/pm_stay_awake() without a matching __pm_relax()/pm_relax() leaves the source permanently active, and the whole system silently stops suspending with no visible error — only a wakeup source whose active_count never comes back down.
  • Confusing capability with policy during debugging. Seeing disabled in power/wakeup does not mean the driver is broken — it may simply mean the policy was intentionally turned off. Check can_wakeup-driven presence of the file first, then the enabled/disabled policy value second.
  • Reading wakeup statistics on a device that was never marked wakeup-capable. The stats attributes only exist once device_init_wakeup() has run; their absence is diagnostic in itself.

Best Practices

  • Call device_init_wakeup() as early as reasonable in probe(), before any interrupt is requested, so the wakeup_source exists before anything could try to report an event against it.
  • Default wakeup to disabled (device_init_wakeup(dev, false)) for devices that aren’t obviously expected to be wake sources, and let board/DT/ACPI policy or the sysfs file turn it on — reserve default-enabled for devices everyone expects to wake the system, like power buttons.
  • Use devm_device_init_wakeup() where available so the wakeup capability is automatically torn down on driver detach instead of requiring manual cleanup in remove().
  • When something looks stuck asleep-that-won’t-sleep, check prevent_sleep_time and wakeup_count per device before anything else — they point directly at the offending source instead of requiring a guess.

Summary and Key Takeaways

A Linux wakeup source is the accounting object — struct wakeup_source — that the PM core uses to decide whether suspend can proceed and to explain, after the fact, what caused a resume. It moves through a strict activate/deactivate lifecycle: an event (almost always an IRQ) activates it, driving up event_count and active_count and accumulating prevent_sleep_time, and it must later be explicitly deactivated or the entire system stops suspending. device_init_wakeup() sets up the capability flag and registers this wakeup_source with its sysfs statistics, but it deliberately does not touch any interrupt — connecting a real wake IRQ is a separate, explicit step. Finally, the power/wakeup sysfs file is policy, layered on top of the capability flag set at probe time, and device_may_wakeup() is the function that combines both to make the final call at suspend time. With this model in hand, the next lecture in this free linux device drivers course builds a complete, original GPIO wake-button driver on top of it.

Frequently Asked Questions

What exactly is a wakeup source in Linux power management?

It’s an instance of struct wakeup_source, a kernel accounting object that tracks whether something is currently justifying blocking suspend or has recently caused a resume. It is usually, but not always, tied to a device.

Is a wakeup event the same thing as a wakeup source?

No. The event is the trigger, almost always an interrupt firing. The source is the persistent object the event is reported against via functions like pm_wakeup_event().

Does device_init_wakeup() configure the interrupt for me?

No. It only sets the capability flag and registers the wakeup_source object with its sysfs statistics. Attaching an actual IRQ as the wake trigger is a separate step, typically done with the wake-IRQ helper API.

What is the difference between wakeup capability and wakeup policy?

Capability (power.can_wakeup) is a hardware fact set once at probe time and gates whether the sysfs file exists at all. Policy is the enabled/disabled state written through power/wakeup, checked at suspend time via device_may_wakeup().

Which wakeup_source field should I check first when suspend seems blocked?

prevent_sleep_time — it directly reports how much time this specific source has been the reason autosleep or an explicit suspend request was blocked.

Why would a device stop suspending forever after a driver update?

The most common cause is a code path that activates the wakeup source (__pm_stay_awake()/pm_stay_awake()) without a matching deactivation (__pm_relax()/pm_relax()), leaving the source permanently active.

Can a device be wakeup-capable but have wakeup disabled?

Yes, and this is completely normal — capability and policy are independent. A device can be physically able to wake the system while policy keeps it disabled by default.

Where do I read wakeup source statistics on a running system?

Per-device, under /sys/devices/.../power/wakeup_count, wakeup_active_count, wakeup_total_time_ms, and related files; system-wide, via /sys/kernel/debug/wakeup_sources if pm debugfs is enabled — covered with real commands in the next lecture.

Ready to see it in code?

The next lecture builds a complete, original wakeup-capable GPIO button driver on top of everything covered here — real sysfs commands, real dmesg output, and the current-recommended wake-IRQ API.

Continue to Driver Wakeup Events Back to Course Index

PREV_LEC | NEXT_LEC

Leave a Reply

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