Skip to content

axi_isolate deadlock when write transaction is sent during drain #441

Description

@dkimTT

PR WITH FIX: #443

Issue

With TerminateTransaction = 1'b1, axi_isolate instantiates a demux that routes the slave port either to axi_isolate_inner (port 0, normal operation) or to the axi_err_slv (port 1, while isolated). The demux ports slv_aw_select_i and slv_ar_select_i are driven by isolated_o.

The demux requires its selects to be stable while a request is pending: the ports are documented as "has to be stable, when aw_valid", and axi_demux_simple has slv_aw_select_stable / slv_ar_select_stable assertions for this. However, axi_isolate doesn't guard against violating that requirement, and therefore isolated_o as the select creates the bug: it rises at the end of a drain, which is a window in which the inner module is holding a request unaccepted. So any request that arrives during a drain and isn't accepted before it finishes draining produces the violation, firing the assertion.

For a write arriving while the inner module is draining:

  • While draining, axi_isolate_inner holds aw_ready low, so an AW presented during this window sits at the demux unaccepted for as long as the drain takes. When the drain finishes, isolated_o rises, and the select changes while the request is still pending.
  • The demux does not use the select the same way for the AW and W. The AW is routed by the live select, but the W beats follow w_select_q, which is latched when the AW is first presented (w_cnt_up increments regardless of aw_ready). Normally these agree because the select is stable for the whole handshake; here it changes mid-handshake.
  • So the AW completes on port 1 (axi_err_slv), while the W beats are sent to port 0 (axi_isolate_inner), which is now isolated with w_ready low. The error slave waits for write data that never arrives, the inner module never accepts it, no B response is ever returned, and the master hangs with w_valid stuck high. De-isolating does not recover this: the error slave is still waiting on W beats that are routed to port 0.
  • The AR path violates the same stability assumption (an AR pending across the isolated_o edge trips slv_ar_select_stable), though it happens to complete since reads don't have split routing.

Waveform

Image
  1. One write is in flight (pending_aw_q = 1) when isolation is requested; the AW FSM enters Drain.
  2. The master presents a new AW during the drain. isolated_o is still 0, so the demux sends it to port 0, locks the decision (lock_aw_valid_q), and latches w_select_q = 0. The inner module holds aw_ready low so the handshake cannot be completed.
  3. The drain completes and isolated_o rises with the AW still pending. (The slv_aw_select_stable assertion would fire here)
  4. The AW handshake then completes on port 1 (mst_reqs_o[1].aw_valid/aw_ready).
  5. The error slave raises w_ready on port 1 and waits, but the W beats are offered on port 0 (mst_reqs_o[0].w_valid high, w_ready never comes). No B is returned and the master's w_valid (and subsequent aw_valid) hang for the rest of the run.

Proposed fix

Drive the demux selects from a registered version of isolate_i that only updates on cycles where the respective channel has no pending unaccepted request, so the select is stable for the full duration of any handshake.

I have this implemented and am validating it locally, and can follow up with a PR once it's verified.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions