apache / apache/nuttx

[BUG] net/w5500: any spurious event permanently fences the interface (no recovery, no carrier indication)

Open
#19,304 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.

*Line numbers vs `drivers/net/w5500.c` at master `50f91ef502`.*

## Description

The driver treats every unexpected condition in its interrupt and receive
paths as fatal and responds with `w5500_fence()` — which disables the IRQ,
asserts hardware RST **and keeps it asserted**, and sets `w_bifup = false`
(l. 932–937). Nothing ever unfences again from these paths, and
`netdev_carrier_off()` is never called, so the network stack keeps queueing
into a dead device forever. The link LEDs go dark and the interface is
unrecoverable until a power cycle or manual `ifdown`/`ifup`.

Paths that fence permanently:

- `w5500_interrupt_work()`: a SIR bit for any socket other than 0
(l. 1542–1548), or `SN_IR == 0`, or any `SN_IR` bit outside
`RECV|SEND_OK` (l. 1563–1568) → `goto error` → fence (l. 1603–1605).
These "unexpected" bits are reachable in normal operation: spurious
CON/DISCON/TIMEOUT-shaped events, or a single glitched SPI read during
an interrupt burst.
- `w5500_receive()`: `read16_atomic` failure (l. 1266–1269),
`s0_rx_rsr < 2` (l. 1282–1286), `pktlen > s0_rx_rsr` (l. 1300–1307) →
fence (l. 1437–1438). One inconsistent length read bricks the interface
(see also the separate missing-`Sn_CR`-wait issue, which can produce this
with a perfect SPI bus).
- After an internal fence, `w5500_interrupt_work()` still falls through to
`done:` and unconditionally re-enables the level-low GPIO IRQ (l. 1599)
with the chip in reset and INTn floating. On the rp2040 reference glue,
`rp2040_common_initialize.c` (l. 195–197) leaves the pad's default
pull-down on the open-drain INTn, so this can become a level-low
interrupt storm / LPWORK livelock.

## Reproduction (real hardware)

Bursts of short-lived TCP connections (e.g. 200 × connect/close against
telnetd) wedge a W5500-EVB-Pico within 1–2 bursts with the stock driver.
With tolerant error handling (below) the same board survives repeated
bursts, flood ping, and a 40-minute soak with zero loss. Reproduced on
both W5500-EVB-Pico (rp2040) and W5500-EVB-Pico2 (rp23xx).

## Suggested fix

- `w5500_interrupt_work()`: acknowledge **all** pending `Sn_IR` bits, act
only on `RECV|SEND_OK`, warn on the rest — never fence from the
interrupt path.
- `w5500_receive()` error path: resync socket 0 (CLOSE + OPEN in MACRAW +
reset the local TX-ring mirror) and drop the partial frame instead of
fencing.
- Only re-enable the IRQ at `done:` if `w_bifup` is still true.
- Where a fence is genuinely terminal, report `netdev_carrier_off()`.

A reference implementation, validated on both boards above, is at:
`https://github.com/ricardgb/nuttx/tree/w5500-driver-fixes`

---
*Disclosure: analysis and reference fixes developed with AI assistance
(Claude Code), reviewed and hardware-validated by me. All citations can be
verified directly against master.*

Contributor guide

Open the contributing guide

Research direction

Start with drivers/net/w5500.c, especially w5500_interrupt_work() and w5500_receive(), then inspect the cited INTn setup in rp2040_common_initialize.c. Reproduce the short TCP-connection bursts on the W5500-EVB-Pico or Pico2 and compare behavior with the reference branch. Done means unexpected events or inconsistent lengths no longer permanently wedge the interface or cause an IRQ storm, while normal traffic survives the soak test.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.