Skip to content

axi: fix AxiStreamDmaV2 stray write burst at continued buffer boundary#1429

Open
ruck314 wants to merge 1 commit into
pre-releasefrom
axi-stream-dma-v2-continue-fix
Open

axi: fix AxiStreamDmaV2 stray write burst at continued buffer boundary#1429
ruck314 wants to merge 1 commit into
pre-releasefrom
axi-stream-dma-v2-continue-fix

Conversation

@ruck314
Copy link
Copy Markdown
Contributor

@ruck314 ruck314 commented Jun 2, 2026

Summary

AxiStreamDmaV2Write emits a stray write burst at a continued buffer's boundary. When a continued (multi-buffer) frame fills a buffer exactly on an AXI burst boundary, the engine falls through MOVE_S → IDLE_S → ADDR_S and issues one more burst at the next buffer's base address before the MOVE_S overflow check starts the continue. With maxSize already zero this is a degenerate zero-length burst one element past the buffer.

This manifests at two different boundaries on the XilinxVariumC1100:

Layer Per-buffer size Symptom
HbmDmaBuffer/HbmDmaBufferV2 (wrap AxiStreamDmaV2Fifo, on-chip HBM) 512 KiB (BUFF_FRAME_WIDTH_G=19) stray burst lands in the next contiguous HBM buffer → masked → corrupt frames > 512 KiB
Main PCIe DMA (AxiPcieDmaAxiStreamDmaV2Desc, host 2 MiB pages) 2 MiB (cfgSize) stray burst lands past the mapped page → AMD-Vi IO_PAGE_FAULT + PRBS errors > 2 MiB

Fix

Detect the exact-fill-on-burst-boundary case at burst completion and start the continue there (return the descriptor with continue set, release the buffer) instead of re-entering ADDR_S, so no boundary burst is emitted. contEn=0 keeps the legacy overflow/drop path unchanged. One change in AxiStreamDmaV2Write.vhd.

Verification (cocotb)

Two new datapath benches; the stray boundary burst is directly detectable in simulation:

  • test_AxiStreamDmaV2FifoLoopback.py — streams a frame through AxiStreamDmaV2Fifo (AXI-RAM-backed M_AXI) and checks it is re-merged byte-for-byte. A single-buffer frame passed before; any frame crossing the 256-byte buffer boundary failed. All pass after the fix.
  • test_AxiStreamDmaV2WriteContinue.py — drives a multi-buffer continue with distinct, gapped buffer addresses and asserts every write burst stays inside a declared buffer window (a burst landing in the gap between buffers is the IOMMU-fault signature). 2- and 3-buffer cases pass after the fix; reproduced the stray boundary burst before it.

Full tests/axi/dma suite: 21 passed.

Hardware status

Both boundaries confirmed fixed on hardware (rebuilt XilinxVariumC1100PrbsTester, PRBS software run):

  • 512 KiB: PRBS payloads across the 512 KiB boundary pass.
  • 2 MiB: PRBS payloads above 2 MiB pass — no AMD-Vi IO_PAGE_FAULT and no PRBS errors in dmesg.

When a continued (multi-buffer) frame fills a buffer exactly on an AXI
burst boundary, AxiStreamDmaV2Write falls through MOVE_S -> IDLE_S ->
ADDR_S and issues one more burst at the next buffer's base address before
the MOVE_S overflow check triggers the continue. With maxSize already
zero this is a degenerate zero-length burst at the buffer boundary:

  * Simulation: getAxiLen() is called with length 0 (typed
    "integer range 1 to 4096") -> bound-check failure.
  * Hardware: the off-by-one address is one element past the buffer.
    For the on-chip HBM store-and-forward (HbmDmaBuffer/HbmDmaBufferV2,
    which wrap AxiStreamDmaV2Fifo) it lands in the next contiguous buffer
    and is masked, corrupting frames larger than the per-buffer frame size
    (512 KiB on the XilinxVariumC1100). For the host PCIe DMA, where each
    continued buffer is a separately-mapped page, it lands past the
    mapping and raises an IOMMU IO_PAGE_FAULT once frames exceed the host
    buffer size (2 MiB).

Detect the exact-fill-on-burst-boundary case at burst completion and
start the continue there (return the descriptor with continue set,
release the buffer) instead of re-entering ADDR_S, so no boundary burst
is emitted. contEn=0 keeps the legacy overflow/drop path unchanged.

Add two cocotb regression benches:
  * test_AxiStreamDmaV2FifoLoopback.py -- streams a frame through
    AxiStreamDmaV2Fifo (AxiRam-backed M_AXI) and checks it is re-merged
    byte-for-byte; frames crossing the buffer boundary failed before.
  * test_AxiStreamDmaV2WriteContinue.py -- drives a multi-buffer continue
    with distinct, gapped buffer addresses and asserts every write burst
    stays inside a declared buffer window (the IOMMU-fault signature).

Full tests/axi/dma suite passes (21 tests).
@ruck314 ruck314 force-pushed the axi-stream-dma-v2-continue-fix branch from 54aea67 to 11a9277 Compare June 2, 2026 21:13
@ruck314 ruck314 changed the title axi: fix AxiStreamDmaV2 continue-frame zero-length burst calculation axi: fix AxiStreamDmaV2 stray write burst at continued buffer boundary Jun 2, 2026
@ruck314 ruck314 requested a review from bengineerd June 2, 2026 21:58
@ruck314 ruck314 marked this pull request as ready for review June 2, 2026 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant