apache / apache/nuttx

[BUG] arch/arm/rp23xx: SPI DMA completion waits are uninterruptible with no timeout — one stalled transfer wedges the whole network stack

Open
#19,305 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
4k
Forks
1.7k
Avg merge
1d 17h
Merged PRs (30d)
237

Description

> **Disclaimer:** This report was prepared with AI assistance (Claude Code). I reviewed it, verified the code citations against master myself, and validated the behaviour on real hardware where noted before filing.

*Vs `arch/arm/src/rp23xx/rp23xx_spi.c` at master `50f91ef502`.*

## Description

The SPI DMA exchange path waits for completion with two back-to-back
untimed, uninterruptible semaphore waits (l. 1196 and l. 1201):

```c
if (nxsem_wait_uninterruptible(&priv->dmasem) != OK)
{
spierr("dma error\n");
}

if (nxsem_wait_uninterruptible(&priv->dmasem) != OK)
{
spierr("dma error\n");
}
```

If a DMA transfer never completes, the calling thread sleeps forever with
no escape. DMA is on by default (`RP23XX_DMAC` default y,
`RP23XX_SPI_DMA` default y, threshold 4), so effectively all bulk SPI
transfers take this path.

## Impact observed on real hardware

With a W5500 Ethernet controller on SPI0 (W5500-EVB-Pico2), network
drivers run their transfers from the LP work queue while holding the
network lock. When the wait stalled, the LP worker slept forever holding
`net_lock`: ping stopped, every shell command touching the network
(`ifconfig`, ...) blocked immediately after echo, and even the driver's
own TX-timeout recovery could not run (it is queued to the same blocked
LP worker). The system was otherwise alive (non-network shell paths
responsive).

A/B on the same board and workload: with `CONFIG_RP23XX_SPI_DMA=n` the
identical external event left the system fully healthy. (The same
untimed-wait pattern appears worth checking in `rp2040_spi.c`, from which
this port derives.)

## Suggested fix

Use a bounded wait (e.g. `nxsem_tickwait_uninterruptible()` with a
transfer-size-derived timeout); on timeout, stop the DMA channels, log,
and fall back to polled PIO or return an error — degrade instead of
deadlocking.

---
*Disclosure: found during an AI-assisted (Claude Code) audit; the A/B
observation is from my own hardware testing.*

Contributor guide

Open the contributing guide

Research direction

Start in arch/arm/src/rp23xx/rp23xx_spi.c at the two DMA semaphore waits around lines 1196 and 1201, then review the RP23XX_DMAC and RP23XX_SPI_DMA defaults. Compare the related wait pattern in rp2040_spi.c. Done means a stalled transfer no longer blocks indefinitely and instead reaches the proposed timeout recovery or error path; validate against the W5500 SPI workload if hardware is available.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.