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