Network boot of Raspberry Pi 4 leads to unstable network in U-Boot

André Althaus <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
I'm trying to netboot a Raspberry Pi 4 B and use the U-Boot pxe bootflow 
to bring up a NixOS system (using the extlinux.conf file created by NixOS).
When I do that the U-Boot DHCP process retries multiple times to get an 
IP and sometimes running out of retries. The TFTP transfers afterwards 
show many timeouts (T).
I tried to boot the same firmware files and U-Boot binary from the SD 
card and then the pxe bootflow works without problems.
Every time the dhcp fails or the tftp timeout occurs, I can see the crc 
error counter on the switch port increase.

I suspect, that the firmware leaves the network peripherals in some 
state that is not completely reset/initialized by u-boot.

I tried to debug it with Qwen AI 3.8 and actually got a seemingly 
working patch. Obviously I'm not confident this is the correct fix.

/proc/cpuinfo:
Revision    : c03114
Serial        : 1000000057c90c1d
Model        : Raspberry Pi 4 Model B Rev 1.4

vcgencmd version:
May 21 2026 11:20:25
Copyright (c) 2012 Broadcom
version 288930ab4712b99596f32732664aaaeb881ef1e0 (clean) (release) (start)

rpi-eeprom-update:
BOOTLOADER: up to date
    CURRENT: So 17. Mai 19:13:18 UTC 2026 (1779045198)
     LATEST: Fr 9. Jan 16:12:13 UTC 2026 (1767975133)
    RELEASE: default 
(/nix/store/0a6v8w38pn6gfagyc5f0czz0jhhqpz40-raspberrypi-eeprom-2026.05.11-2712/lib/firmware/raspberrypi/bootloader-2711/default)
             Use raspi-config to change the release.

   VL805_FW: Using bootloader EEPROM
      VL805: up to date
    CURRENT: 000138c0
     LATEST: 000138c0

rpi-eeprom-config:
[all]
BOOT_UART=0
WAKE_ON_GPIO=1
ENABLE_SELF_UPDATE=1
BOOT_ORDER=0xf21
NET_INSTALL_AT_POWER_ON=1

u-boot master (ece349ade2973e220f524ce59e59711cc919263f):
make rpi_arm64_defconfig

Additional configs:
CONFIG_CMD_MII=y
CONFIG_BOOTSTD_FULL=y

CONFIG_USE_BOOTCOMMAND=y
CONFIG_BOOTCOMMAND="bootflow scan -lb pxe"

CONFIG_LOG=y
CONFIG_LOG_MAX_LEVEL=7
CONFIG_LOG_CONSOLE=y


During the debugging, Qwen told me to try the following manual reset of 
the PHY after the firmware started u-boot and before running the bootflow:
mii write 1 0 0x8000        # PHY soft reset
mii read  1 0                      # repeat until bit15 clears (PHY 
reset done)
1140
mii write 1 4 0x01E1        # advertise 10/100 F+H, pause (known-good value)
mii write 1 9 0x0300        # 1000T cap
mii write 1 0 0x1200        # AN enable + AN restart
mii read  1 1                      # expect 0x796D (link up) after ~2 s
7949

Afterwards the bootflow worked without problems.

It added the following patch which seems to fix the problems:
diff --git a/drivers/net/bcmgenet.c b/drivers/net/bcmgenet.c
index a0264dc386d..1c867e61dd2 100644
--- a/drivers/net/bcmgenet.c
+++ b/drivers/net/bcmgenet.c
@@ -601,6 +601,30 @@ static int bcmgenet_mdio_init(const char *name, 
struct udevice *priv)
      return mdio_register(bus);
  }

+static int bcmgenet_phy_soft_reset(struct bcmgenet_eth_priv *priv)
+{
+    int val;
+    int timeout = 100; /* ms */
+
+    /* Firmware may leave the internal GPHY in a state where MDIO
+     * auto-negotiation works but the RGMII data path corrupts frames,
+     * so force the PHY back to its defaults before attaching to it. */
+    if (bcmgenet_mdio_write(priv->bus, priv->phyaddr, 0, MII_BMCR, 
BIT(15)))
+        return -EIO;
+
+    do {
+        udelay(1000);
+        val = bcmgenet_mdio_read(priv->bus, priv->phyaddr, 0, MII_BMCR);
+        if (val < 0)
+            return val;
+    } while ((val & BIT(15)) && --timeout);
+
+    if (!timeout)
+        return -ETIMEDOUT;
+
+    return 0;
+}
+
  /* We only support RGMII (as used on the RPi4). */
  static int bcmgenet_interface_set(struct bcmgenet_eth_priv *priv)
  {
@@ -665,6 +689,12 @@ static int bcmgenet_eth_probe(struct udevice *dev)
          return ret;

      priv->bus = miiphy_get_dev_by_name(name);
+    if (!priv->bus)
+        return -ENODEV;
+
+    ret = bcmgenet_phy_soft_reset(priv);
+    if (ret)
+        return ret;

      return bcmgenet_phy_init(priv, dev);
  }

Its explanation:
The Broadcom legacy firmware performs its own DHCP/TFTP over the same 
GENET before loading U-Boot, then shuts the MAC/PD down and hands off 
without re-initialising the embedded GPHY. At hand-off the
GPHY's MDIO register file and IEEE auto-negotiation still function, so 
U-Boot's generic PHY machinery brings the link up cleanly — but the 
RGMII/PMA data path is left in a firmware-era state that corrupts
frames on the wire (bad FCS, visible only as the switch's receive CRC 
errors under load).

Two facts support this being an initialisation-missing problem rather 
than a driver bug in the normal path:

- The identical binary is stable when booting from SD, i.e. when the 
firmware never used the network (a clean, default-like GPHY state 
reaches U-Boot).
- A single PHY soft-reset at first use fully cures it; there is no other 
state difference between the two paths that was found 
(speed/duplex/advertise settings are identical once link is up).



If you need more information or some register values, I can provide them.

-- 
André Althaus
TU Dortmund/DELTA/Beschleunigerphysik
Maria-Goeppert-Mayer-Str. 2a
D-44221 Dortmund
Tel.: 0231 755 5488
smime.p7s (application/pkcs7-signature, 3.9 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.