diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 69b04a92b776..41d1b20cde2c 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1766,11 +1766,12 @@ static bool phy_drv_supports_irq(const struct phy_driver *phydrv) /** * phy_detach_internal - detach a PHY device from its network device * @phydev: target phy_device struct + * @notify_bus: whether to notify the MDIO bus about the PHY detach * * This detaches the phy device from its network device and the phy * driver, and drops the reference count taken in phy_attach_direct(). */ -static void phy_detach_internal(struct phy_device *phydev) +static void phy_detach_internal(struct phy_device *phydev, bool notify_bus) { struct net_device *dev = phydev->attached_dev; struct module *ndev_owner = NULL; @@ -1792,6 +1793,10 @@ static void phy_detach_internal(struct phy_device *phydev) &dev_attr_phy_standalone.attr); phy_suspend(phydev); + + if (notify_bus && phydev->mdio.bus->notify_phy_detach) + phydev->mdio.bus->notify_phy_detach(phydev); + if (dev) { struct hwtstamp_provider *hwprov; @@ -1851,7 +1856,8 @@ static void phy_detach_internal(struct phy_device *phydev) */ void phy_detach(struct phy_device *phydev) { - phy_detach_internal(phydev); + /* cleanup including bus notification */ + phy_detach_internal(phydev, true); } EXPORT_SYMBOL(phy_detach); @@ -1997,6 +2003,12 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, if (err) goto error; + if (phydev->mdio.bus->notify_phy_attach) { + err = phydev->mdio.bus->notify_phy_attach(phydev); + if (err) + goto error; + } + phy_resume(phydev); /** @@ -2011,8 +2023,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_internal() does all of the cleanup below */ + phy_detach_internal(phydev, false); return err; error_module_put: diff --git a/include/linux/phy.h b/include/linux/phy.h index 5f8d65868e0f..3d8afe6b7f1c 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -376,6 +376,24 @@ struct mii_bus { int regnum, u16 val); /** @reset: Perform a reset of the bus */ int (*reset)(struct mii_bus *bus); + /** + * @notify_phy_attach: Perform post-attach handling for MDIO bus + * drivers. Optional and independent of @notify_phy_detach. Called + * in phy_attach_direct() right before phy_resume(). Runs in process + * context, may sleep and may be called with RTNL held. Must not + * acquire or rely on RTNL. Returns 0 on success or negative errno + * on failure. Must unwind its own state on error as attachment is + * aborted. + */ + int (*notify_phy_attach)(struct phy_device *phydev); + /** + * @notify_phy_detach: Perform pre-detach handling for MDIO bus + * drivers. Optional and independent of @notify_phy_attach. Called + * in phy_detach() right after phy_suspend(). Runs in process context, + * may sleep and may be called with RTNL held. Must not acquire or + * rely on RTNL. + */ + void (*notify_phy_detach)(struct phy_device *phydev); /** @stats: Statistic counters per device on the bus */ struct mdio_bus_stats stats[PHY_MAX_ADDR];