Suspend States (from Zircon's perspective)

From Zircon's perspective, there are different kinds of "suspend": system suspend, task scheduling suspend (per-CPU), and platform-specific suspend (per-CPU), and CPU Idle.

System Suspend State

This is a system-wide state that is entered when a user program calls zx_system_suspend_enter(). The defining characteristic is that while in this state, task execution is suspended for all CPUs. That is, while in this state, no user thread will execute. However, Zircon's interrupt handlers as well each CPU's special "idle power thread" (part of Zircon) may continue to execute as necessary. More on this below.

When entering this state Zircon identifies which interrupts are designated as wake vectors (ZX_INTERRUPT_WAKE_VECTOR) and ensures that only those interrupts will bring the system out of this state.

This state builds on Task Scheduling Suspend State (see below). In order for the system to enter this state, every CPU must enter the Task Scheduling Suspend State.

Task Scheduling Suspend State

This is a per-CPU state. When a CPU is in this state, its special "idle power thread" is the only task that may execute. This task is responsible for managing state transitions, waking the system when necessary, and putting the CPU into a Platform-Specific Suspend State or none is available, a CPU Idle State.

Platform-Specific Suspend State

This is a per-CPU state that's defined by the platform layer (think "PC" or "generic ARM"). Currently, this state is only supported on the arm64 architecture and only for QEMU and Sorrel.

On Sorrel, this state is implemented via PSCI CPU_SUSPEND (see below).

When entering a Platform-Specific Suspend State, Zircon makes no effort to mask off or otherwise disable hardware interrupts (think SPIs). If, prior to entering this state, a particular device had been configured to generate an interrupt on some event and that event occurs while in this state, the interrupt will be generated and the CPU will leave this state.

The CPU's handler will then execute and determine whether the interrupt is a wake vector or not. If the interrupt is a wake vector, then the CPU's idle power thread will begin to transition all CPUs out of their Task Scheduling Suspend State and the system out of System Suspend. If the interrupt is not a wake vector, then the idle power thread will immediately re-enter the Platform-Specific Suspend State.

PSCI CPU_SUSPEND

This is a state that a CPU enters by issuing a CPU_SUSPEND PSCI call. On Sorrel, this call comes in two flavors. One flavor is for putting just the calling CPU into a suspend state. The other flavor is for putting the last non-suspended CPU into suspend and powering down the AP complex. That is, entering AP Power Collapse.

When in this state, interrupting the CPU will cause the CPU to resume execution (i.e. leave this state).

CPU Idle

This isn't really a suspend state. A CPU enters this state whenever it has nothing better to do. The CPU will pause execution, enter a lower power state and wait until an interrupt occurs or another CPU has asked it to resume execution. On arm64 and riscv64, this is done using a WFI instruction. On x64, we use either MWAIT or HLT. While a CPU may enter this state during any of the above suspend states, this state is not inherently tied to System Suspend, or Task Scheduling Suspend.