commit ba9cbad98a6e2ead1538b6287108597659d46a56 Author: Kory Maincent Date: Thu Mar 13 13:18:51 2025 +0100 net: Throw ASSERT_RTNL into phy_detach phy_detach needs the rtnl lock to be held. It should have been added before to avoid this massive change among lots of net drivers but there was no clear evidence of such needs at that time. This imply an lock change in this API. The adds of rtnl_dereference inside phy_detach comes from the support for select the hw timestamp: https://lore.kernel.org/all/20241212-feature_ptp_netnext-v21-3-2c282a941518@bootlin.com/ The hwtstamp support seems not the only feature that need rtnl to be held: https://lore.kernel.org/netdev/Z6OdkdI2ss19FyVT@shell.armlinux.org.uk/ Signed-off-by: Kory Maincent --- drivers/net/ethernet/actions/owl-emac.c | 4 +- drivers/net/ethernet/adi/adin1110.c | 2 +- drivers/net/ethernet/agere/et131x.c | 4 +- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 2 +- drivers/net/ethernet/apm/xgene-v2/mdio.c | 2 +- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 4 +- drivers/net/ethernet/arc/emac_main.c | 4 +- drivers/net/ethernet/asix/ax88796c_main.c | 4 +- drivers/net/ethernet/broadcom/b44.c | 2 +- drivers/net/ethernet/broadcom/bgmac.c | 8 +- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 7 +- drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 +- drivers/net/ethernet/broadcom/tg3.c | 4 +- drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 2 +- drivers/net/ethernet/cortina/gemini.c | 4 +- drivers/net/ethernet/davicom/dm9051.c | 4 +- drivers/net/ethernet/dnet.c | 2 +- drivers/net/ethernet/ethoc.c | 2 +- drivers/net/ethernet/faraday/ftgmac100.c | 8 +- drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 4 +- drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c | 6 +- drivers/net/ethernet/hisilicon/hip04_eth.c | 2 +- drivers/net/ethernet/hisilicon/hisi_femac.c | 4 +- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 2 +- .../ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c | 2 +- drivers/net/ethernet/lantiq_etop.c | 2 +- drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +- drivers/net/ethernet/marvell/pxa168_eth.c | 2 +- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c | 4 +- drivers/net/ethernet/oa_tc6.c | 2 +- drivers/net/ethernet/rdc/r6040.c | 8 +- drivers/net/ethernet/renesas/rswitch.c | 2 +- drivers/net/ethernet/renesas/rtsn.c | 2 +- drivers/net/ethernet/ti/icssg/icssg_prueth.c | 4 +- drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c | 4 +- drivers/net/ethernet/toshiba/tc35815.c | 2 +- drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 2 +- drivers/net/ethernet/xscale/ixp4xx_eth.c | 4 +- drivers/net/phy/phy_device.c | 40 +++++- drivers/net/phy/phylink.c | 148 +++++++++++++++++---- drivers/net/usb/asix_devices.c | 2 +- drivers/net/usb/ax88172a.c | 2 +- drivers/net/usb/lan78xx.c | 4 +- drivers/net/usb/smsc95xx.c | 2 +- include/linux/phy.h | 2 + include/linux/phylink.h | 4 + net/dsa/user.c | 2 +- 47 files changed, 239 insertions(+), 98 deletions(-) diff --git a/drivers/net/ethernet/actions/owl-emac.c b/drivers/net/ethernet/actions/owl-emac.c index 0a08da799255b..d2b564e51a4bd 100644 --- a/drivers/net/ethernet/actions/owl-emac.c +++ b/drivers/net/ethernet/actions/owl-emac.c @@ -1570,7 +1570,7 @@ static int owl_emac_probe(struct platform_device *pdev) ret = devm_register_netdev(dev, netdev); if (ret) { netif_napi_del(&priv->napi); - phy_disconnect(netdev->phydev); + phy_disconnect_unlock(netdev->phydev); return ret; } @@ -1582,7 +1582,7 @@ static void owl_emac_remove(struct platform_device *pdev) struct owl_emac_priv *priv = platform_get_drvdata(pdev); netif_napi_del(&priv->napi); - phy_disconnect(priv->netdev->phydev); + phy_disconnect_unlock(priv->netdev->phydev); cancel_work_sync(&priv->mac_reset_task); } diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index 30f9d271e5953..a10542ca5ab70 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -1224,7 +1224,7 @@ static struct notifier_block adin1110_netdevice_nb = { static void adin1110_disconnect_phy(void *data) { - phy_disconnect(data); + phy_disconnect_unlock(data); } static int adin1110_port_set_forwarding_state(struct adin1110_port_priv *port_priv) diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index b325e0cef120f..e3ac97b92374b 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -3293,7 +3293,7 @@ static void et131x_pci_remove(struct pci_dev *pdev) unregister_netdev(netdev); netif_napi_del(&adapter->napi); - phy_disconnect(netdev->phydev); + phy_disconnect_unlock(netdev->phydev); mdiobus_unregister(adapter->mii_bus); mdiobus_free(adapter->mii_bus); @@ -4027,7 +4027,7 @@ static int et131x_pci_setup(struct pci_dev *pdev, return rc; err_phy_disconnect: - phy_disconnect(netdev->phydev); + phy_disconnect_unlock(netdev->phydev); err_mdio_unregister: mdiobus_unregister(adapter->mii_bus); err_mdio_free: diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 268399dfcf22f..0d4ddd6ea1e04 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -914,7 +914,7 @@ static void xgbe_phy_free_phy_device(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; if (phy_data->phydev) { - phy_detach(phy_data->phydev); + phy_detach_unlock(phy_data->phydev); phy_device_remove(phy_data->phydev); phy_device_free(phy_data->phydev); phy_data->phydev = NULL; diff --git a/drivers/net/ethernet/apm/xgene-v2/mdio.c b/drivers/net/ethernet/apm/xgene-v2/mdio.c index 6a17045a5f626..4cf2179ee84de 100644 --- a/drivers/net/ethernet/apm/xgene-v2/mdio.c +++ b/drivers/net/ethernet/apm/xgene-v2/mdio.c @@ -87,7 +87,7 @@ void xge_mdio_remove(struct net_device *ndev) struct mii_bus *mdio_bus = pdata->mdio_bus; if (ndev->phydev) - phy_disconnect(ndev->phydev); + phy_disconnect_unlock(ndev->phydev); if (mdio_bus->state == MDIOBUS_REGISTERED) mdiobus_unregister(mdio_bus); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index b854b6b42d77b..24382cc07fbff 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -973,7 +973,7 @@ void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata) struct net_device *ndev = pdata->ndev; if (ndev->phydev) - phy_disconnect(ndev->phydev); + phy_disconnect_unlock(ndev->phydev); } void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) @@ -981,7 +981,7 @@ void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) struct net_device *ndev = pdata->ndev; if (ndev->phydev) - phy_disconnect(ndev->phydev); + phy_disconnect_unlock(ndev->phydev); mdiobus_unregister(pdata->mdio_bus); mdiobus_free(pdata->mdio_bus); diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index 8283aeee35fb6..413673bb7545e 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -1000,7 +1000,7 @@ int arc_emac_probe(struct net_device *ndev, int interface) out_netif_api: netif_napi_del(&priv->napi); - phy_disconnect(phydev); + phy_disconnect_unlock(phydev); out_mdio: arc_mdio_remove(priv); out_clken: @@ -1017,7 +1017,7 @@ void arc_emac_remove(struct net_device *ndev) { struct arc_emac_priv *priv = netdev_priv(ndev); - phy_disconnect(ndev->phydev); + phy_disconnect_unlock(ndev->phydev); arc_mdio_remove(priv); unregister_netdev(ndev); netif_napi_del(&priv->napi); diff --git a/drivers/net/ethernet/asix/ax88796c_main.c b/drivers/net/ethernet/asix/ax88796c_main.c index 11e8996b33d77..e4490966024ab 100644 --- a/drivers/net/ethernet/asix/ax88796c_main.c +++ b/drivers/net/ethernet/asix/ax88796c_main.c @@ -1097,7 +1097,7 @@ static int ax88796c_probe(struct spi_device *spi) return 0; err_phy_dis: - phy_disconnect(ax_local->phydev); + phy_disconnect_unlock(ax_local->phydev); err: return ret; } @@ -1107,7 +1107,7 @@ static void ax88796c_remove(struct spi_device *spi) struct ax88796c_device *ax_local = dev_get_drvdata(&spi->dev); struct net_device *ndev = ax_local->ndev; - phy_disconnect(ndev->phydev); + phy_disconnect_unlock(ndev->phydev); netif_info(ax_local, probe, ndev, "removing network device %s %s\n", dev_driver_string(&spi->dev), diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index e5809ad5eb827..3dc740b242538 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -2314,7 +2314,7 @@ static void b44_unregister_phy_one(struct b44 *bp) struct net_device *dev = bp->dev; struct mii_bus *mii_bus = bp->mii_bus; - phy_disconnect(dev->phydev); + phy_disconnect_unlock(dev->phydev); mdiobus_unregister(mii_bus); mdiobus_free(mii_bus); } diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index a461ec612e952..82f931f304c9b 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1548,15 +1548,15 @@ int bgmac_enet_probe(struct bgmac *bgmac) err = register_netdev(bgmac->net_dev); if (err) { dev_err(bgmac->dev, "Cannot register net device\n"); - goto err_phy_disconnect; + goto err_phy_disconnect_unlock; } netif_carrier_off(net_dev); return 0; -err_phy_disconnect: - phy_disconnect(net_dev->phydev); +err_phy_disconnect_unlock: + phy_disconnect_unlock(net_dev->phydev); err_dma_free: bgmac_dma_free(bgmac); err_out: @@ -1568,7 +1568,7 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe); void bgmac_enet_remove(struct bgmac *bgmac) { unregister_netdev(bgmac->net_dev); - phy_disconnect(bgmac->net_dev->phydev); + phy_disconnect_unlock(bgmac->net_dev->phydev); netif_napi_del(&bgmac->napi); bgmac_dma_free(bgmac); } diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 73d78dcb774d9..8cd426da3447c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -4143,8 +4143,11 @@ static int bcmgenet_resume(struct device *d) return 0; out_clk_disable: - if (priv->internal_phy) + if (priv->internal_phy) { + rtnl_lock(); bcmgenet_power_down(priv, GENET_POWER_PASSIVE); + rtnl_unlock(); + } clk_disable_unprepare(priv->clk); return ret; } @@ -4212,11 +4215,13 @@ static int bcmgenet_suspend_noirq(struct device *d) if (!netif_running(dev)) return 0; + rtnl_lock(); /* Prepare the device for Wake-on-LAN and switch to the slow clock */ if (device_may_wakeup(d) && priv->wolopts) ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); else if (priv->internal_phy) ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); + rtnl_unlock(); /* Let the framework handle resumption and leave the clocks on */ if (ret) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 71c619d2bea5f..9e647edb9ab37 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -392,7 +392,7 @@ int bcmgenet_mii_probe(struct net_device *dev) */ ret = bcmgenet_mii_config(dev, true); if (ret) { - phy_disconnect(dev->phydev); + phy_disconnect_unlock(dev->phydev); return ret; } diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index d9d675f1ebfe9..826a3ac3036e0 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2116,7 +2116,7 @@ static int tg3_phy_init(struct tg3 *tp) phy_support_asym_pause(phydev); break; default: - phy_disconnect(mdiobus_get_phy(tp->mdio_bus, tp->phy_addr)); + phy_disconnect_unlock(mdiobus_get_phy(tp->mdio_bus, tp->phy_addr)); return -EINVAL; } @@ -2161,7 +2161,7 @@ static void tg3_phy_stop(struct tg3 *tp) static void tg3_phy_fini(struct tg3 *tp) { if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) { - phy_disconnect(mdiobus_get_phy(tp->mdio_bus, tp->phy_addr)); + phy_disconnect_unlock(mdiobus_get_phy(tp->mdio_bus, tp->phy_addr)); tp->phy_flags &= ~TG3_PHYFLG_IS_CONNECTED; } } diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 608cc6af5af1c..909f2ba442827 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -1183,7 +1183,7 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid) (lmac->lmac_type != BGX_MODE_XLAUI) && (lmac->lmac_type != BGX_MODE_40G_KR) && (lmac->lmac_type != BGX_MODE_10G_KR) && lmac->phydev) - phy_disconnect(lmac->phydev); + phy_disconnect_unlock(lmac->phydev); lmac->phydev = NULL; } diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index 1f8067bdd61a6..2bbbd72640071 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -393,7 +393,7 @@ static int gmac_setup_phy(struct net_device *netdev) break; default: netdev_err(netdev, "Unsupported MII interface\n"); - phy_disconnect(phy); + phy_disconnect_unlock(phy); netdev->phydev = NULL; return -EINVAL; } @@ -2324,7 +2324,7 @@ static irqreturn_t gemini_port_irq(int irq, void *data) static void gemini_port_remove(struct gemini_ethernet_port *port) { if (port->netdev) { - phy_disconnect(port->netdev->phydev); + phy_disconnect_unlock(port->netdev->phydev); unregister_netdev(port->netdev); } clk_disable_unprepare(port->pclk); diff --git a/drivers/net/ethernet/davicom/dm9051.c b/drivers/net/ethernet/davicom/dm9051.c index 59ea48d4c9ded..50bfac05fd7fe 100644 --- a/drivers/net/ethernet/davicom/dm9051.c +++ b/drivers/net/ethernet/davicom/dm9051.c @@ -1215,7 +1215,7 @@ static int dm9051_probe(struct spi_device *spi) ret = devm_register_netdev(dev, ndev); if (ret) { - phy_disconnect(db->phydev); + phy_disconnect_unlock(db->phydev); return dev_err_probe(dev, ret, "device register failed"); } @@ -1228,7 +1228,7 @@ static void dm9051_drv_remove(struct spi_device *spi) struct net_device *ndev = dev_get_drvdata(dev); struct board_info *db = to_dm9051_board(ndev); - phy_disconnect(db->phydev); + phy_disconnect_unlock(db->phydev); } static const struct of_device_id dm9051_match_table[] = { diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index 0de3cd660ec80..3cf0aa80d0ee3 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -852,7 +852,7 @@ static void dnet_remove(struct platform_device *pdev) if (dev) { bp = netdev_priv(dev); if (dev->phydev) - phy_disconnect(dev->phydev); + phy_disconnect_unlock(dev->phydev); mdiobus_unregister(bp->mii_bus); mdiobus_free(bp->mii_bus); unregister_netdev(dev); diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 0c418557264c2..0a51d657b90f8 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1261,7 +1261,7 @@ static void ethoc_remove(struct platform_device *pdev) if (netdev) { netif_napi_del(&priv->napi); - phy_disconnect(netdev->phydev); + phy_disconnect_unlock(netdev->phydev); if (priv->mdio) { mdiobus_unregister(priv->mdio); diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 17ec35e75a656..c570e25a883c7 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -1727,14 +1727,14 @@ static int ftgmac100_setup_mdio(struct net_device *netdev) return err; } -static void ftgmac100_phy_disconnect(struct net_device *netdev) +static void ftgmac100_phy_disconnect_unlock(struct net_device *netdev) { struct ftgmac100 *priv = netdev_priv(netdev); if (!netdev->phydev) return; - phy_disconnect(netdev->phydev); + phy_disconnect_unlock(netdev->phydev); if (of_phy_is_fixed_link(priv->dev->of_node)) of_phy_deregister_fixed_link(priv->dev->of_node); @@ -2018,7 +2018,7 @@ static int ftgmac100_probe(struct platform_device *pdev) clk_disable_unprepare(priv->rclk); clk_disable_unprepare(priv->clk); err_phy_connect: - ftgmac100_phy_disconnect(netdev); + ftgmac100_phy_disconnect_unlock(netdev); err_ncsi_dev: if (priv->ndev) ncsi_unregister_dev(priv->ndev); @@ -2053,7 +2053,7 @@ static void ftgmac100_remove(struct platform_device *pdev) */ cancel_work_sync(&priv->reset_task); - ftgmac100_phy_disconnect(netdev); + ftgmac100_phy_disconnect_unlock(netdev); ftgmac100_destroy_mdio(netdev); iounmap(priv->base); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index 422ce13a7c949..f22469658fcd1 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -434,10 +434,10 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac) mac->phylink = phylink; rtnl_lock(); - err = phylink_fwnode_phy_connect(mac->phylink, dpmac_node, 0); + err = phylink_fwnode_phy_connect_unlock(mac->phylink, dpmac_node, 0); rtnl_unlock(); if (err) { - netdev_err(net_dev, "phylink_fwnode_phy_connect() = %d\n", err); + netdev_err(net_dev, "phylink_fwnode_phy_connect_unlock() = %d\n", err); goto err_phylink_destroy; } diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c index f29a937ad0879..19975fca9b88b 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c @@ -183,9 +183,9 @@ static void hbg_phy_adjust_link(struct net_device *netdev) } } -static void hbg_phy_disconnect(void *data) +static void hbg_phy_disconnect_unlock(void *data) { - phy_disconnect((struct phy_device *)data); + phy_disconnect_unlock((struct phy_device *)data); } static int hbg_phy_connect(struct hbg_priv *priv) @@ -199,7 +199,7 @@ static int hbg_phy_connect(struct hbg_priv *priv) if (ret) return dev_err_probe(dev, ret, "failed to connect phy\n"); - ret = devm_add_action_or_reset(dev, hbg_phy_disconnect, phydev); + ret = devm_add_action_or_reset(dev, hbg_phy_disconnect_unlock, phydev); if (ret) return ret; diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index a376d4bdf2819..ae7a6b9bd040f 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -1029,7 +1029,7 @@ static void hip04_remove(struct platform_device *pdev) struct device *d = &pdev->dev; if (priv->phy) - phy_disconnect(priv->phy); + phy_disconnect_unlock(priv->phy); hip04_free_ring(ndev, d); unregister_netdev(ndev); diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c index d244a40df4309..e246497d080ae 100644 --- a/drivers/net/ethernet/hisilicon/hisi_femac.c +++ b/drivers/net/ethernet/hisilicon/hisi_femac.c @@ -884,7 +884,7 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) out_disconnect_phy: netif_napi_del(&priv->napi); - phy_disconnect(phy); + phy_disconnect_unlock(phy); out_disable_clk: clk_disable_unprepare(priv->clk); out_free_netdev: @@ -901,7 +901,7 @@ static void hisi_femac_drv_remove(struct platform_device *pdev) netif_napi_del(&priv->napi); unregister_netdev(ndev); - phy_disconnect(ndev->phydev); + phy_disconnect_unlock(ndev->phydev); clk_disable_unprepare(priv->clk); free_netdev(ndev); } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 42bb341fd80b7..fd71a6bf281f7 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -2406,7 +2406,7 @@ static void hns_nic_dev_remove(struct platform_device *pdev) priv->ring_data = NULL; if (ndev->phydev) - phy_disconnect(ndev->phydev); + phy_disconnect_unlock(ndev->phydev); if (!IS_ERR_OR_NULL(priv->ae_handle)) hnae_put_handle(priv->ae_handle); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c index 9a456ebf9b7cd..8f43b2753ab7b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c @@ -248,7 +248,7 @@ void hclge_mac_disconnect_phy(struct hnae3_handle *handle) if (!phydev) return; - phy_disconnect(phydev); + phy_disconnect_unlock(phydev); } void hclge_mac_start_phy(struct hclge_dev *hdev) diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 83ce3bfefa5c2..6e67cedc8d3df 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -424,7 +424,7 @@ ltq_etop_mdio_cleanup(struct net_device *dev) { struct ltq_etop_priv *priv = netdev_priv(dev); - phy_disconnect(dev->phydev); + phy_disconnect_unlock(dev->phydev); mdiobus_unregister(priv->mii_bus); mdiobus_free(priv->mii_bus); } diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 67a6ff07c83d8..5a68f329c91de 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -3276,7 +3276,7 @@ static void mv643xx_eth_remove(struct platform_device *pdev) unregister_netdev(mp->dev); if (dev->phydev) - phy_disconnect(dev->phydev); + phy_disconnect_unlock(dev->phydev); cancel_work_sync(&mp->tx_timeout_task); if (!IS_ERR(mp->clk)) diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 2bf426cea6ddc..581728242e02c 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -1535,7 +1535,7 @@ static void pxa168_eth_remove(struct platform_device *pdev) pep->htpr = NULL; } if (dev->phydev) - phy_disconnect(dev->phydev); + phy_disconnect_unlock(dev->phydev); mdiobus_unregister(pep->smi_bus); mdiobus_free(pep->smi_bus); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index fb2e5b844c150..94b8422d1b9ea 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -478,7 +478,7 @@ static int mlxbf_gige_probe(struct platform_device *pdev) err = register_netdev(netdev); if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); - phy_disconnect(phydev); + phy_disconnect_unlock(phydev); goto out; } @@ -494,7 +494,7 @@ static void mlxbf_gige_remove(struct platform_device *pdev) struct mlxbf_gige *priv = platform_get_drvdata(pdev); unregister_netdev(priv->netdev); - phy_disconnect(priv->netdev->phydev); + phy_disconnect_unlock(priv->netdev->phydev); mlxbf_gige_mdio_remove(priv); platform_set_drvdata(pdev, NULL); } diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index db200e4ec284d..b7118851bbaa1 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -579,7 +579,7 @@ static int oa_tc6_phy_init(struct oa_tc6 *tc6) static void oa_tc6_phy_exit(struct oa_tc6 *tc6) { - phy_disconnect(tc6->phydev); + phy_disconnect_unlock(tc6->phydev); oa_tc6_mdiobus_unregister(tc6); } diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c index f4d434c379e7c..4b1fbe008f5ae 100644 --- a/drivers/net/ethernet/rdc/r6040.c +++ b/drivers/net/ethernet/rdc/r6040.c @@ -1159,12 +1159,12 @@ static int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) err = register_netdev(dev); if (err) { dev_err(&pdev->dev, "Failed to register net device\n"); - goto err_out_phy_disconnect; + goto err_out_phy_disconnect_unlock; } return 0; -err_out_phy_disconnect: - phy_disconnect(dev->phydev); +err_out_phy_disconnect_unlock: + phy_disconnect_unlock(dev->phydev); err_out_mdio_unregister: mdiobus_unregister(lp->mii_bus); err_out_mdio: @@ -1188,7 +1188,7 @@ static void r6040_remove_one(struct pci_dev *pdev) struct r6040_private *lp = netdev_priv(dev); unregister_netdev(dev); - phy_disconnect(dev->phydev); + phy_disconnect_unlock(dev->phydev); mdiobus_unregister(lp->mii_bus); mdiobus_free(lp->mii_bus); netif_napi_del(&lp->napi); diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index aba772e14555d..f25f2da8e9632 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1478,7 +1478,7 @@ static int rswitch_phy_device_init(struct rswitch_device *rdev) static void rswitch_phy_device_deinit(struct rswitch_device *rdev) { if (rdev->ndev->phydev) - phy_disconnect(rdev->ndev->phydev); + phy_disconnect_unlock(rdev->ndev->phydev); } static int rswitch_serdes_set_params(struct rswitch_device *rdev) diff --git a/drivers/net/ethernet/renesas/rtsn.c b/drivers/net/ethernet/renesas/rtsn.c index 6b3f7fca8d157..d5086e95c6cd1 100644 --- a/drivers/net/ethernet/renesas/rtsn.c +++ b/drivers/net/ethernet/renesas/rtsn.c @@ -930,7 +930,7 @@ static int rtsn_phy_init(struct rtsn_private *priv) static void rtsn_phy_deinit(struct rtsn_private *priv) { - phy_disconnect(priv->ndev->phydev); + phy_disconnect_unlock(priv->ndev->phydev); priv->ndev->phydev = NULL; } diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c index 742f9803026a2..5b55a49615538 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c @@ -1894,7 +1894,7 @@ static int prueth_probe(struct platform_device *pdev) if (!prueth->registered_netdevs[i]) continue; if (prueth->emac[i]->ndev->phydev) { - phy_disconnect(prueth->emac[i]->ndev->phydev); + phy_disconnect_unlock_unlock(prueth->emac[i]->ndev->phydev); prueth->emac[i]->ndev->phydev = NULL; } unregister_netdev(prueth->registered_netdevs[i]); @@ -1953,7 +1953,7 @@ static void prueth_remove(struct platform_device *pdev) if (!prueth->registered_netdevs[i]) continue; phy_stop(prueth->emac[i]->ndev->phydev); - phy_disconnect(prueth->emac[i]->ndev->phydev); + phy_disconnect_unlock_unlock(prueth->emac[i]->ndev->phydev); prueth->emac[i]->ndev->phydev = NULL; unregister_netdev(prueth->registered_netdevs[i]); } diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c b/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c index ff5f41bf499e3..2408c2f7a04d4 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c @@ -1125,7 +1125,7 @@ static int prueth_probe(struct platform_device *pdev) continue; if (prueth->emac[i]->ndev->phydev) { - phy_disconnect(prueth->emac[i]->ndev->phydev); + phy_disconnect_unlock(prueth->emac[i]->ndev->phydev); prueth->emac[i]->ndev->phydev = NULL; } unregister_netdev(prueth->registered_netdevs[i]); @@ -1187,7 +1187,7 @@ static void prueth_remove(struct platform_device *pdev) if (!prueth->registered_netdevs[i]) continue; phy_stop(prueth->emac[i]->ndev->phydev); - phy_disconnect(prueth->emac[i]->ndev->phydev); + phy_disconnect_unlock(prueth->emac[i]->ndev->phydev); prueth->emac[i]->ndev->phydev = NULL; unregister_netdev(prueth->registered_netdevs[i]); } diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index 6e3758dfbdbd2..18a9c2cfd22f7 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -856,7 +856,7 @@ static void tc35815_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct tc35815_local *lp = netdev_priv(dev); - phy_disconnect(dev->phydev); + phy_disconnect_unlock(dev->phydev); mdiobus_unregister(lp->mii_bus); mdiobus_free(lp->mii_bus); unregister_netdev(dev); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 85f022ceef4fe..3fe6acb524c02 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -290,7 +290,7 @@ static int txgbe_phylink_init(struct txgbe *txgbe) if (wx->phydev) { int ret; - ret = phylink_connect_phy(phylink, wx->phydev); + ret = phylink_connect_phy_unlock(phylink, wx->phydev); if (ret) { phylink_destroy(phylink); return ret; diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index a2ab1c1508221..046fb7da37101 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -1586,7 +1586,7 @@ static int ixp4xx_eth_probe(struct platform_device *pdev) return 0; err_phy_dis: - phy_disconnect(phydev); + phy_disconnect_unlock(phydev); err_free_mem: npe_port_tab[NPE_ID(port->id)] = NULL; npe_release(port->npe); @@ -1600,7 +1600,7 @@ static void ixp4xx_eth_remove(struct platform_device *pdev) struct port *port = netdev_priv(ndev); unregister_netdev(ndev); - phy_disconnect(phydev); + phy_disconnect_unlock(phydev); ixp4xx_mdio_remove(); npe_port_tab[NPE_ID(port->id)] = NULL; npe_release(port->npe); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 675fbd2253787..fb49da8227e2d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1175,6 +1175,22 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); +/** + * phy_disconnect_unlock - disable interrupts, stop state machine, and detach a PHY + * device + * @phydev: target phy_device struct + * + * This is a wrapper around phy_disconnect that takes the rtnl semaphore. + */ +void phy_disconnect_unlock(struct phy_device *phydev) +{ + if (rtnl_lock_killable()) + return; + phy_disconnect(phydev); + rtnl_unlock(); +} +EXPORT_SYMBOL(phy_disconnect_unlock); + /** * phy_poll_reset - Safely wait until a PHY reset has properly completed * @phydev: The PHY device to poll @@ -1604,8 +1620,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, return err; error: - /* phy_detach() does all of the cleanup below */ - phy_detach(phydev); + /* phy_detach_unlock() does all of the cleanup below */ + phy_detach_unlock(phydev); return err; error_module_put: @@ -1700,6 +1716,8 @@ void phy_detach(struct phy_device *phydev) struct module *ndev_owner = NULL; struct mii_bus *bus; + ASSERT_RTNL(); + if (phydev->devlink) device_link_del(phydev->devlink); @@ -1762,6 +1780,24 @@ void phy_detach(struct phy_device *phydev) } EXPORT_SYMBOL(phy_detach); +/** + * phy_detach_unlock - detach a PHY device from its network device + * @phydev: target phy_device struct + * + * This detaches the phy device from its network device and the phy + * driver, and drops the reference count taken in phy_attach_direct(). + * + * This is a wrapper around phy_detach that takes the rtnl semaphore. + */ +void phy_detach_unlock(struct phy_device *phydev) +{ + if (rtnl_lock_killable()) + return; + phy_detach(phydev); + rtnl_unlock(); +} +EXPORT_SYMBOL(phy_detach_unlock); + int phy_suspend(struct phy_device *phydev) { struct net_device *netdev = phydev->attached_dev; diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 0f70a7f3dfccd..48515a71dc853 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2140,6 +2140,17 @@ static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, return phy_attach_direct(pl->netdev, phy, flags, interface); } +static int phylink_preconnect_phy(struct phylink *pl, struct phy_device *phy) +{ + /* Use PHY device/driver interface */ + if (pl->link_interface == PHY_INTERFACE_MODE_NA) { + pl->link_interface = phy->interface; + pl->link_config.interface = pl->link_interface; + } + + return phylink_attach_phy(pl, phy, pl->link_interface); +} + /** * phylink_connect_phy() - connect a PHY to the phylink instance * @pl: a pointer to a &struct phylink returned from phylink_create() @@ -2159,14 +2170,8 @@ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy) { int ret; - /* Use PHY device/driver interface */ - if (pl->link_interface == PHY_INTERFACE_MODE_NA) { - pl->link_interface = phy->interface; - pl->link_config.interface = pl->link_interface; - } - - ret = phylink_attach_phy(pl, phy, pl->link_interface); - if (ret < 0) + ret = phylink_preconnect_phy(pl, phy); + if (ret) return ret; ret = phylink_bringup_phy(pl, phy, pl->link_config.interface); @@ -2177,6 +2182,40 @@ int phylink_connect_phy(struct phylink *pl, struct phy_device *phy) } EXPORT_SYMBOL_GPL(phylink_connect_phy); +/** + * phylink_connect_phy_unlock() - connect a PHY to the phylink instance + * @pl: a pointer to a &struct phylink returned from phylink_create() + * @phy: a pointer to a &struct phy_device. + * + * Connect @phy to the phylink instance specified by @pl by calling + * phy_attach_direct(). Configure the @phy according to the MAC driver's + * capabilities, start the PHYLIB state machine and enable any interrupts + * that the PHY supports. + * + * This updates the phylink's ethtool supported and advertising link mode + * masks. + * + * This is a similar to phylink_connect_phy but is called without the hold + * of rtnlock. It then use phy_detach_unlock that takes the rtnl semaphore. + * + * Returns 0 on success or a negative errno. + */ +int phylink_connect_phy_unlock(struct phylink *pl, struct phy_device *phy) +{ + int ret; + + ret = phylink_preconnect_phy(pl, phy); + if (ret) + return ret; + + ret = phylink_bringup_phy(pl, phy, pl->link_config.interface); + if (ret) + phy_detach_unlock(phy); + + return ret; +} +EXPORT_SYMBOL_GPL(phylink_connect_phy_unlock); + /** * phylink_of_phy_connect() - connect the PHY specified in the DT mode. * @pl: a pointer to a &struct phylink returned from phylink_create() @@ -2196,20 +2235,10 @@ int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn, } EXPORT_SYMBOL_GPL(phylink_of_phy_connect); -/** - * phylink_fwnode_phy_connect() - connect the PHY specified in the fwnode. - * @pl: a pointer to a &struct phylink returned from phylink_create() - * @fwnode: a pointer to a &struct fwnode_handle. - * @flags: PHY-specific flags to communicate to the PHY device driver - * - * Connect the phy specified @fwnode to the phylink instance specified - * by @pl. - * - * Returns 0 on success or a negative errno. - */ -int phylink_fwnode_phy_connect(struct phylink *pl, - const struct fwnode_handle *fwnode, - u32 flags) +static struct phy_device * +phylink_fwnode_phy_preconnect(struct phylink *pl, + const struct fwnode_handle *fwnode, + u32 flags) { struct fwnode_handle *phy_fwnode; struct phy_device *phy_dev; @@ -2219,20 +2248,20 @@ int phylink_fwnode_phy_connect(struct phylink *pl, if (pl->cfg_link_an_mode == MLO_AN_FIXED || (pl->cfg_link_an_mode == MLO_AN_INBAND && phy_interface_mode_is_8023z(pl->link_interface))) - return 0; + return NULL; phy_fwnode = fwnode_get_phy_node(fwnode); if (IS_ERR(phy_fwnode)) { if (pl->cfg_link_an_mode == MLO_AN_PHY) - return -ENODEV; - return 0; + return ERR_PTR(-ENODEV); + return NULL; } phy_dev = fwnode_phy_find_device(phy_fwnode); /* We're done with the phy_node handle */ fwnode_handle_put(phy_fwnode); if (!phy_dev) - return -ENODEV; + return ERR_PTR(-ENODEV); /* Use PHY device/driver interface */ if (pl->link_interface == PHY_INTERFACE_MODE_NA) { @@ -2247,7 +2276,38 @@ int phylink_fwnode_phy_connect(struct phylink *pl, pl->link_interface); phy_device_free(phy_dev); if (ret) - return ret; + return ERR_PTR(ret); + + ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); + if (ret) { + phy_detach(phy_dev); + return ERR_PTR(ret); + } + + return phy_dev; +} + +/** + * phylink_fwnode_phy_connect() - connect the PHY specified in the fwnode. + * @pl: a pointer to a &struct phylink returned from phylink_create() + * @fwnode: a pointer to a &struct fwnode_handle. + * @flags: PHY-specific flags to communicate to the PHY device driver + * + * Connect the phy specified @fwnode to the phylink instance specified + * by @pl. + * + * Returns 0 on success or a negative errno. + */ +int phylink_fwnode_phy_connect(struct phylink *pl, + const struct fwnode_handle *fwnode, + u32 flags) +{ + struct phy_device *phy_dev; + int ret; + + phy_dev = phylink_fwnode_phy_preconnect(pl, fwnode, flags); + if (IS_ERR_OR_NULL(phy_dev)) + return PTR_ERR(phy_dev); ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); if (ret) @@ -2257,6 +2317,40 @@ int phylink_fwnode_phy_connect(struct phylink *pl, } EXPORT_SYMBOL_GPL(phylink_fwnode_phy_connect); +/** + * phylink_fwnode_phy_connect() - connect the PHY specified in the fwnode. + * @pl: a pointer to a &struct phylink returned from phylink_create() + * @fwnode: a pointer to a &struct fwnode_handle. + * @flags: PHY-specific flags to communicate to the PHY device driver + * + * Connect the phy specified @fwnode to the phylink instance specified + * by @pl. + * + * This is a similar to phylink_fwnode_phy_connect but is called without + * the hold of rtnlock. It then use phy_detach_unlock that takes the rtnl + * semaphore. + * + * Returns 0 on success or a negative errno. + */ +int phylink_fwnode_phy_connect_unlock(struct phylink *pl, + const struct fwnode_handle *fwnode, + u32 flags) +{ + struct phy_device *phy_dev; + int ret; + + phy_dev = phylink_fwnode_phy_preconnect(pl, fwnode, flags); + if (IS_ERR_OR_NULL(phy_dev)) + return PTR_ERR(phy_dev); + + ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); + if (ret) + phy_detach_unlock(phy_dev); + + return ret; +} +EXPORT_SYMBOL_GPL(phylink_fwnode_phy_connect_unlock); + /** * phylink_disconnect_phy() - disconnect any PHY attached to the phylink * instance. diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index da24941a6e444..3104b34ab1e7c 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -707,7 +707,7 @@ static int ax88772_init_phy(struct usbnet *dev) return -ENODEV; } - ret = phylink_connect_phy(priv->phylink, priv->phydev); + ret = phylink_connect_phy_unlock(priv->phylink, priv->phydev); if (ret) { netdev_err(dev->net, "Could not connect PHY\n"); return ret; diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index e47bb125048d4..f79a0d24b379e 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c @@ -244,7 +244,7 @@ static int ax88172a_stop(struct usbnet *dev) netdev_info(dev->net, "Disconnecting from phy %s\n", priv->phy_name); phy_stop(priv->phydev); - phy_disconnect(priv->phydev); + phy_disconnect_unlock(priv->phydev); } return 0; diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 137adf6d5b08a..326791e3447d9 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -4357,7 +4357,7 @@ static void lan78xx_disconnect(struct usb_interface *intf) phydev = net->phydev; - phy_disconnect(net->phydev); + phy_disconnect_unlock(net->phydev); if (phy_is_pseudo_fixed_link(phydev)) { fixed_phy_unregister(phydev); @@ -4581,7 +4581,7 @@ static int lan78xx_probe(struct usb_interface *intf, return 0; out8: - phy_disconnect(netdev->phydev); + phy_disconnect_unlock(netdev->phydev); free_urbs: usb_free_urb(dev->urb_intr); out5: diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 8e82184be5e7d..caec6775bcc6b 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1263,7 +1263,7 @@ static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf) { struct smsc95xx_priv *pdata = dev->driver_priv; - phy_disconnect(dev->net->phydev); + phy_disconnect_unlock(dev->net->phydev); mdiobus_unregister(pdata->mdiobus); mdiobus_free(pdata->mdiobus); irq_dispose_mapping(irq_find_mapping(pdata->irqdomain, PHY_HWIRQ)); diff --git a/include/linux/phy.h b/include/linux/phy.h index 60d3b8860ea26..5a3555770227b 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1827,7 +1827,9 @@ struct phy_device *phy_connect(struct net_device *dev, const char *bus_id, void (*handler)(struct net_device *), phy_interface_t interface); void phy_disconnect(struct phy_device *phydev); +void phy_disconnect_unlock(struct phy_device *phydev); void phy_detach(struct phy_device *phydev); +void phy_detach_unlock(struct phy_device *phydev); void phy_start(struct phy_device *phydev); void phy_stop(struct phy_device *phydev); int phy_config_aneg(struct phy_device *phydev); diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 79876c84ae814..c70233d131012 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -690,10 +690,14 @@ void phylink_destroy(struct phylink *); bool phylink_expects_phy(struct phylink *pl); int phylink_connect_phy(struct phylink *, struct phy_device *); +int phylink_connect_phy_unlock(struct phylink *, struct phy_device *); int phylink_of_phy_connect(struct phylink *, struct device_node *, u32 flags); int phylink_fwnode_phy_connect(struct phylink *pl, const struct fwnode_handle *fwnode, u32 flags); +int phylink_fwnode_phy_connect_unlock(struct phylink *pl, + const struct fwnode_handle *fwnode, + u32 flags); void phylink_disconnect_phy(struct phylink *); int phylink_set_fixed_link(struct phylink *, const struct phylink_link_state *); diff --git a/net/dsa/user.c b/net/dsa/user.c index 804dc7dac4f2f..47b79010bbfea 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -2637,7 +2637,7 @@ static int dsa_user_phy_connect(struct net_device *user_dev, int addr, user_dev->phydev->dev_flags |= flags; - return phylink_connect_phy(dp->pl, user_dev->phydev); + return phylink_connect_phy_unlock(dp->pl, user_dev->phydev); } static int dsa_user_phy_setup(struct net_device *user_dev)