Skip to content

xuartlite: fix race condition and receive overrun in XUartLite_SendBuffer#384

Open
dxmake wants to merge 1 commit into
Xilinx:masterfrom
dxmake:Fix-uartlite-lib
Open

xuartlite: fix race condition and receive overrun in XUartLite_SendBuffer#384
dxmake wants to merge 1 commit into
Xilinx:masterfrom
dxmake:Fix-uartlite-lib

Conversation

@dxmake

@dxmake dxmake commented Jul 9, 2026

Copy link
Copy Markdown

This commit addresses two critical bugs found in the XUartLite v3.11 driver when operating in interrupt-driven mode with heavy bidirectional (concurrent TX and RX) traffic on a Zynq-7000 platform.


Bug 1: Race condition causing Data Abort (bus error)

Root Cause:
XUartLite_SendBuffer() is called from both normal (non-interrupt)
context via XUartLite_Send(), and from interrupt context via the
shared TX/RX interrupt handler. The original implementation reads
the StatusRegister before disabling interrupts, then uses that
stale status to drive the FIFO fill loop. If an RX interrupt fires
between reading the status register and disabling interrupts, the
interrupt handler may also write to the TX FIFO. Both contexts
writing to the same 16-byte FIFO concurrently can overflow it,
triggering an AXI bus fault and a Data Abort.

Fix:
After disabling interrupts, re-read StatusRegister before entering
the FIFO fill loop. This guarantees the FIFO status used for
transmission reflects the hardware state after interrupts are
disabled, eliminating the window where interrupt-context FIFO writes
could race with normal-context writes.

As an alternative workaround, callers can bracket XUartLite_Send()
with XUartLite_DisableInterrupt() / XUartLite_EnableInterrupt().


Bug 2: Receive overrun errors during heavy transmission

Root Cause:
The original byte-by-byte FIFO fill loop writes at most a few bytes
per call. When optimized to batch-write up to the full 16-byte FIFO
capacity, filling all 16 slots causes ReceiveOverrunErrors under
concurrent full-duplex traffic. This suggests a hardware-level
boundary condition in the AXI UART Lite IP core: a completely full
TX FIFO interferes with or stalls the RX path, causing incoming
data loss. The original byte-by-byte approach masked this because
it never filled the FIFO completely in one atomic write sequence.

Fix:
Limit the batch write to 15 bytes (FIFO depth - 1), leaving one
FIFO slot free. This avoids the fully-saturated state that triggers
the RX overrun condition.


Testing:

  • Platform: Xilinx Zynq-7000 (XC7Z020), AXI UART Lite v3.11
  • Baud rate: 921600, full-duplex, -O0
  • Bug 1: Data Abort reliably reproduced; eliminated with the re-read-after-disable fix and/or caller-side interrupt bracketing.
  • Bug 2: Batch size 16 → ReceiveOverrunErrors observed; batch size 15 → zero overruns across >1,000,000 bytes of continuous transfer.

Please do not submit a Pull Request via github. Our project makes use of mailing lists for patch submission and review. For more details please see https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842172/Create+and+Submit+a+Patch

…ffer

This commit addresses two critical bugs found in the XUartLite v3.11
driver when operating in interrupt-driven mode with heavy bidirectional
(concurrent TX and RX) traffic on a Zynq-7000 platform.

---

Bug 1: Race condition causing Data Abort (bus error)

Root Cause:
  XUartLite_SendBuffer() is called from both normal (non-interrupt)
  context via XUartLite_Send(), and from interrupt context via the
  shared TX/RX interrupt handler. The original implementation reads
  the StatusRegister *before* disabling interrupts, then uses that
  stale status to drive the FIFO fill loop. If an RX interrupt fires
  between reading the status register and disabling interrupts, the
  interrupt handler may also write to the TX FIFO. Both contexts
  writing to the same 16-byte FIFO concurrently can overflow it,
  triggering an AXI bus fault and a Data Abort.

Fix:
  After disabling interrupts, re-read StatusRegister before entering
  the FIFO fill loop. This guarantees the FIFO status used for
  transmission reflects the hardware state *after* interrupts are
  disabled, eliminating the window where interrupt-context FIFO writes
  could race with normal-context writes.

  As an alternative workaround, callers can bracket XUartLite_Send()
  with XUartLite_DisableInterrupt() / XUartLite_EnableInterrupt().

---

Bug 2: Receive overrun errors during heavy transmission

Root Cause:
  The original byte-by-byte FIFO fill loop writes at most a few bytes
  per call. When optimized to batch-write up to the full 16-byte FIFO
  capacity, filling all 16 slots causes ReceiveOverrunErrors under
  concurrent full-duplex traffic. This suggests a hardware-level
  boundary condition in the AXI UART Lite IP core: a completely full
  TX FIFO interferes with or stalls the RX path, causing incoming
  data loss. The original byte-by-byte approach masked this because
  it never filled the FIFO completely in one atomic write sequence.

Fix:
  Limit the batch write to 15 bytes (FIFO depth - 1), leaving one
  FIFO slot free. This avoids the fully-saturated state that triggers
  the RX overrun condition.

---

Testing:
  - Platform: Xilinx Zynq-7000 (XC7Z020), AXI UART Lite v3.11
  - Baud rate: 921600, full-duplex, -O0
  - Bug 1: Data Abort reliably reproduced; eliminated with the
    re-read-after-disable fix and/or caller-side interrupt bracketing.
  - Bug 2: Batch size 16 → ReceiveOverrunErrors observed; batch size
    15 → zero overruns across >1,000,000 bytes of continuous transfer.

Signed-off-by: <julongjian> <talk5600@gmail.com>
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