Skip to content

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

Description

@ricardgb

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions