With CONFIG_DM_ETH_PHY, priv->bus may come from eth_phy_get_mdio_bus(), in which case it belongs to another controller. zynq_gem_remove() and the probe error path nevertheless unregister it, and remove() also frees it, pulling the bus out from under its owner.
The same applies to priv->phydev: phy_connect() caches PHY devices in the bus's phymap[] and hands out the cached pointer, so on a shared bus the phy_device belongs to the bus owner (and may even be the owner's own PHY). Freeing it in remove() leaves the owner with a dangling pointer. Track whether the bus was allocated by this instance and only release the bus and phy_device in that case. Signed-off-by: Graeme Smecher <[email protected]> --- drivers/net/zynq_gem.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 957d5251cb8af15899648e7e61d53205d35f3db6..d28b97d01d08da50049280fe2f75277506a4b740 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -257,6 +257,7 @@ struct zynq_gem_priv { struct phy_device *phydev; ofnode phy_of_node; struct mii_dev *bus; + bool own_bus; struct clk rx_clk; struct clk tx_clk; struct clk pclk; @@ -998,6 +999,7 @@ static int zynq_gem_probe(struct udevice *dev) if (!priv->bus) { priv->bus = mdio_alloc(); + priv->own_bus = true; priv->bus->read = zynq_gem_miiphy_read; priv->bus->write = zynq_gem_miiphy_write; priv->bus->priv = priv; @@ -1040,7 +1042,8 @@ static int zynq_gem_probe(struct udevice *dev) return ret; err3: - mdio_unregister(priv->bus); + if (priv->own_bus) + mdio_unregister(priv->bus); err2: free(priv->tx_bd); err1: @@ -1052,9 +1055,11 @@ static int zynq_gem_remove(struct udevice *dev) { struct zynq_gem_priv *priv = dev_get_priv(dev); - free(priv->phydev); - mdio_unregister(priv->bus); - mdio_free(priv->bus); + if (priv->own_bus) { + free(priv->phydev); + mdio_unregister(priv->bus); + mdio_free(priv->bus); + } return 0; } -- 2.47.3
