designware_eth_probe may be called multiple times for a given device.
such as if the first probe (or post_probe) fails for whatever reason.
When this happens, subsequent probes still try to bind the MDIO bus,
creating several duplicate copies of the bus (all possibly sharing the
same of_node). This can cause an infinite loop in dm_mdio_probe_devices
if we have been probed at least once already:

dm_mdio_probe_devices()
 device_probe(dwmac.mac0)
  device_probe(dwmac)
   designware_eth_probe()
    device_bind_driver_to_node(dwmac.mac1)
    return -EFOO
 device_probe(dwmac.mac1)
  ...

Prevent this by binding the MDIO bus in designware_eth_bind instead of
designware_eth_probe.

Fixes: 5160b4567c71 ("net: designware: add DM_MDIO support")
Signed-off-by: Sean Anderson <[email protected]>
---

Changes in v2:
- Fix warnings about mdio_err and dw_mdio_init not being used
- Fix missing else clause when bitbang MDIO is enabled

 drivers/net/designware.c    | 30 ++++++++++++++++--------------
 drivers/net/designware.h    |  1 +
 drivers/net/dwmac_meson8b.c |  3 +++
 drivers/net/dwmac_s700.c    |  3 +++
 drivers/net/dwmac_socfpga.c |  3 +++
 drivers/net/dwmac_thead.c   |  3 +++
 drivers/net/gmac_rockchip.c |  3 +++
 7 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index ff7294ab4f4..2ca21c373db 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -210,15 +210,14 @@ static int dw_mdio_init(const char *name, void *priv)
        return mdio_register(bus);
 }
 
-static int dw_dm_mdio_init(const char *name, void *priv)
+int dw_dm_mdio_bind(struct udevice *dev)
 {
-       struct udevice *dev = priv;
+       struct udevice *mdiodev;
        ofnode node;
        int ret;
 
        ofnode_for_each_subnode(node, dev_ofnode(dev)) {
                const char *subnode_name = ofnode_get_name(node);
-               struct udevice *mdiodev;
 
                if (strcmp(subnode_name, "mdio"))
                        continue;
@@ -232,8 +231,10 @@ static int dw_dm_mdio_init(const char *name, void *priv)
        }
 
        printf("%s: mdio node is missing, registering legacy mdio bus", 
__func__);
-
-       return dw_mdio_init(name, priv);
+       ret = device_bind_driver(dev, "eth_designware_mdio", dev->name, 
&mdiodev);
+       if (ret)
+               debug("%s: not able to create mdio bus\n", __func__);
+       return ret;
 }
 
 #if IS_ENABLED(CONFIG_BITBANGMII) && IS_ENABLED(CONFIG_DM_GPIO)
@@ -855,6 +856,8 @@ static int designware_eth_bind(struct udevice *dev)
                }
        }
 
+       if (IS_ENABLED(CONFIG_DM_MDIO))
+               return dw_dm_mdio_bind(dev);
        return 0;
 }
 
@@ -962,16 +965,15 @@ int designware_eth_probe(struct udevice *dev)
        } else
 #endif
        {
-               if (IS_ENABLED(CONFIG_DM_MDIO))
-                       ret = dw_dm_mdio_init(dev->name, dev);
-               else
-                       ret = dw_mdio_init(dev->name, dev);
-               if (ret) {
-                       err = ret;
-                       goto mdio_err;
-               }
-               priv->bus = miiphy_get_dev_by_name(dev->name);
                priv->dev = dev;
+               if (!IS_ENABLED(CONFIG_DM_MDIO)) {
+                       ret = dw_mdio_init(dev->name, dev);
+                       if (ret) {
+                               err = ret;
+                               goto mdio_err;
+                       }
+                       priv->bus = miiphy_get_dev_by_name(dev->name);
+               }
        }
 
        ret = dw_phy_init(priv, dev);
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index cccf9d54e02..3618300f4c5 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -249,6 +249,7 @@ struct dw_eth_dev {
        struct mii_dev *bus;
 };
 
+int dw_dm_mdio_bind(struct udevice *dev);
 int designware_eth_of_to_plat(struct udevice *dev);
 int designware_eth_probe(struct udevice *dev);
 extern const struct eth_ops designware_eth_ops;
diff --git a/drivers/net/dwmac_meson8b.c b/drivers/net/dwmac_meson8b.c
index fde4aabbace..cb9de81a819 100644
--- a/drivers/net/dwmac_meson8b.c
+++ b/drivers/net/dwmac_meson8b.c
@@ -157,6 +157,9 @@ U_BOOT_DRIVER(dwmac_meson8b) = {
        .id             = UCLASS_ETH,
        .of_match       = dwmac_meson8b_ids,
        .of_to_plat = dwmac_meson8b_of_to_plat,
+#if IS_ENABLED(CONFIG_DM_MDIO)
+       .bind           = dw_dm_mdio_bind,
+#endif
        .probe          = dwmac_meson8b_probe,
        .ops            = &designware_eth_ops,
        .priv_auto      = sizeof(struct dw_eth_dev),
diff --git a/drivers/net/dwmac_s700.c b/drivers/net/dwmac_s700.c
index 76daab961c0..d95f2111a5b 100644
--- a/drivers/net/dwmac_s700.c
+++ b/drivers/net/dwmac_s700.c
@@ -56,6 +56,9 @@ U_BOOT_DRIVER(dwmac_s700) = {
        .id     = UCLASS_ETH,
        .of_match = dwmac_s700_ids,
        .of_to_plat = dwmac_s700_of_to_plat,
+#if IS_ENABLED(CONFIG_DM_MDIO)
+       .bind           = dw_dm_mdio_bind,
+#endif
        .probe  = dwmac_s700_probe,
        .ops    = &designware_eth_ops,
        .priv_auto      = sizeof(struct dw_eth_dev),
diff --git a/drivers/net/dwmac_socfpga.c b/drivers/net/dwmac_socfpga.c
index a55f3e29f9f..64bb2dbfbe3 100644
--- a/drivers/net/dwmac_socfpga.c
+++ b/drivers/net/dwmac_socfpga.c
@@ -143,6 +143,9 @@ U_BOOT_DRIVER(dwmac_socfpga) = {
        .id             = UCLASS_ETH,
        .of_match       = dwmac_socfpga_ids,
        .of_to_plat = dwmac_socfpga_of_to_plat,
+#if IS_ENABLED(CONFIG_DM_MDIO)
+       .bind           = dw_dm_mdio_bind,
+#endif
        .probe          = dwmac_socfpga_probe,
        .ops            = &designware_eth_ops,
        .priv_auto      = sizeof(struct dw_eth_dev),
diff --git a/drivers/net/dwmac_thead.c b/drivers/net/dwmac_thead.c
index 138d71a6202..5843bed49cb 100644
--- a/drivers/net/dwmac_thead.c
+++ b/drivers/net/dwmac_thead.c
@@ -280,6 +280,9 @@ U_BOOT_DRIVER(dwmac_thead) = {
        .id             = UCLASS_ETH,
        .of_match       = dwmac_thead_match,
        .of_to_plat     = dwmac_thead_of_to_plat,
+#if IS_ENABLED(CONFIG_DM_MDIO)
+       .bind           = dw_dm_mdio_bind,
+#endif
        .probe          = dwmac_thead_probe,
        .ops            = &dwmac_thead_eth_ops,
        .priv_auto      = sizeof(struct dw_eth_dev),
diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c
index 2b6080dd9ee..1d21cb2606d 100644
--- a/drivers/net/gmac_rockchip.c
+++ b/drivers/net/gmac_rockchip.c
@@ -790,6 +790,9 @@ U_BOOT_DRIVER(eth_gmac_rockchip) = {
        .id     = UCLASS_ETH,
        .of_match = rockchip_gmac_ids,
        .of_to_plat = gmac_rockchip_of_to_plat,
+#if IS_ENABLED(CONFIG_DM_MDIO)
+       .bind           = dw_dm_mdio_bind,
+#endif
        .probe  = gmac_rockchip_probe,
        .ops    = &gmac_rockchip_eth_ops,
        .priv_auto      = sizeof(struct dw_eth_dev),
-- 
2.53.0

Reply via email to