From c588728777db64621a63badb454eda18e0918bb7 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 27 Aug 2026 02:26:51 +0200 Subject: [PATCH] octeon: handle EPROBE_DEFER when reading MAC addresses The octeon ethernet driver reads the MAC addresses from ndo_init(), far too late to ask for a retry, and cvm_oct_probe() cannot unwind once it started the packet I/O hardware. Check the port nodes at the top of the probe instead, where returning an error is still free. On the EdgeRouter the addresses sit in a fixed-layout cell on the SPI flash, which since 6.18.45 is not readable that early, so all ports got a random MAC address. Not upstream yet. Refresh the octeon patches. Assisted-by: Claude:claude-opus-5 Link: https://github.com/openwrt/openwrt/pull/24924 (cherry picked from commit fffaf972ddbc9203207110a671fd47a2eed58e0c) Link: https://github.com/openwrt/openwrt/pull/25055 Signed-off-by: Hauke Mehrtens --- ...upport-EPROBE_DEFER-when-reading-MAC.patch | 66 +++++++++++++++++++ .../110-er200-ethernet_probe_order.patch | 4 +- ...-honor_sgmii_node_device_tree_status.patch | 2 +- 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 target/linux/octeon/patches-6.12/105-staging-octeon-support-EPROBE_DEFER-when-reading-MAC.patch diff --git a/target/linux/octeon/patches-6.12/105-staging-octeon-support-EPROBE_DEFER-when-reading-MAC.patch b/target/linux/octeon/patches-6.12/105-staging-octeon-support-EPROBE_DEFER-when-reading-MAC.patch new file mode 100644 index 00000000000..07a43347761 --- /dev/null +++ b/target/linux/octeon/patches-6.12/105-staging-octeon-support-EPROBE_DEFER-when-reading-MAC.patch @@ -0,0 +1,66 @@ +From: Hauke Mehrtens +Date: Thu, 27 Aug 2026 20:00:00 +0200 +Subject: [PATCH] staging: octeon: support EPROBE_DEFER when reading MAC + addresses + +The per port MAC addresses are read in cvm_oct_common_init(), which runs +as ndo_init() from register_netdev(). When the NVMEM provider holding +them is not available yet - on the Ubiquiti EdgeRouter it is an MTD +partition on the SPI flash - of_get_ethdev_address() returns +-EPROBE_DEFER and every port ends up with a random MAC address that +changes on every boot. + +Returning the error from ndo_init() does not help: it only makes +register_netdev() fail and the interface disappear. cvm_oct_probe() has +no unwind path either once it started to bring up the packet I/O +hardware. + +Look at all port nodes at the very beginning of cvm_oct_probe() instead, +where returning an error is still free, and ask to be probed again later +when one of them is not readable yet. + +Signed-off-by: Hauke Mehrtens +--- + drivers/staging/octeon/ethernet.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +--- a/drivers/staging/octeon/ethernet.c ++++ b/drivers/staging/octeon/ethernet.c +@@ -670,6 +670,27 @@ static void cvm_set_rgmii_delay(struct o + priv->phy_mode = PHY_INTERFACE_MODE_RGMII; + } + ++/* ++ * The per-port MAC addresses may live in an NVMEM provider that is not there ++ * yet, for example an MTD partition on a SPI flash. The netdevs read them from ++ * ndo_init(), which is far too late to ask for a retry: once cvm_oct_probe() ++ * has begun to bring up the packet I/O hardware there is no way back. Look at ++ * all of them here instead, while returning an error is still free. ++ */ ++static bool cvm_oct_mac_addresses_deferred(struct device_node *pip) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ for_each_available_child_of_node_scoped(pip, interface) { ++ for_each_available_child_of_node_scoped(interface, port) { ++ if (of_get_mac_address(port, mac) == -EPROBE_DEFER) ++ return true; ++ } ++ } ++ ++ return false; ++} ++ + static int cvm_oct_probe(struct platform_device *pdev) + { + int num_interfaces; +@@ -689,6 +710,9 @@ static int cvm_oct_probe(struct platform + return -EINVAL; + } + ++ if (cvm_oct_mac_addresses_deferred(pip)) ++ return -EPROBE_DEFER; ++ + cvm_oct_configure_common_hw(); + + cvmx_helper_initialize_packet_io_global(); diff --git a/target/linux/octeon/patches-6.12/110-er200-ethernet_probe_order.patch b/target/linux/octeon/patches-6.12/110-er200-ethernet_probe_order.patch index 133e167d2c3..1c17f7fc2b3 100644 --- a/target/linux/octeon/patches-6.12/110-er200-ethernet_probe_order.patch +++ b/target/linux/octeon/patches-6.12/110-er200-ethernet_probe_order.patch @@ -1,6 +1,6 @@ --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c -@@ -676,6 +676,7 @@ static int cvm_oct_probe(struct platform +@@ -697,6 +697,7 @@ static int cvm_oct_probe(struct platform int interface; int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE; int qos; @@ -8,7 +8,7 @@ struct device_node *pip; int mtu_overhead = ETH_HLEN + ETH_FCS_LEN; -@@ -797,13 +798,19 @@ static int cvm_oct_probe(struct platform +@@ -821,13 +822,19 @@ static int cvm_oct_probe(struct platform } num_interfaces = cvmx_helper_get_number_of_interfaces(); diff --git a/target/linux/octeon/patches-6.12/701-honor_sgmii_node_device_tree_status.patch b/target/linux/octeon/patches-6.12/701-honor_sgmii_node_device_tree_status.patch index fdfbc233aba..87f1327122b 100644 --- a/target/linux/octeon/patches-6.12/701-honor_sgmii_node_device_tree_status.patch +++ b/target/linux/octeon/patches-6.12/701-honor_sgmii_node_device_tree_status.patch @@ -12,7 +12,7 @@ Tested-by: Johannes Kimmel Signed-off-by: Roman Kuzmitskii --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c -@@ -877,8 +877,10 @@ static int cvm_oct_probe(struct platform +@@ -901,8 +901,10 @@ static int cvm_oct_probe(struct platform case CVMX_HELPER_INTERFACE_MODE_SGMII: priv->phy_mode = PHY_INTERFACE_MODE_SGMII;