Thread (5 messages) flat view 5 messages, 4 authors, 1d ago
WARM1d

[PATCH net v2] net: ethernet: mtk_eth_soc: allocate dummy netdev before registering netdevs

From: Sandeep Haemoon <hidden>
Date: 2026-09-20 17:38:33
Also in: stable
Subsystem: mediatek ethernet driver, networking drivers, the rest · Maintainers: Felix Fietkau, Lorenzo Bianconi, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

The RX rings and the shared NAPI are carried by an internal "dummy" netdev
(eth->dummy_dev). mtk_probe() creates that dummy device only after the MAC
netdevs have been registered, so for a brief window the netdevs are visible
to the network core while eth->dummy_dev is still NULL.

If anything brings the first netdev up during that window (e.g. netifd
opening the WAN link the instant the interface is registered), mtk_open()
takes the first-open path and runs mtk_start_dma() -> mtk_dma_init() ->
mtk_rx_alloc(), which calls __xdp_rxq_info_reg() with eth->dummy_dev ==
NULL. That triggers

  WARNING: CPU: ... Missing net_device from driver

in net/core/xdp.c and returns -ENODEV, so mtk_open() fails and the
interface stays down until it is manually brought up once probe finishes.

Allocate the dummy netdev and add the shared tx/rx NAPI to it before the
register_netdev() loop. Both the dummy-allocation failure and a
register_netdev() failure now unwind through mtk_unreg_dev(), which
unregisters the net_device notifiers and the netdevs registered so far -
stopping a concurrently-opened netdev (ndo_stop) and its NAPI before the
dummy carrier is freed. The never-registered netdevs are skipped thanks to
the NETREG_REGISTERED guard in mtk_unreg_dev() and freed directly.

Fixes: b209bd6d0bff ("net: mediatek: mtk_eth_sock: allocate dummy net_device dynamically")
Signed-off-by: Sandeep Haemoon <redacted>
---
Version 2:
  - Rebased on top of netdev/net.git, which now carries Lorenzo Bianconi's
    "mtk_eth_soc: unregister net_devices in case of probe failure" fix; the
    dummy allocation sits before the register_netdev() loop and both its
    failure and a register_netdev() failure unwind through mtk_unreg_dev(),
    unregistering the net_device notifiers and every netdev registered so
    far (never-registered ones are skipped by the NETREG_REGISTERED guard)
    before the dummy carrier is freed.
  - Error path stops any concurrently-opened netdev (ndo_stop, NAPI
    disabled) via that unregister, then frees the dummy carrier; a
    dummy-allocation failure likewise cleans the notifier chain that
    mtk_add_mac() registered.
  - Add Fixes: b209bd6d0bff, the commit that made eth->dummy_dev dynamic
    and introduced the NULL window.

 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 33 +++++++++++++--------
 1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 2ea5dfe85..5e7d8b8be 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -5341,6 +5341,22 @@ static int mtk_probe(struct platform_device *pdev)
 		}
 	}
 
+	/* we run 2 devices on the same DMA ring so we need a dummy device
+	 * for NAPI to work. Allocate it before registering the netdevs so a
+	 * concurrent ndo_open (e.g. netifd bringing the first netdev up the
+	 * instant it is registered) never observes eth->dummy_dev == NULL in
+	 * mtk_dma_init() -> mtk_rx_alloc() -> __xdp_rxq_info_reg() (net/core/xdp.c
+	 * "Missing net_device from driver") and fails the first open.
+	 */
+	eth->dummy_dev = alloc_netdev_dummy(0);
+	if (!eth->dummy_dev) {
+		err = -ENOMEM;
+		dev_err(eth->dev, "failed to allocated dummy device\n");
+		goto err_unreg_netdev;
+	}
+	netif_napi_add(eth->dummy_dev, &eth->tx_napi, mtk_napi_tx);
+	netif_napi_add(eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);
+
 	for (i = 0; i < MTK_MAX_DEVS; i++) {
 		if (!eth->netdev[i])
 			continue;
@@ -5355,18 +5371,6 @@ static int mtk_probe(struct platform_device *pdev)
 				   eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]);
 	}
 
-	/* we run 2 devices on the same DMA ring so we need a dummy device
-	 * for NAPI to work
-	 */
-	eth->dummy_dev = alloc_netdev_dummy(0);
-	if (!eth->dummy_dev) {
-		err = -ENOMEM;
-		dev_err(eth->dev, "failed to allocated dummy device\n");
-		goto err_unreg_netdev;
-	}
-	netif_napi_add(eth->dummy_dev, &eth->tx_napi, mtk_napi_tx);
-	netif_napi_add(eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);
-
 	platform_set_drvdata(pdev, eth);
 	schedule_delayed_work(&eth->reset.monitor_work,
 			      MTK_DMA_MONITOR_TIMEOUT);
@@ -5376,6 +5380,11 @@ static int mtk_probe(struct platform_device *pdev)
 err_unreg_netdev:
 	mtk_unreg_dev(eth);
 err_deinit_ppe:
+	if (eth->dummy_dev) {
+		netif_napi_del(&eth->tx_napi);
+		netif_napi_del(&eth->rx_napi);
+		free_netdev(eth->dummy_dev);
+	}
 	mtk_ppe_deinit(eth);
 	mtk_mdio_cleanup(eth);
 err_free_dev:
-- 
2.53.0

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help