Re: [PATCH net-next v13 5/6] net: dsa: mxl862xx: recover switch stuck in MCUboot rescue mode
From: Andrew Lunn <andrew@lunn.ch>
Date: 2026-09-08 12:38:43
Also in:
driver-core, linux-doc, lkml
On Mon, Sep 07, 2026 at 07:38:40PM +0100, Daniel Golle wrote:
A broken or interrupted firmware image, or the sticky rescue bit, keeps
the switch in its MCUboot bootloader, which exposes only the clause-22
SMDIO download interface. The clause-45 MMD API never comes up, so probe
would fail with -ETIMEDOUT and the only way back would be the switch's
UART console, or a power cycle or out-of-band reset (not currently
implemented).
Probe for the loader over SB PDI at setup, before any clause-45 access,
since the C45 API floods the log with CRC errors when no firmware
answers. A scratch write to two mailbox registers first establishes
that a switch is there at all. It reaches a running firmware as well,
but lands in registers that firmware does not read, so it is inert
there. The status register the loader publishes then tells the cases
apart without touching C45: a running firmware, which answers with its
own non-zero status word (0x0003 on the firmware tested), so probe
continues normally; a loader idle in its console loop, confirmed live
by a register-read challenge; a loader wedged mid-download, the one
case that publishes zero; the flashless download loop, which this
driver cannot drive; and a switch whose scratch write does not latch --
absent, unpowered, misdescribed in the device tree (wrong address or
bus, or a reset GPIO with inverted polarity), or with its SB PDI window
somewhere other than the OTP reset offsets assumed here. The first
three enter rescue mode or normal operation, the last two fail probe
cleanly with -EOPNOTSUPP and -ENODEV instead of a CRC-error storm.
A loader that publishes the ready magic but never services the
register-read challenge fails probe too, with -ENXIO. The challenge is
what tells the loader apart from a firmware whose status word happens
to read the same value, and offering to flash a healthy firmware would
be worse than refusing to bind, so a mailbox that does not answer is
treated as unusable rather than as a flash target. Every loader tested
services it.
In rescue mode the switch registers without user interfaces so devlink
stays available: user ports fail port_setup with -ENODEV (the DSA core
re-registers them as unused) while shared and CPU ports succeed, and the
CPU port works on its fixed link with mac_select_pcs returning no PCS.
Firmware API commands fail fast with -ENODEV and the port and STP
callbacks become no-ops.
An interrupted download can leave the loader wedged mid-payload. A
background work item off the devlink flash path drains it back to a
clean ready state by feeding the outstanding byte count one byte at a
time, which takes tens of minutes for a large image and is logged as it
progresses; until then devlink dev info reports no version and devlink
dev flash returns -EBUSY, and -EIO once a drain has failed for good.
Reaching the end of the count is all the drain does: the loader then
verifies the corrupt image and returns to its console loop on its own,
so the drain reprobes and lets the probe-time detection re-classify the
switch -- a valid image that a last-moment interruption left bootable
comes up as running firmware, with no second-guessing in the drain path.
The re-probe the drain schedules is the same device_schedule_reprobe()
hand-off the flash path uses: the core skips it if the device is
unbound or shut down before it fires, so a drain finishing after the
driver is gone does nothing. Should scheduling it fail, recovery is
marked failed, since the loader would otherwise sit at a clean ready
state that nothing reclassifies while devlink keeps promising that a
retry will work.
The CHIP ID registers need a running firmware, so no asic.id/asic.rev is
reported in rescue mode. Once the loader is ready, devlink dev info
reports the null firmware version "0.0.0" as both running and stored:
$ devlink dev info mdio_bus/mdio-bus:10
mdio_bus/mdio-bus:10:
driver mxl862xx
versions:
running:
fw 0.0.0
stored:
fw 0.0.0
An operational switch never reports 0.0.0 (a released firmware's major
is non-zero), so version-comparing tools like fwupd offer every release
as an upgrade, recovering the switch through the regular flash flow,
matched on the driver name. The flash skips the FW_UPDATE command since
MCUboot is already waiting. A successful flash reboots the switch into
the new firmware and the reprobe then brings the driver up against it
normally; after a failed one the switch is still in MCUboot, rescue mode
is detected again, and the user can retry.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew