PCIe · Module 18
Hot Reset — Resetting a Link Without Removing Power
Sometimes PCIe logic must be reset without pulling the platform reset pin. Hot Reset carries that instruction in-band — and teaches the reset architecture lesson the rest of the curriculum depends on: releasing a reset is not the same as being ready.
A system sometimes needs to reset a device's PCIe logic — after a firmware update, a wedged endpoint, a failed recovery, or an operator's instruction.
The obvious mechanism is unavailable. Asserting the platform's fundamental reset means pulling a physical pin, and that pin is usually shared, usually not under software control at runtime, and usually resets far more than the one device in question. On a running server, "reset that card" cannot mean "reset the slot's power domain."
So the instruction has to travel over the Link itself — the same Link that is about to be reset.
How does PCIe reset a device's protocol logic through in-band signalling, what does that reset actually touch, and when is it safe to send traffic again?
1. The Verified Sources
2. Four Resets, Four Scopes
The distinctions that make this chapter worth reading, all sourced in §1.
| Fundamental Reset | Hot Reset | FLR | Link Layer Reset | |
|---|---|---|---|---|
| Carried by | a platform pin (perst_n_i) | in-band Link signalling | a Configuration Space write | a local reset input |
| Scope, per §1 | "the core (PHY and Link layer blocks) except for the core configuration registers" | Link and protocol state (§7) | "the function's Configuration Space registers… except Sticky registers" | "only the Link layer block" |
| Granularity | the whole device | the Link and what is behind it | one Function | one layer |
| Initiated by | the platform | software, via a port | software, on the Function | local logic |
| Available at runtime? | usually not | yes | yes | yes |
| Restriction | — | — | "only enabled for Endpoints" | — |
Read the Fundamental Reset row carefully, because it destroys the intuition that "fundamental" means "everything." §1 says it resets PHY and Link layer blocks except for the core configuration registers — so even the strongest reset in the table deliberately preserves something.
And read the FLR row against it. FLR resets "the function's Configuration Space registers" — exactly the thing Fundamental Reset spares.
They are not ordered by strength. They have different shapes, and asking "which is stronger" is the wrong question. Asking "which state does this touch" is the right one (§7).
3. Hot Reset Is Not Fundamental Reset
The instinct is that Hot Reset is a software-triggered version of the reset pin. It is not, and §1 shows why in one line.
Fundamental Reset is a wire. perst_n_i — a platform signal, asserted by the platform, resetting "the core (PHY and Link layer blocks)." It does not travel over the Link, and on a running system it is usually not available per-device: pulling it typically means resetting a power domain shared with other things.
Hot Reset travels over the Link. It is carried in training ordered sets (§1), which means the Link must be working well enough to carry it — and that is the constraint that shapes everything about it.
4. Hot Reset Is Not FLR
One of the most valuable distinctions in PCIe, and §1 sources both sides.
| Hot Reset | Function Level Reset | |
|---|---|---|
| Scope | the Link and the hierarchy behind it | one Function |
| Delivered by | in-band Link signalling | a Configuration Space register write |
| Does the Link go down? | yes — it must re-establish | no — the Link stays up throughout |
| Config Space | §7 — not fully asserted here | "reset to their default values (except Sticky registers)" |
| Availability | any port | "only enabled for Endpoints" |
| Completion | Link re-establishment | an explicit acknowledgement (§1's flr_ack_i) |
The row that matters most is the third. FLR does not take the Link down. A multi-Function device can have one Function reset while the others keep transacting over the same Link — because FLR's scope is a Function, and the Link is shared.
Hot Reset takes the Link down for everything behind it. Every Function on the device, and — depending on topology — devices further down.
So "reset the device" is ambiguous in a way that matters operationally. If a single Function is wedged on a multi-Function card, FLR resets it without disturbing the others. Hot Reset resets all of them and interrupts every transaction in flight.
5. Master and Slave
§1's three active substates encode two roles, not one.
HOT_RESET_MASTER_UP initiating, Link up
HOT_RESET_MASTER_DOWN initiating, Link down
HOT_RESET_HOT_RESET receiving (Slave)The Master is the port that was told to reset its partner — typically a Downstream Port whose Secondary Bus Reset register was written (§6). It transmits the instruction.
The Slave is the port that receives it — and §1 shows how: "typically 2 consecutive TS OS with the appropriate Control Symbol bit set." It observes and qualifies (§9).
Two ownership problems, exactly as in Chapter 18.9 §7, and §9 keeps them in separate blocks for the same reason: a local command must not be lost; remote evidence must be qualified.
On propagation through a hierarchy, this chapter is deliberately careful. Link training is hop-local — each Link trains with its immediate neighbour (Chapter 17.3 §16) — and a Switch is a device with ports, not a wire.
So a reset directed at a Switch's Downstream Port affects the Link below it and the hierarchy behind that Link. The exact rules by which a Switch propagates reset behaviour downstream are not stated in this chapter's evidence, and this chapter does not invent them. What it does assert is the negative, which is the part engineers get wrong: Hot Reset is not a TLP (§13), and it is not forwarded the way a Switch forwards packet traffic.
6. The Register Write Is the Initiator, Not the Mechanism
Chapter 18.5 §1's cause register names the trigger: direct_to_hot_reset — "directed into Hot Reset (Secondary Bus Reset Register)."
The chain has four links, and collapsing it is a common error:
software writes Secondary Bus Reset on a bridge/port
↓
that port's control logic requests Hot Reset
↓
the LTSSM transmits the instruction in-band
↓
the partner qualifies it, enters Hot Reset, and resets its state"Hot Reset is just writing Secondary Bus Reset" is wrong in a way that matters for debugging. The write is a request to a port. Everything that actually resets anything happens afterwards, in hardware, over the Link — and can fail at any of the three later steps.
Which is why §14's first ladder does not stop at "the write happened." A write that succeeded, with a partner that never entered Hot Reset, means the instruction was transmitted and not accepted — and §1 names a specific, legitimate reason: the partner's hot_reset bit in ltssm_prevent_rx_ts_entry_to may be set to disabled, refusing received-TS entry entirely (§9).
7. What Actually Resets
8. The Reset Cascade
9. Two Entry Paths, and the Same Bit-Error Hazard
§1 gives Hot Reset the identical structure to Disable (Chapter 18.9 §7):
| Directed (Master) | Observed (Slave) | |
|---|---|---|
| Origin | Secondary Bus Reset write (§6) | "typically 2 consecutive TS OS" |
| Bit-error exposed? | no | yes |
| Separately disableable? | no | yes — ltssm_prevent_rx_ts_entry_to[1] |
| RTL | §10's request latch | §10's qualifier |
And the hazard is the same, with a different consequence. Two consecutive corrupted training ordered sets can reset the Link — and unlike Disable, which stops participation, a spurious Hot Reset destroys Data Link and Transaction Layer state (§7, §8): outstanding Requests, credits, replay contents.
§1's mitigation is per-state, so a system can refuse remote Hot Reset while still accepting remote Disable — or neither. The directed path is unaffected either way, because a register write does not travel over the noisy channel.
The design consequence for §10: the qualifier counts consecutive observations and resets to zero on any non-matching one — scattered errors never accumulate. And the enable is an input, not an assumption.
10. The Hot Reset Subtree
Four things to read out of the figure.
Two Master substates, because §1 distinguishes initiating with the Link up from initiating with it down (§3).
The observed path is coloured as a hazard — it is the one two bit errors can trigger (§9).
Exit goes to Detect, not to L0. A Hot Reset ends in a bring-up, not a resumption — the Physical Layer went down, so training, configuration and flow-control initialization all run again.
And the final arrow is labelled deliberately. Reaching L0 is not the same as being ready to transmit; §11 is about the difference.
11. Five Events That Are Not the Same Event
The reset-architecture lesson this chapter exists for.
1. reset REQUEST someone asked (a register write, or received TS)
2. reset ASSERTION the reset is active (may be immediate)
3. state CLEARING the state is gone (takes cycles; scope matters)
4. reset RELEASE the reset deasserts (an edge)
5. functional READINESS you may use it again (the Link is retrained,
credits reinitialized)They are routinely collapsed into one, and every collapse is a distinct bug.
Collapsing 1 and 2 loses a request that arrives while the controller is busy — Chapter 18.9 §12's problem, and mutation 3 here.
Collapsing 2 and 3 assumes state disappears the moment reset asserts. §4's FLR evidence shows otherwise: the application logic resets itself and acknowledges when done, because the core cannot know how long it takes.
Collapsing 4 and 5 is the big one, and §12 measured it. Reset deassertion says "I have stopped resetting you." Readiness says "the Link exists again." Between them lie Detect, Polling, Configuration and flow-control initialization — microseconds during which reset is deasserted and nothing works.
§1's cascade is the architectural answer (§8): each layer is held in reset by the layer below being unready, so readiness — not reset release — is what enables the layer above.
12. RTL — Request Latch, Remote Detector, and Signalling Descriptor
// SYNTHESIZABLE. Normalized Hot Reset types and reset-domain scope.
// THE DOMAINS follow section 1's cascade evidence. They are NOT a claim
// about which Configuration Space fields survive -- section 7 marks that
// NOT ASSERTED, and no signal here pretends to know.
package hotrst_pkg;
typedef enum logic [1:0] {
HR_SRC_NONE = 2'd0,
HR_SRC_LOCAL = 2'd1, // Secondary Bus Reset write -> Master (section 6)
HR_SRC_REMOTE = 2'd2 // qualified TS with the Hot Reset bit -> Slave
} hotrst_src_e;
// ==================================================================
// RESET DOMAINS, NOT A GLOBAL RESET.
//
// `assign global_reset = hot_reset;` is the design this package exists
// to prevent. Section 1's cascade shows the domains are LAYERED and
// that at least one thing is deliberately EXCLUDED -- configuration
// registers stay readable when the link is down.
// ==================================================================
typedef struct packed {
logic dll_state; // sequence numbers, replay buffer, ACK/NAK (15.x)
logic fc_state; // flow-control credits (16.x) -- DLL state
logic ltssm_training; // qualification history, candidate config
logic tl_context; // outstanding Tags, in-flight request context
// NOTE THE ABSENCE of a config_registers bit. Section 1 states Root
// Port configuration registers are deliberately kept readable when
// the link is down; section 7 declines to assert Hot Reset's exact
// Configuration Space scope. A domain this design cannot justify
// is a domain it must not drive.
} reset_domains_t;
function automatic reset_domains_t all_link_domains();
return '{ dll_state: 1'b1, fc_state: 1'b1,
ltssm_training: 1'b1, tl_context: 1'b1 };
endfunction
endpackageimport hotrst_pkg::*;
// SYNTHESIZABLE. Hold a LOCAL (directed) Hot Reset request.
// A SECONDARY BUS RESET WRITE IS A ONE-CYCLE PULSE (section 6). The
// episode controller may be busy. A pulse wired straight into the entry
// condition is lost, and the software that requested the reset sees
// nothing happen (section 15, mutation 3).
module hotrst_request_latch (
input logic clk,
input logic rst_n,
input logic sbr_write_pulse,
input logic request_taken,
input logic abort,
output logic request_pending
);
logic p_q;
assign request_pending = p_q;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n || abort) p_q <= 1'b0;
else if (request_taken) p_q <= 1'b0; // consumed EXACTLY once
else if (sbr_write_pulse) p_q <= 1'b1;
end
endmoduleimport hotrst_pkg::*;
// SYNTHESIZABLE. Qualify a REMOTE Hot Reset instruction.
// SECTION 1: "typically 2 consecutive TS OS with the appropriate Control
// Symbol bit set" -- AND the hazard that two corrupted TS can spell it
// (section 9). THRESH is parameterised; this chapter publishes no
// normative count.
module hotrst_remote_qual #(
parameter int THRESH = 2,
parameter int CNT_W = (THRESH <= 1) ? 1 : $clog2(THRESH + 1)
) (
input logic clk,
input logic rst_n,
input logic rx_ts_entry_enabled, // section 1's per-state mitigation
input logic obs_valid,
input logic obs_hot_reset_bit,
// ==============================================================
// CLEARED ON RESET ENTRY. Section 13 measured this exact bug: with
// history retained, 25.0% of (stream, reset-point) cases qualify
// prematurely after the reset using PRE-reset observations.
// ==============================================================
input logic episode_restart,
output logic [CNT_W-1:0] count,
output logic remote_hot_reset
);
generate
if (THRESH < 1) $error("THRESH must be at least 1");
if ((1 << CNT_W) < (THRESH + 1)) $error("CNT_W too narrow for THRESH");
endgenerate
logic [CNT_W-1:0] cnt_q;
assign count = cnt_q;
assign remote_hot_reset = rx_ts_entry_enabled && (cnt_q >= CNT_W'(THRESH));
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) cnt_q <= '0;
else if (episode_restart) cnt_q <= '0;
else if (obs_valid) begin
// CONSECUTIVE, not cumulative -- the defence against scattered
// bit errors accumulating into a reset instruction (section 9).
if (obs_hot_reset_bit) begin
if (cnt_q < CNT_W'(THRESH)) cnt_q <= cnt_q + CNT_W'(1);
end else cnt_q <= '0;
end
end
endmoduleClassification: all three synthesizable.
Failure — four. Pulsing the directed request loses it. Cumulative counting lets bit errors accumulate into a reset. Ignoring rx_ts_entry_enabled removes §1's own mitigation. And not clearing history on episode restart — §13's measured 25%.
13. RTL — Episode Controller, Domain Fanout, and Release Coordinator
import hotrst_pkg::*;
// SYNTHESIZABLE. One Hot Reset episode.
// THESE ARE TEACHING PHASES. Section 1 verifies the Master/Slave roles;
// it does not publish the transition criteria a normative substate
// encoding would need. This is not the LTSSM.
module hotrst_controller (
input logic clk,
input logic rst_n,
input logic request_pending, // local (section 12)
input logic remote_hot_reset, // remote (section 12)
input logic link_up, // MASTER_UP vs MASTER_DOWN (section 1)
input logic signal_sent, // the instruction was transmitted
input logic domains_cleared, // every driven domain reports done
input logic link_ready, // retrained, configured, DL up
output logic request_taken,
output logic start_signal,
output logic hot_reset_active,
output logic episode_restart,
output logic episode_pulse, // ONE per episode (section 14)
output hotrst_src_e source
);
typedef enum logic [2:0] {
S_IDLE, S_MASTER_SIGNAL, S_SLAVE_ACCEPT, S_CLEARING, S_WAIT_LINK, S_DONE
} st_e;
st_e st_q;
hotrst_src_e src_q;
assign source = src_q;
assign request_taken = (st_q == S_IDLE) && request_pending;
assign start_signal = (st_q == S_MASTER_SIGNAL);
// ==================================================================
// hot_reset_active SPANS CLEARING AND RETRAINING.
//
// It does NOT drop when the domains finish clearing. Section 11: reset
// release is not readiness, and the Link has to be rebuilt after the
// state is gone.
// ==================================================================
assign hot_reset_active = (st_q inside {S_MASTER_SIGNAL, S_SLAVE_ACCEPT,
S_CLEARING, S_WAIT_LINK});
// ONE PULSE PER EPISODE, on entry -- not per qualifying observation.
// Section 13 measured the level-counting alternative: a single reset
// episode over-counted by up to +9.
assign episode_pulse = (st_q == S_IDLE) && (request_pending || remote_hot_reset);
assign episode_restart = episode_pulse;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin st_q <= S_IDLE; src_q <= HR_SRC_NONE; end
else begin
unique case (st_q)
S_IDLE :
// LOCAL WINS a same-cycle tie: this port was explicitly told to
// reset its partner, and that instruction still has to go out.
if (request_pending) begin
src_q <= HR_SRC_LOCAL;
st_q <= link_up ? S_MASTER_SIGNAL : S_CLEARING;
end else if (remote_hot_reset) begin
src_q <= HR_SRC_REMOTE;
st_q <= S_SLAVE_ACCEPT;
end
// MASTER_UP: the instruction can be delivered, so send it first.
// MASTER_DOWN skipped straight to clearing above -- section 3.
S_MASTER_SIGNAL : if (signal_sent) st_q <= S_CLEARING;
S_SLAVE_ACCEPT : st_q <= S_CLEARING;
// State clearing takes cycles and is NOT instantaneous (section 11).
S_CLEARING : if (domains_cleared) st_q <= S_WAIT_LINK;
// AND THEN THE LINK MUST BE REBUILT. This state is the difference
// between reset release and readiness.
S_WAIT_LINK : if (link_ready) st_q <= S_DONE;
S_DONE : st_q <= S_IDLE;
default : st_q <= S_IDLE;
endcase
end
end
endmoduleimport hotrst_pkg::*;
// SYNTHESIZABLE. Drive ONLY the domains this reset is defined to affect.
// THIS BLOCK EXISTS TO PREVENT ONE LINE: `assign global_reset = hot_reset;`
// Section 1's cascade shows the domains are layered and that
// configuration registers are deliberately excluded (section 8).
module hotrst_domain_fanout (
input logic clk,
input logic rst_n,
input logic hot_reset_active,
input logic clearing_phase,
// Per-domain completion. Each domain knows when IT is done; this block
// does not guess (the lesson from section 4's FLR acknowledgement).
input logic dll_clear_done,
input logic fc_clear_done,
input logic ltssm_clear_done,
input logic tl_clear_done,
output reset_domains_t domain_reset,
output logic domains_cleared
);
// Asserted only during the clearing phase, and only for declared domains.
assign domain_reset = clearing_phase ? all_link_domains() : '0;
// EVERY driven domain must report done. A design that proceeded on the
// first completion would release with state still live in the others.
assign domains_cleared = dll_clear_done && fc_clear_done
&& ltssm_clear_done && tl_clear_done;
// NOTE: nothing here drives configuration registers. Section 7 declines
// to assert Hot Reset's Configuration Space scope, and section 1 shows
// config registers are deliberately kept readable when the link is
// down. Driving a domain this design cannot justify is mutation 15.
endmodule// SYNTHESIZABLE. THE FLAGSHIP BLOCK OF THIS CHAPTER.
// Traffic resumes on READINESS, never on reset deassertion (section 11).
module hotrst_release_coord (
input logic hot_reset_active,
input logic local_reset_done, // our own state is cleared
input logic ltssm_link_ready, // trained, configured, DL layer up
output logic protocol_enable
);
// ==================================================================
// ALL THREE CONDITIONS.
//
// assign protocol_enable = !hot_reset_active; // WRONG
//
// Section 15 enumerated all 32 input combinations: the wrong version
// transmits a TLP into an untrained Link in 3 of them. This version
// does so in 0.
//
// This is section 1's cascade in miniature: a layer is enabled by the
// readiness of what it depends on, not by the absence of a reset.
// ==================================================================
assign protocol_enable = !hot_reset_active
&& local_reset_done
&& ltssm_link_ready;
endmoduleClassification: all three synthesizable.
domains_cleared requires every driven domain, following §4's FLR lesson: each domain knows when it is done, and the coordinator waits rather than guessing. A design that proceeded on the first completion would release with state still live elsewhere.
And the fanout's most important property is what it does not drive. §7 declines to assert Hot Reset's Configuration Space scope, so no signal here touches configuration registers — mutation 15 is the version that adds one "for completeness."
14. RTL — Diagnostics
import hotrst_pkg::*;
// SYNTHESIZABLE. Lab diagnostics. Saturating, EDGE-driven.
module hotrst_diag #(parameter int CYC_W = 32, parameter int EVT_W = 16) (
input logic clk,
input logic rst_n,
input logic hot_reset_active,
input logic episode_pulse, // ONE per episode (section 13)
input hotrst_src_e source,
input logic exit_state_valid,
input logic clear,
output logic [EVT_W-1:0] hot_reset_count,
output logic [EVT_W-1:0] local_count,
output logic [EVT_W-1:0] remote_count,
output logic [CYC_W-1:0] last_duration,
output hotrst_src_e last_source
);
logic [EVT_W-1:0] n_q, l_q, r_q;
logic [CYC_W-1:0] cur_q, last_q;
hotrst_src_e s_q;
assign hot_reset_count = n_q; assign local_count = l_q;
assign remote_count = r_q; assign last_duration = last_q;
assign last_source = s_q;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n || clear) begin
n_q<='0; l_q<='0; r_q<='0; cur_q<='0; last_q<='0; s_q<=HR_SRC_NONE;
end else begin
// ==============================================================
// ONE INCREMENT PER EPISODE. Section 15 measured the alternative:
// counting every qualifying observation over-counts a SINGLE
// reset episode by up to +9, because the instruction is
// transmitted repeatedly by design.
// ==============================================================
if (episode_pulse) begin
if (!(&n_q)) n_q <= n_q + EVT_W'(1);
s_q <= source;
cur_q <= '0;
// LOCAL vs REMOTE, separately. Section 16's first question.
if (source == HR_SRC_LOCAL && !(&l_q)) l_q <= l_q + EVT_W'(1);
if (source == HR_SRC_REMOTE && !(&r_q)) r_q <= r_q + EVT_W'(1);
end else if (hot_reset_active) begin
if (!(&cur_q)) cur_q <= cur_q + CYC_W'(1);
end else if (exit_state_valid) begin
last_q <= cur_q;
end
end
end
endmoduleClassification: synthesizable (instrumentation).
Separating local_count from remote_count is what makes §17's first question answerable. A device resetting unexpectedly is a completely different investigation depending on whether this port initiated it or the partner instructed it — and a single total cannot tell them apart.
last_duration measures the whole episode, including retraining — because §11's point is that the reset is not over when the reset signal drops.
15. Assertions
// SVA over the Hot Reset blocks. LOCAL contract only. Nothing asserts that
// a reset completes, that the Link retrains, or that the partner accepts.
// ---- ENVIRONMENT ------------------------------------------------------
assume property (@(posedge clk) disable iff (!rst_n)
sbr_write_pulse |=> !sbr_write_pulse);
assume property (@(posedge clk) disable iff (!rst_n)
(up_valid && !up_ready) |=> (up_valid && $stable(up_payload)));
// ---- REQUEST OWNERSHIP ------------------------------------------------
// P1: A LOCAL RESET REQUEST IS NEVER LOST. A Secondary Bus Reset write is
// a one-cycle pulse and the controller may be busy (section 12).
property p_request_held;
@(posedge clk) disable iff (!rst_n)
(request_pending && !request_taken && !abort) |=> request_pending;
endproperty
a_held : assert property (p_request_held);
// P2: REMOTE DETECTION REQUIRES QUALIFIED, CONSECUTIVE EVIDENCE, and is
// gated by section 1's per-state mitigation (section 9).
property p_remote_qualified;
@(posedge clk) disable iff (!rst_n)
remote_hot_reset |-> (rx_ts_entry_enabled && (count >= CNT_W'(THRESH)));
endproperty
a_qual : assert property (p_remote_qualified);
// P2b: a non-matching observation resets the count to ZERO -- the defence
// against scattered bit errors accumulating into a RESET instruction.
property p_reset_to_zero;
@(posedge clk) disable iff (!rst_n)
(obs_valid && !obs_hot_reset_bit) |=> (count == '0);
endproperty
a_zero : assert property (p_reset_to_zero);
// P3: the signalling descriptor is stable while the generator stalls.
property p_descriptor_stable;
@(posedge clk) disable iff (!rst_n)
(sig_valid && !sig_ready) |=> (sig_valid && $stable(sig_kind)
&& $stable(sig_hot_reset_bit));
endproperty
a_desc : assert property (p_descriptor_stable);
// P4: and the Hot Reset bit is set. Without it the partner receives
// ordinary training sets and no reset occurs (mutation 4).
property p_bit_set;
@(posedge clk) disable iff (!rst_n) sig_valid |-> sig_hot_reset_bit;
endproperty
a_bit : assert property (p_bit_set);
// ---- TRAFFIC AND THE RELEASE -- THE CENTRAL PROPERTIES ----------------
// P5: NO NORMAL PACKET TRANSFER DURING HOT RESET, and a packet offered
// remains upstream-owned.
property p_no_transfer;
@(posedge clk) disable iff (!rst_n)
hot_reset_active |-> !(up_valid && up_ready);
endproperty
a_noxfer : assert property (p_no_transfer);
property p_symmetric;
@(posedge clk) disable iff (!rst_n)
(up_valid && up_ready) <-> (down_valid && down_ready);
endproperty
a_sym : assert property (p_symmetric);
// P6: TRAFFIC RESUMES ON READINESS, NEVER ON RESET DEASSERTION.
// THE flagship property of this chapter. Section 15 enumerated all 32
// input combinations: `protocol_enable = !hot_reset_active` transmits into
// an untrained Link in 3 of them; this form does so in 0.
property p_enable_needs_ready;
@(posedge clk) disable iff (!rst_n)
protocol_enable |-> (!hot_reset_active && local_reset_done
&& ltssm_link_ready);
endproperty
a_ready : assert property (p_enable_needs_ready);
// P6b: restated as a transfer property, independently of protocol_enable,
// so a miswired enable fails rather than agreeing with itself.
property p_no_transfer_before_ready;
@(posedge clk) disable iff (!rst_n)
(up_valid && up_ready) |-> (local_reset_done && ltssm_link_ready);
endproperty
a_noearly : assert property (p_no_transfer_before_ready);
// ---- RESET DOMAINS ----------------------------------------------------
// P7: EVERY DRIVEN DOMAIN MUST REPORT DONE before clearing completes.
// Proceeding on the first completion releases with state still live
// elsewhere (mutation 14).
property p_all_domains;
@(posedge clk) disable iff (!rst_n)
domains_cleared |-> (dll_clear_done && fc_clear_done
&& ltssm_clear_done && tl_clear_done);
endproperty
a_domains : assert property (p_all_domains);
// P7b: DOMAIN RESETS ARE ASSERTED ONLY DURING THE CLEARING PHASE, and only
// for declared domains. Section 7 declines to assert Hot Reset's exact
// Configuration Space scope, so nothing here may drive it (mutation 15).
property p_domain_scope;
@(posedge clk) disable iff (!rst_n)
(domain_reset != '0) |-> clearing_phase;
endproperty
a_scope : assert property (p_domain_scope);
// P8: A CANDIDATE CONFIGURATION CANNOT BECOME ACTIVE DURING A RESET. The
// configuration being committed describes a Link that is being torn down
// (Chapter 18.5 P14's reasoning, one layer over).
property p_no_commit_during_reset;
@(posedge clk) disable iff (!rst_n)
hot_reset_active |-> !$rose(active_config_valid);
endproperty
a_nocommit : assert property (p_no_commit_during_reset);
// ---- EPISODE ACCOUNTING -----------------------------------------------
// P9: THE SOURCE IS CAPTURED AND STABLE for the episode. Section 16's first
// debugging question depends on local vs remote being trustworthy.
property p_source_stable;
@(posedge clk) disable iff (!rst_n)
(hot_reset_active && !episode_pulse) |=> $stable(source);
endproperty
a_src : assert property (p_source_stable);
// P10: ONE EPISODE PER RESET, however many times the instruction is
// signalled. Section 15 measured the alternative: a single episode
// over-counted by up to +9, because repeated signalling IS the design.
property p_one_episode;
@(posedge clk) disable iff (!rst_n)
(hot_reset_count > $past(hot_reset_count)) |-> $past(episode_pulse);
endproperty
a_episode : assert property (p_one_episode);
// P10b: and a pulse cannot occur while an episode is already running.
property p_no_nested;
@(posedge clk) disable iff (!rst_n)
(hot_reset_active && !$rose(hot_reset_active)) |-> !episode_pulse;
endproperty
a_nested : assert property (p_no_nested);
// P11: STALE DATA LINK STATE IS NOT REUSED. Replay and credit state are
// reset when the Physical Layer goes down (sections 7, 8), so post-reset
// operation must start from reinitialized values.
property p_no_stale_dll;
@(posedge clk) disable iff (!rst_n)
$fell(hot_reset_active) |-> ((dut_replay.occupancy == '0)
&& (dut_fc.credits_initialized == 1'b0));
endproperty
a_dll : assert property (p_no_stale_dll);
// P12: PRE-RESET QUALIFICATION HISTORY CANNOT COMPLETE POST-RESET
// QUALIFICATION. Section 15 measured retention: 25.0% of reset points
// qualify prematurely.
property p_no_stale_history;
@(posedge clk) disable iff (!rst_n)
episode_restart |=> (count == '0);
endproperty
a_history : assert property (p_no_stale_history);
// P13: reset dominates.
property p_reset;
@(posedge clk)
!rst_n |=> (!hot_reset_active && !request_pending && !protocol_enable);
endproperty
a_reset : assert property (p_reset);P6 and P6b are the pair that matters most, and they are deliberately redundant. P6 constrains protocol_enable; P6b constrains the transfer directly, without mentioning protocol_enable at all — so a design whose enable logic is correct but whose gate reads something else still fails.
P12 is the stale-history property, measured at 25.0% (§15), and P11 is its Data Link counterpart — both express the same principle: state that described the pre-reset Link is not evidence about the post-reset one.
And P7b is a property about restraint. It asserts that the fanout drives only the domains this chapter can justify — because §7's honest answer to "what does Hot Reset touch" includes three rows marked not asserted, and a design that drove them anyway would be resetting state on the strength of a guess.
No liveness. "Hot Reset eventually completes" depends on the partner and on retraining; "the Link eventually becomes ready" depends on the channel.
16. Verification, Fault Injection, and Model Verification
Executed before publication.
Reset-release gating — exhaustive
All 32 combinations of (hot_reset_active, local_reset_done, link_ready, up_valid, down_ready), checking whether a TLP transfers while the Link is not actually ready:
| Implementation | Transfers into an unready Link |
|---|---|
| §13's coordinator (all three conditions) | 0 of 32 |
protocol_enable = !hot_reset_active | 3 of 32 |
All three failing cases have hot_reset_active = 0 — the reset has been released — with local_reset_done or link_ready still low. That is the entire gap between §11's events 4 and 5, enumerated.
Stale qualification history across a reset
Every 8-observation stream × every reset point — 1,792 cases, THRESH = 2, checking whether qualification completes after the reset using observations from before it:
| Implementation | Premature post-reset qualifications |
|---|---|
| history cleared on episode restart | 0 |
| history retained | 448 of 1,792 (25.0%) |
One in four. Not a rare interleaving — a quarter of all reset points leave enough history that a single new observation completes a qualification that should have required two.
Episode counting with repeated signalling
All 1,024 signal patterns of length 10, compared against an independent run-counting model:
| Implementation | Result |
|---|---|
edge-detected (episode_pulse) | 0 mismatches |
| counting every qualifying observation | over-counts a single episode by up to +9 |
And repeated signalling is not pathological — it is the design. The instruction is transmitted many times so it survives bit errors, exactly as Chapter 18.9 §6's 16-to-32 announcement is.
Directed tests
- Local request while the controller is busy — verify it is held (P1). Required.
- Remote detection with exactly
THRESHconsecutive observations;THRESH − 1then a non-matching one — verify no entry (§9's defence). Required. rx_ts_entry_enabledlow with a full qualifying sequence — verify no entry, and that the local path still works (§9).- Local and remote in the same cycle — verify one episode, source
HR_SRC_LOCAL(§17's audit). - Master with link up vs link down — verify the signalling phase is taken only when it can be delivered (§3).
- Repeated reset signalling throughout an episode — verify one episode counted (P10). Required.
- Domains reporting done at different times — verify
domains_clearedwaits for all. hot_reset_activedeasserted withlink_readylow — verify no traffic (P6). Required, and the §16 counterexample.- A packet offered during every phase — verify no transfer and no acceptance (P5).
- Post-reset training observations — verify pre-reset history does not contribute (P12).
- Reset during L0, during Recovery, and during an L0s/L1 abstraction.
- Replay and credit state after re-establishment — verify reinitialization rather than reuse (§7, §8).
- Repeated back-to-back episodes; reset during clearing.
The scoreboard runs its own reset-domain and release model — recomputing expected protocol_enable from (hot_reset_active, local_reset_done, link_ready) alone — and never reads the DUT's controller enum, counters or domains_cleared.
Mutations
| # | Mutation | Caught by | Lab symptom |
|---|---|---|---|
| 1 | Hot Reset treated as Fundamental Reset | scoreboard | attempts to reset a Link that cannot carry the instruction (§3) |
| 2 | Hot Reset treated as FLR | scoreboard | resets the whole Link when one Function was meant (§4) |
| 3 | one-cycle local request lost | P1 | software writes Secondary Bus Reset and nothing happens |
| 4 | Hot Reset bit omitted from the descriptor | scoreboard | partner sees ordinary TS1; no reset occurs |
| 5 | descriptor changes under stall | P3 | a partially-signalled instruction |
| 6 | normal traffic accepted during reset | P5 | packet destroyed; unrecoverable above |
| 7 | protocol_enable = !hot_reset_active | P6 | TLP into an untrained Link — 3 of 32 (measured) |
| 8 | replay state reused after reset | P11 | stale sequence numbers against a reinitialized partner |
| 9 | credit state reused after reset | P11 | transmitting against credits the partner never advertised |
| 10 | training qualifier not cleared | P12 | 25% of reset points qualify prematurely (measured) |
| 11 | candidate config commits during reset | P8 | a configuration from before the reset becomes active |
| 12 | local/remote source misattributed | P9 | investigation starts at the wrong device |
| 13 | every qualifying observation counted | P10 | one reset reported as up to 10 (measured) |
| 14 | domains released before all report done | P7 | state still live in one domain when traffic resumes |
| 15 | fanout drives configuration registers | review + §7 | resets state the evidence does not place in scope |
| 16 | stale packet accepted after reset without revalidation | P5 | a pre-reset packet transmitted on a post-reset Link |
| 17 | Hot Reset confused with the Secondary Bus Reset bit itself | §6 | "the write succeeded so the reset happened" (§17) |
| 18 | Switch behaviour generalized to all topologies | §5 | propagation assumptions this evidence does not support |
Same-cycle audit
| Case | Declared resolution |
|---|---|
| reset observed + a packet offered | no transfer — the gate is combinational off protocol_enable (P5) |
| local + remote reset in the same cycle | one episode, source HR_SRC_LOCAL (§13); the local instruction still has to be transmitted |
| reset + a Recovery commit ready | reset wins — the configuration being committed is about to be discarded |
| reset + a Disable request | reset wins, matching Chapter 18.9 §18's declared priority from the other side |
hot_reset_active deasserts + link_ready still low | no traffic (P6) — the whole point |
| post-reset observation + pre-reset history | history is already cleared by episode_restart (P12) |
| repeated signalling while already active | no new episode (P10) |
Declared priority: reset > disable > ordinary state commits. Stated because it is a local contract, not because this chapter's evidence makes it normative (§17).
17. Debugging
Symptom → local or remote → signal → distinguishing experiment.
The first question is last_source (§14). A device resetting unexpectedly is a different investigation depending on who asked.
A device disappears and reappears without a reboot
Read hot_reset_count and last_source.
HR_SRC_LOCAL: this port initiated it — something wrote Secondary Bus Reset. A management agent, a driver reload, an error-handling path. Working as instructed; find the writer.
HR_SRC_REMOTE: the partner instructed it — or §9's bit-error hazard fired. Distinguished by: whether the partner's software actually requested a reset. If it did not, and the channel is marginal, two consecutive corrupted TS may have spelled the instruction — and §1's ltssm_prevent_rx_ts_entry_to[1] turns that path off.
Then confirm the recovery path. After a Hot Reset the LTSSM should walk Detect → Polling → Configuration → L0 (§10). If it does not reach L0, the reset succeeded and the re-establishment failed — a different problem, in Chapters 18.2–18.4.
The first transactions after a Hot Reset fail
Suspect the release, not the reset — §16's counterexample.
The signature is unmistakable once you know it: the first transactions after a reset fail or vanish; transactions issued slightly later work perfectly; and adding a delay after the reset "fixes" it.
That last property is the tell. A defect a sleep can hide is a timing window, and here the window is the re-establishment interval.
The distinguishing experiment: sample protocol_enable against link_ready and dl_link_up continuously across a reset. If protocol_enable ever rises while either is low, it is mutation 7 — and P6 is that check made permanent.
Two related candidates with the same symptom: replay or credit state reused across the reset (mutations 8 and 9) — check that sequence numbers restart and that credits come from a fresh InitFC (Chapter 16.1) rather than from retained values.
hot_reset_count increases unexpectedly
Three candidates, and one number separates the first two.
Compare local_count against remote_count. Local increments mean something on this side keeps writing Secondary Bus Reset. Remote increments mean the partner — or §9's hazard.
And if the total is implausibly large relative to observed outages, suspect mutation 13 — counting every qualifying observation rather than one per episode. §16 measured up to +9 for a single reset, and repeated signalling is the design, not an anomaly. Distinguished by: comparing the count against the number of observed link-down events.
FLR works but Hot Reset does not
Expected — they exercise different paths (§4), and this is not a contradiction to resolve but a clue to use.
FLR is a Configuration Space write handled by the Function, with an explicit acknowledgement, and the Link stays up throughout. Hot Reset is in-band signalling that takes the Link down.
So FLR working proves Configuration Space access and the Function's reset logic are fine — and says nothing about the Link path. If Hot Reset fails while FLR works, the fault is in the parts FLR never touches: the signalling path, the partner's acceptance (is rx_ts_entry_enabled off? §6), or the re-establishment afterwards.
And they are not interchangeable tests. Validating FLR does not validate Hot Reset, and a test plan that assumes it leaves the entire in-band path unexercised.
18. Common Misconceptions
- "Hot Reset is a power cycle." No power is removed; the device stays powered throughout.
- "Hot Reset is Fundamental Reset." One is a platform pin, the other is in-band signalling (§3).
- "Hot Reset is FLR." Link scope versus Function scope; FLR does not take the Link down (§4).
- "Hot Reset is just writing Secondary Bus Reset." The write is the initiator; three more steps follow (§6).
- "Hot Reset is a TLP." It travels in training ordered sets, below the packet layer.
- "A Switch forwards Hot Reset like packet traffic." It is not forwarded; Link training is hop-local (§5).
- "All Configuration Space state survives." Not asserted here — §7 marks it explicitly.
- "All state clears." §1 shows configuration registers deliberately kept readable when the link is down (§8).
- "Normal traffic may resume when reset deasserts." 3 of 32 combinations transmit into an untrained Link (§16).
- "The Link does not need re-establishment." The Physical Layer went down; exit goes toward Detect (§10).
- "Replay and credit state remain valid." They are Data Link state, reset when the Physical Layer goes down (§7, §8).
- "Repeated reset TS observations are multiple resets." Repeated signalling is the design (§16).
- "Hot Reset is software-only." Software initiates; hardware performs all of it (§6).
- "The PHY analog blocks must lose power." Nothing in this evidence requires that.
- "A Link that will not train can be Hot Reset." The instruction needs a working Link to arrive (§3).
19. Understanding Check
20. Module 18 in One Table
Nine states, nine engineering questions.
| State | The question it answers |
|---|---|
| Detect | Is a receiver physically there? |
| Polling | Can both sides reliably recognize training communication? |
| Configuration | Which lanes form this coherent Link? |
| Recovery | Can an existing Link be repaired or changed? |
| L0 | Is normal packet operation legal now? |
| L0s | Can one direction save power with a quick return? |
| L1 | Can the Link enter deeper, coordinated low power? |
| Disabled | Has Link participation been intentionally stopped? |
| Hot Reset | Must PCIe Link and protocol state be reset in-band? |
Read as a sequence, it stops being nine definitions and becomes one machine: establish, operate, maintain, economize, and — when instructed — stop or start over.
21. The Ownership Model
One rule connects Module 18 to everything above it:
PHY / electrical evidence
↓
LTSSM state
↓
normal-link eligibility
↓
TLP / DLLP machineryHigher layers may rely on the Link only when the LTSSM says the physical contract is valid.
| State | Normal traffic |
|---|---|
| Detect, Polling, Configuration | no — the Link does not exist yet |
| Recovery | no — the Link is being repaired or changed |
| L0 | yes — and only here |
| L0s, L1 | no — but the packet is retained while waking |
| Disabled | no — participation was stopped |
| Hot Reset | no — and not on reset release either (§11) |
The L0s and L1 rows are the subtle ones. In every other non-L0 state, "no traffic" means the Link is not usable. In the power states it means the packet waits — upstream-owned, unharmed, and transferred when the Link returns.
And one law appeared in six of these chapters (17.1, 17.3, 18.1, 18.6, 18.7, 18.8): a gate must gate both valid and ready. Every violation destroys a packet before the replay buffer's retention point, where no layer above can recover it.
A second law appeared in four (16.5, 17.3, 18.4, 18.5): state that multiple consumers depend on must change all at once or not at all.
And this chapter adds a third: readiness is not the absence of a reset.
22. What's Next
Hot Reset closes Module 18.
It is in-band, so it needs a working Link to reset that Link (§3) — which makes it the tool for wedged protocol state and not for a Link that will not train.
It is not Fundamental Reset and not FLR (§2), and the three are not ordered by strength: they have different shapes, and §1's evidence shows even the platform reset deliberately spares configuration registers.
And it teaches the reset architecture the rest of this curriculum depends on (§11): request, assertion, clearing, release and readiness are five events, and collapsing the last two transmits into an untrained Link in 3 of 32 combinations — a defect that a sleep will hide and a field failure will find.
Module 19 — PCIe Interrupts comes next. Everything so far has been about one adjacent Link: establishing it, operating it, powering it down, recovering it, disabling it, resetting it. Interrupts are the first mechanism that is not about the Link at all — how a device tells software that something happened, from legacy INTx through MSI and MSI-X to interrupt routing, over a Link this module has now fully explained.
The idea to carry forward: releasing a reset is a statement about the reset, not about the thing.