Share the mii_bus for others MAC device because EMAC include MDIO, and the motherboard has more than one PHY connected to an MDIO bus.
Signed-off-by: Wang Dongsheng <dongsheng.w...@hxt-semitech.com> --- drivers/net/ethernet/qualcomm/emac/emac-phy.c | 63 ++++++++++++++++++- drivers/net/ethernet/qualcomm/emac/emac.c | 8 ++- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/emac/emac-phy.c b/drivers/net/ethernet/qualcomm/emac/emac-phy.c index 2d16c6b9ef49..4f98f9a0ed54 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-phy.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-phy.c @@ -13,6 +13,7 @@ /* Qualcomm Technologies, Inc. EMAC PHY Controller driver. */ +#include <linux/of_platform.h> #include <linux/of_mdio.h> #include <linux/phy.h> #include <linux/iopoll.h> @@ -96,8 +97,51 @@ static int emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) return 0; } -static int emac_mdio_bus_create(struct platform_device *pdev, - struct emac_adapter *adpt) +static int emac_of_get_shared_bus(struct platform_device *pdev, + struct mii_bus **bus) +{ + struct device_node *shared_node; + struct platform_device *shared_pdev; + struct net_device *shared_netdev; + struct emac_adapter *shared_adpt; + struct device_node *np = pdev->dev.of_node; + + const phandle *prop; + + prop = of_get_property(np, "mdio-device", NULL); + if (!prop) { + dev_err(&pdev->dev, "Missing mdio-device property\n"); + return -ENODEV; + } + + shared_node = of_find_node_by_phandle(*prop); + if (!shared_node) + return -ENODEV; + + shared_pdev = of_find_device_by_node(shared_node); + if (!shared_pdev) + return -ENODEV; + + shared_netdev = dev_get_drvdata(&shared_pdev->dev); + if (!shared_netdev) + return -EPROBE_DEFER; + + shared_adpt = netdev_priv(shared_netdev); + if (!shared_adpt->mii_bus) + return -EPROBE_DEFER; + + *bus = shared_adpt->mii_bus; + return 0; +} + +static int __do_get_emac_mido_shared_bus(struct platform_device *pdev, + struct emac_adapter *adpt) +{ + return emac_of_get_shared_bus(pdev, &adpt->mii_bus); +} + +static int __do_emac_mido_bus_create(struct platform_device *pdev, + struct emac_adapter *adpt) { struct device_node *np = pdev->dev.of_node; struct mii_bus *mii_bus; @@ -125,6 +169,17 @@ static int emac_mdio_bus_create(struct platform_device *pdev, return 0; } +static int emac_mdio_bus_create(struct platform_device *pdev, + struct emac_adapter *adpt) +{ + bool shared_mdio; + + shared_mdio = device_property_read_bool(&pdev->dev, "mdio-device"); + if (shared_mdio) + return __do_get_emac_mido_shared_bus(pdev, adpt); + return __do_emac_mido_bus_create(pdev, adpt); +} + static void emac_get_phydev(struct platform_device *pdev, struct emac_adapter *adpt) { @@ -174,6 +229,8 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt) return 0; dev_err(&pdev->dev, "Could not find external phy\n"); - mdiobus_unregister(adpt->mii_bus); + /* Only the bus creator can unregister mdio bus */ + if (&pdev->dev == adpt->mii_bus->parent) + mdiobus_unregister(adpt->mii_bus); return -ENODEV; } diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index 2a0cbc535a2e..6e566b4c5a6b 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -727,7 +727,9 @@ static int emac_probe(struct platform_device *pdev) netif_napi_del(&adpt->rx_q.napi); err_undo_mdiobus: put_device(&adpt->phydev->mdio.dev); - mdiobus_unregister(adpt->mii_bus); + /* Only the bus creator can unregister mdio bus */ + if (&pdev->dev == adpt->mii_bus->parent) + mdiobus_unregister(adpt->mii_bus); err_undo_clocks: emac_clks_teardown(adpt); err_undo_netdev: @@ -747,7 +749,9 @@ static int emac_remove(struct platform_device *pdev) emac_clks_teardown(adpt); put_device(&adpt->phydev->mdio.dev); - mdiobus_unregister(adpt->mii_bus); + /* Only the bus creator can unregister mdio bus */ + if (&pdev->dev == adpt->mii_bus->parent) + mdiobus_unregister(adpt->mii_bus); free_netdev(netdev); if (adpt->phy.digital) -- 2.18.0