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.
Line numbers vs
drivers/net/w5500.cat master50f91ef502.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 queueinginto 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 anySN_IRbit outsideRECV|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_atomicfailure (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 thiswith a perfect SPI bus).
w5500_interrupt_work()still falls through todone: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 defaultpull-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 pendingSn_IRbits, actonly on
RECV|SEND_OK, warn on the rest — never fence from theinterrupt 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.
done:ifw_bifupis still true.netdev_carrier_off().A reference implementation, validated on both boards above, is at:
https://github.com/ricardgb/nuttx/tree/w5500-driver-fixesDisclosure: analysis and reference fixes developed with AI assistance
(Claude Code), reviewed and hardware-validated by me. All citations can be
verified directly against master.