Skip to content
VLSI Mentor

USB · Module 8

Suspended State

The state that is not a state: why suspend is a modifier on the other four rather than a sixth peer, what breaks in a peer-state model, the overlay RTL that remembers where to return, and why one major host drives resume for twice the specified time.

Five chapters have built a state machine on one assumption, stated in Chapter 8.4 §1 and true of every state so far:

A state is defined by what is true, not by how you got there.

Suspended breaks it, and the break is not a technicality:

Suspend is not a sixth state. It is a modifier on the other five — and a suspended device must remember which state it was suspended from, because resuming returns it there.

An implementation that models suspend as a peer state discovers this at the worst possible moment: at resume, when the device has to go back somewhere and no longer knows where.

1. Why Suspend Exists

USB carries power, and a device that is connected but unused is consuming it.

The bus has a natural idleness signal. A host that has nothing to say to any device stops generating traffic, and the line goes idle. That idleness is observable by every device on the bus without anyone being told anything.

So suspend is triggered by absence rather than by a request. A device that observes the bus idle for longer than a defined interval enters a low-power condition on its own. There is no suspend request, no transfer, and no acknowledgement.

Which makes it unlike every other transition in this module. Every other edge is caused by a host action the device responds to. Suspend is caused by the host doing nothing, and the device acting unilaterally on that observation — the only transition above Powered where the device decides.

2. Suspend Is an Overlay

Here is the chapter's structural claim, and it is worth stating carefully because it contradicts the way suspend is usually drawn.

A device suspends from whatever state it was in. A Configured device that suspends is suspended from Configured. An Address-state device that suspends is suspended from Address. So is a Powered one, and a Default one.

And resuming returns it to where it came from. A Configured device that suspends and resumes is Configured again — it does not re-enumerate, it does not lose its address, and its configuration is still selected. That is the entire point: suspend saves power without losing the work of enumeration.

Which means there is not one suspended state. There are four, distinguished by where they return to.

This is not an interpretation. The Linux kernel's device-state enumeration says so explicitly, in a comment attached to its single SUSPENDED value:

there are actually four different SUSPENDED states, returning to POWERED, DEFAULT, ADDRESS, or CONFIGURED respectively when [traffic] flows again.

The kernel carries one value and documents that it stands for four. That is a reasonable engineering compromise at its level of abstraction, and it is not a compromise a device controller can make — because the controller is the thing that has to go back.

Suspend is a modifier on four states, not a sixth state

fsm
A state machine showing suspend as an overlay. The four states Powered, Default, Address and Configured each have a corresponding suspended variant. Bus idleness lasting longer than the suspend threshold moves a device from each state into its own suspended variant, and resume signalling returns it from that variant to exactly the state it came from. A bus reset from any suspended variant leads to Default rather than back to the originating state, because a reset overrides the saved information.PoweredDefaultAddressConfiguredSusp/PwrSusp/DefSusp/AdrSusp/Cfgidleidleidleidleidleidleidleidleresumeresumeresumeresumeresumeresumeresumeresumebus resetbus resetbus resetbus reset
Figure 1 — suspend as an overlay rather than a peer. Each state has its own suspended variant, and each returns to the state it came from; the dashed frame is the modifier, and drawing it as one node with four exits is precisely the error section 3 measures.

Count the edges out of the suspended row. Each has a resume edge to exactly one state, and that is the information a peer-state model throws away.

3. What Breaks in a Peer-State Model

Make the failure concrete, because "it loses information" is too abstract to be useful.

The implementation: a sixth enum value, DEV_SUSPENDED, entered from any state on the idle timer.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
if (suspend_detected) next_state = DEV_SUSPENDED;   // from anywhere

Now resume arrives. What is the next state?

There is no answer available. The state register holds DEV_SUSPENDED and that value does not encode where the device came from. Three things can happen, and all of them are wrong:

Return to a fixed state. Pick Default and every resume forces a re-enumeration — the device loses its address and configuration every time the host idles the bus, which defeats suspend's purpose entirely. Pick Configured and an unaddressed device claims to be configured.

Return to Configured if a configuration is held. This almost works, and it is the fix people reach for. It infers the state from the registers rather than remembering it — and it cannot distinguish a device suspended from Address from one suspended from Default, because both hold no configuration and it must guess between them.

Do not clear the registers on suspend and infer everything. Now the state is fully derivable from the address and configuration registers — at which point the state enum was never carrying the information in the first place, and the design has accidentally discovered that suspend needs a separate holder.

The third option is the interesting one, because it is correct and it reveals the structure: the return state has to be stored somewhere, and if not in the state register then in something else. §4 makes it explicit rather than accidental.

4. The Overlay, as RTL

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// usb_suspend_overlay
//
// Classification: SIMPLIFIED SYNTHESIZABLE TEACHING RTL. It models suspend
// as an OVERLAY on the Chapter 8.3 state machine -- a separate bit plus a
// saved state -- rather than as a sixth value inside it.
//
// WHAT IT MODELS. Section 2's structure: a device suspends from a state,
// remembers which, and returns there on resume. It also models the two
// events that OVERRIDE the saved state -- a bus reset and physical loss --
// because both make the saved value meaningless.
//
// WHAT IT DOES NOT MODEL. Detecting bus idleness or resume signalling
// (Module 3 owns the line conditions; these arrive decoded and qualified),
// the low-power behaviour itself -- clock gating, supply management,
// suspend current limits -- which is Module 19's, remote wakeup initiation,
// or anything the Chapter 8.3 state machine already owns.
//
// ARCHITECTURAL NOTE. The suspended condition is a SEPARATE BIT, not an
// enum value. That is the whole design: it makes "suspended" orthogonal to
// "which state", which is what section 2 says it structurally is. A sixth
// enum value would force the two facts into one register that can only
// hold one of them (section 3).
// ─────────────────────────────────────────────────────────────────────────
module usb_suspend_overlay
  import usb_state_pkg::*;
(
  input  logic clk,
  input  logic rst_n,

  // The Chapter 8.3 state machine's output -- unchanged and unaware of
  // suspend. That independence is deliberate: adding suspend must not
  // require modifying the state machine.
  input  usb_dev_state_e base_state,

  // Decoded and qualified by Module 3. `suspend_req` means the bus has been
  // idle for longer than the threshold; `resume_req` means resume signalling
  // has been seen. Both are single-cycle pulses.
  input  logic suspend_req,
  input  logic resume_req,

  // These override the saved state -- see the comments below.
  input  logic bus_reset,
  input  logic phys_connected,
  input  logic phys_powered,

  output logic            suspended,      // the overlay bit
  output usb_dev_state_e  effective_state,// what the rest of the device sees
  output usb_dev_state_e  saved_state,    // exported for status and debug
  output logic            resume_to_cfg   // resumed INTO Configured, 1 cycle
);

  // The effective state is the base state unless suspended, in which case it
  // is the state the device was suspended from. Consumers therefore never
  // need to know suspend exists -- Chapter 8.5's derived enable keeps
  // working unchanged, which is the payoff of the overlay structure.
  always_comb begin
    if (suspended) effective_state = saved_state;
    else           effective_state = base_state;
  end

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      suspended     <= 1'b0;
      saved_state   <= DEV_NOTATTACHED;
      resume_to_cfg <= 1'b0;
    end else begin
      resume_to_cfg <= 1'b0;

      // ── PRIORITY, highest first. Chapter 8.3 section 5's rule applies
      // unchanged: events that invalidate context dominate.
      if (!phys_connected || !phys_powered) begin
        // The saved state describes a device that is no longer there.
        // Keeping it would resume a reconnected device into a state it
        // never established (Chapter 8.1 section 9's stale-state bug).
        suspended   <= 1'b0;
        saved_state <= DEV_NOTATTACHED;
      end
      else if (bus_reset) begin
        // A reset OVERRIDES the saved state. This is the one place where
        // "return where you came from" does not apply: the host has
        // asserted a new starting point, and a device that resumed into
        // its pre-reset state afterwards would contradict it.
        suspended   <= 1'b0;
        saved_state <= DEV_NOTATTACHED;
      end
      else if (suspend_req && !suspended) begin
        // Capture where we are. This is the information section 3's
        // peer-state model has nowhere to put.
        suspended   <= 1'b1;
        saved_state <= base_state;
      end
      else if (resume_req && suspended) begin
        suspended     <= 1'b0;
        // Report a resume into Configured as its own event: firmware
        // frequently needs to restart data movement, and Chapter 8.5
        // section 5 established that a level it might miss is not enough.
        resume_to_cfg <= (saved_state == DEV_CONFIGURED);
      end
      // A suspend_req while already suspended, or a resume_req while not
      // suspended, does nothing -- deliberately. Both are conditions a real
      // line decoder can produce, and neither should disturb saved_state.
    end
  end

endmodule

What it models. The overlay: a suspended bit, a saved state, and the two events that invalidate the saved value.

Why this hardware exists. Because resume has to return the device somewhere, and the state register cannot hold both which state and suspended at once.

Inputs. The base state machine's output; qualified suspend and resume events; a bus reset; and the two physical signals.

State retained. The suspended bit and the saved state.

Outputs. The suspended bit, the effective state consumers use, the saved state for status, and a one-cycle resume-into-Configured event.

Reset behaviour. The local reset clears both. A bus reset clears the overlay as an input, per Chapter 8.3 §6's distinction.

Hardware implied. One flip-flop, a 3-bit register, and a multiplexer.

Assumptions. That suspend_req and resume_req are decoded and qualified by Module 3 — the timer that distinguishes an idle bus from a gap between transfers lives there, not here; and that the base state machine is unmodified.

Deliberately omits. Idleness and resume detection, all low-power behaviour, remote wakeup initiation, and everything Chapter 8.3 owns.

What DV should verify. That suspend from each of the four states resumes to that same state; that a bus reset while suspended produces Default and not the saved state; that physical loss while suspended does not leave a saved state to resume into; that a redundant suspend does not overwrite the saved value; that a resume while not suspended does nothing; and that the effective state equals the base state whenever the device is not suspended.

5. Timing, and a Host That Doubles It

The numbers, with their origins — and one of them is more interesting than a specification value.

Entering suspend. The device observes bus idleness and, after a defined interval, must be suspended. The interval exists for §1's reason: it must be long enough that ordinary gaps cannot trigger it. Implementations allow a further window to complete the transition — the Linux kernel's host-side code, having put a port into suspend, waits with the comment that the device has up to 10 msec to fully suspend before treating it as done.

Resume signalling — and the interesting one. The specification requires the host to drive resume signalling for at least 20 ms, and specifies no upper bound.

The Linux kernel drives it for 40 ms, and documents why at length. Its reasoning, in its own words, is twofold: a 20 ms sleep may expire slightly before 20 ms and fail electrical certification; and

Some (many) devices actually need more than 20 ms of resume signalling, and while we can argue that's against the USB Specification, we don't have control over which devices a certification laboratory will be using for certification.

The conclusion is a 40 ms timeout chosen to cope with both calibration errors and devices not following every detail of the USB Specification.

Suspend and resume from the Configured state

8 cycles
A waveform of suspend and resume for a configured device. The base state from the protocol state machine reads Configured throughout. A suspend request pulse, produced after the bus has been idle longer than the threshold, sets the suspended bit and captures Configured into the saved state. While suspended, the effective state continues to read Configured because it follows the saved state. A resume request pulse then clears the suspended bit and produces a single-cycle resume-into-configured event. The effective state reads Configured for the entire sequence. The figure shows controller-domain decoded events and registered state, not electrical line conditions, and depicts no real durations.idle threshold reached — capture the stateidle threshold reached —capture the statesuspended; effective state UNCHANGEDsuspended; effective stateUNCHANGEDresume signalling seenresume signalling seenback to Configured — and never left itback to Configured — andnever left itbase_stateCFGCFGCFGCFGCFGCFGCFGCFGsuspend_reqresume_reqsuspendedsaved_state----CFGCFGCFGCFGCFGCFGeffective_stateCFGCFGCFGCFGCFGCFGCFGCFGresume_to_cfgt0t1t2t3t4t5t6t7
Figure 2 — the overlay through a full cycle. Note that the effective state never leaves Configured: the device is suspended from Configured, so every consumer gating on the effective state continues to see a configured device throughout.

6. Mutation Test

Five mutations, run against a bench that suspends and resumes from each of the four states. Three of them behaved differently from the prediction, and the differences are the useful part.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  mutation                              fails when suspended from …
  ─────────────────────────────────────────────────────────────────
  correct overlay                       (nothing)
  U1  fixed return state (Default)       Powered, Address, Configured
  U2  infer from the configuration       Powered, Address
  U3  reset preserves saved_state        (nearly benign — see below)
  U3b reset branch removed entirely      the post-reset window
  U4  redundant suspend overwrites       only under deliberate stimulus

U1 — a fixed return state

The §3 failure: resume always returns to Default.

Result. Fails from Powered, Address and Configured — and passes from Default, because Default is the fixed target and a device suspended from Default is returned there correctly by accident.

That accidental pass is worth noticing. A test suspending only from Default reports this mutant clean, and Default is a plausible state to test from because it is where enumeration starts.

The practical failure is total. Every bus idle period silently re-enumerates the device, which is exactly what suspend exists to avoid.

U2 — infer the return state from the configuration

The plausible fix: resume to Configured if a configuration is held, otherwise Default.

Result, and it is worse than predicted. It fails from Powered as well as Address — both map to Default, because neither holds a configuration. It works only from Configured and, coincidentally, from Default.

Which sharpens the lesson. The inference does not merely lose the Address/Default distinction; it collapses three states into one. Configured is the only state it can identify, because a configuration register is the only thing that distinguishes any state from the others.

And it still passes the common case, which is what makes it dangerous: a device is normally suspended while configured, and that is the one path the inference gets right.

U3 — a bus reset preserves the saved state

Remove the saved_state clearing from the reset branch, leaving the suspended clearing in place.

Result: nearly benign. The stale saved state is never used, because suspended was cleared and the effective state therefore follows the base state. Only a check reading saved_state directly notices.

U3b — remove the reset branch entirely

Leave both suspended and saved_state untouched by a bus reset.

Result, traced directly:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
                           after a bus reset while suspended from Configured
  correct overlay          suspended=0  effective=DEV_DEFAULT
  U3  (saved stale only)   suspended=0  effective=DEV_DEFAULT
  U3b (branch removed)     suspended=1  effective=DEV_CONFIGURED   ← the defect

The device reports Configured while the host believes it has just reset it to Default, and continues to until something resumes it. Both ends disagree and neither errors.

U4 — a redundant suspend request overwrites the saved state

Remove the && !suspended guard.

Result: it depends entirely on the stimulus, and that is the finding.

Under natural stimulus — the base state holding constant while the device is suspended, which is what really happens, because the state machine is receiving no events — the mutation is behaviourally equivalent. Re-capturing an unchanged value changes nothing.

Under deliberate stimulus that moves the base state while suspended, it fails immediately: the saved state is overwritten and the device resumes into the wrong place.

So the guard protects against a condition the surrounding design currently prevents. That is the same judgment as U3's, and the same conclusion: keep it, and know that its redundancy is a property of another block rather than of this one. A physical-loss path that updated the base state, or a refactor letting some event through while suspended, would make the guard load-bearing with nothing to announce the change.

7. Verification

This chapter's commit point is the device returned where it came from.

Stimulus. Suspend and resume from each of the four states — Powered, Default, Address and Configured; a bus reset while suspended, from each; physical loss while suspended; a redundant suspend request; a resume request while not suspended; and suspend immediately following a state transition, so the captured value is exercised at a boundary.

The stimulus requirement §6 makes non-negotiable: suspend from every state, not just the realistic one. U2 works only from Configured and Default and fails from both Powered and Address; U1 passes from Default by accident because Default is its fixed target. A plan testing the realistic case — a configured device going idle — or the convenient one — a device at the start of enumeration — reports both mutants clean.

Observation. The suspended bit, the saved state, and the effective state — the last being the one consumers act on, and therefore the one whose correctness matters.

Reference model. A two-field model: expected suspended, expected saved state. Compare the effective state derived from both against the DUT's. The model is small and worth building because the property it checks — resume returns where suspend captured — spans two events separated by an arbitrary interval, which is awkward to express as a single temporal property and trivial for a model.

Representative coverage — crosses:

  • suspend from each of the four states × resume
  • suspend from each state × bus reset while suspended
  • suspend from each state × physical loss while suspended
  • redundant suspend × resume-while-not-suspended
  • suspend immediately after each state transition

Negative cases with defined outcomes: a resume while not suspended must do nothing; a redundant suspend must not overwrite the saved state; a bus reset while suspended must produce Default and not the saved state; and physical loss must leave nothing to resume into.

8. Debugging: the Device That Re-enumerates

A device works. If left idle for a minute it re-enumerates, and any transfer in progress fails. The user reports it as a device that "disconnects when you stop using it".

What does idle for a minute point at? Suspend. It is the only mechanism triggered by the absence of traffic, and the timescale matches a host idling a bus rather than anything the device or the application does.

What does re-enumerates tell you? That the device came back at the default address with no configuration — which is Default. So it suspended from Configured and resumed into Default.

Which mutation is this? §6's U1 if it resumes to Default from every state, or U2 if it happens to be an Address-state case. The reported symptom — from Configured — points at U1.

What is the first observation? The saved state at the moment of suspend, and the effective state at the moment of resume. If the saved value is right and the resumed state is wrong, the return path is the bug; if no saved value exists, the design is a peer-state model and §3 is the diagnosis.

Why does the user's description mislead? Disconnects when you stop using it describes a physical event, and there is none. Nothing was unplugged and nothing lost power. The device performed a transition it was designed to perform and returned to the wrong place.

And the signature? A device that loses state after a period of inactivity, with no physical event, is a resume-path failure — and the interval is the tell, because nothing else in USB is triggered by a minute of nothing happening.

9. Common Misconceptions

10. Reason It Through

A controller models suspend as a sixth enum value and stores the return state in a separate register alongside it. A reviewer argues this is equivalent to §4's overlay, since both carry two pieces of information.

Is the information content the same? Yes. A suspended bit plus a saved state, or an enum value plus a saved state — both hold suspended and where from.

So where do they differ? In what consumers see. §4 exports an effective_state that equals the saved state while suspended, so a block gating on Configured keeps working. The sixth-value design exports a state that reads SUSPENDED, so every consumer must be changed to (state == CONFIGURED) || (state == SUSPENDED && saved == CONFIGURED).

Could the sixth-value design export an effective state too? Yes — and if it does, the two are genuinely equivalent, because the enum value has become an internal detail and the exported interface is the same.

So what is the real distinction? Not how the state is stored but what is exported. The overlay's advantage is not the bit; it is that the natural thing to export is already the right thing. In the sixth-value design, exporting the raw state is natural and wrong, and exporting a derived effective state requires someone to have recognised the problem first.

And the design principle? Choose the representation whose obvious usage is correct. Both designs can be made right; one of them is right by default and the other is right only if the designer sees the trap. Chapter 8.5 §3's derived-versus-stored argument has the same shape — storing can be done correctly, and deriving is correct without anyone having to remember.

11. Understanding Check

12. Summary

Suspend is not a sixth state. It is a modifier on the other four, and a device suspends from a state and resumes to it — which is what makes it the one place in this module where how you got here is part of the state. The Linux kernel says so explicitly: four suspended states carrying one value, a reasonable abstraction for a host and not one a controller can make, because the controller is the thing that has to go back.

It is also the only transition above Powered the device causes, and it is triggered by absence — bus idleness — which is why it needs a duration to be meaningful and why resume must be an explicit signal rather than the return of traffic.

A peer-state model breaks at resume, with nowhere to go. §6 measured the responses: a fixed return state re-enumerates the device on every idle period — and passes from Default by accident, because Default is its fixed target; inference from the registers collapses three states into one, getting right only Configured, because a configuration register is the only thing that distinguishes any state from the others; and keeping everything and deriving works while revealing that the return state needed storing all along.

The overlay makes that explicit — a suspended bit, a saved state, and an effective state that consumers use. That last output is the design's real content: a block gating on Configured keeps working unchanged through a suspend, whereas a sixth enum value propagates a compound condition into every consumer of the state.

Reset overrides the saved value, for the same reason it overrides everything: the host has asserted a new starting point.

And the timing carries a lesson beyond its numbers. Resume signalling is specified as at least 20 ms with no maximum, and a major host drives 40 ms — documenting that many devices need more than the specification allows and that it cannot control which ones a certification laboratory will use. Where a specification bounds one direction only, the other is set by whatever shipped.

13. Where This Leaves You

Module 8 is complete. Six states, one state machine, an overlay, and a set of invariants that hold across blocks.

What the module actually built is a way of reasoning about protocol state that survives contact with real controllers:

  • Five state domains — physical, PHY, protocol, RTL registers, firmware — each derived from the one below, each able to disagree while every block stays locally correct.
  • Protocol state as a small authoritative abstraction that gates a controller rather than containing it: an input to everything and the implementation of nothing.
  • States as claims about registers, which makes composition invariants — properties spanning a state machine and the registers that give it meaning — the only things that catch the module's characteristic bugs. §8.3 measured eight state-machine properties passing a device answering at the wrong address.
  • Safety, progress and composition as three disjoint families, established by mutations that defeat two of the three at a time.
  • Derived over stored, wherever timing and clock domains allow, because a derived signal cannot disagree with its source and a stored one creates an obligation per transition.

What comes next opens what Configured brought to life. Module 9 is USB Endpoints — the abstraction every transfer rides on, and the hardware this module has referred to for six chapters as an abstract enable.

The connection is direct: this module established when endpoints may operate. Module 9 establishes what they are — addressing, direction, numbering, and the buffering model every device controller implements.

Browse the full path on the USB tutorials index.

Continue learning

Standards & specifications

Governing standard
USB-IF (Universal Serial Bus Specification)(opens USB Implementers Forum (USB-IF) in a new tab)

Defines the USB bus — its electrical signalling, connectors, packet and transaction model, device framework and the descriptors a device must expose — together with the device-class specifications layered on it. It does not define host-controller register interfaces (xHCI and EHCI are separate documents) nor any operating system's driver architecture.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the USB curriculum.