Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'phy-micrel-toggling-reset'

Yoshihiro Shimoda says:

====================
net: phy: micrel: add toggling phy reset

This patch set is for R-Car Gen3 Salvator-XS boards. If we do
the following method, the phy cannot link up correctly.

1) Kernel boots by using initramfs.
--> No open the nic, so phy_device_register() and phy_probe()
deasserts the reset.
2) Kernel enters the suspend.
--> So, keep the reset signal as deassert.
--> On R-Car Salvator-XS board, unfortunately, the board power is
turned off.
3) Kernel returns from suspend.
4) ifconfig eth0 up
--> Then, since edge signal of the reset doesn't happen,
it cannot link up.
5) ifconfig eth0 down
6) ifconfig eth0 up
--> In this case, it can link up.

When resolving this issue after I got feedback from Andrew and Heiner,
I found an issue that the phy_device.c didn't call phy_resume()
if the PHY was not attached. So, patch 1 fixes it and add toggling
the phy reset to the micrel phy driver.

Changes from v1 (as RFC):
- No remove the current code of phy_device.c to avoid any side effects.
- Fix the mdio_bus_phy_resume() in phy_device.c.
- Add toggling the phy reset in micrel.c if the PHY is not attached.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+14 -5
+8
drivers/net/phy/micrel.c
··· 23 23 * ksz9477 24 24 */ 25 25 26 + #include <linux/delay.h> 26 27 #include <linux/kernel.h> 27 28 #include <linux/module.h> 28 29 #include <linux/phy.h> ··· 835 834 static int kszphy_resume(struct phy_device *phydev) 836 835 { 837 836 int ret; 837 + 838 + if (!phydev->attached_dev) { 839 + /* If the PHY is not attached, toggle the reset */ 840 + phy_device_reset(phydev, 1); 841 + udelay(1); 842 + phy_device_reset(phydev, 0); 843 + } 838 844 839 845 genphy_resume(phydev); 840 846
+6 -5
drivers/net/phy/phy_device.c
··· 220 220 static DEFINE_MUTEX(phy_fixup_lock); 221 221 222 222 #ifdef CONFIG_PM 223 - static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) 223 + static bool mdio_bus_phy_may_suspend(struct phy_device *phydev, bool suspend) 224 224 { 225 225 struct device_driver *drv = phydev->mdio.dev.driver; 226 226 struct phy_driver *phydrv = to_phy_driver(drv); ··· 232 232 /* PHY not attached? May suspend if the PHY has not already been 233 233 * suspended as part of a prior call to phy_disconnect() -> 234 234 * phy_detach() -> phy_suspend() because the parent netdev might be the 235 - * MDIO bus driver and clock gated at this point. 235 + * MDIO bus driver and clock gated at this point. Also may resume if 236 + * PHY is not attached. 236 237 */ 237 238 if (!netdev) 238 - return !phydev->suspended; 239 + return suspend ? !phydev->suspended : phydev->suspended; 239 240 240 241 if (netdev->wol_enabled) 241 242 return false; ··· 271 270 if (phydev->attached_dev && phydev->adjust_link) 272 271 phy_stop_machine(phydev); 273 272 274 - if (!mdio_bus_phy_may_suspend(phydev)) 273 + if (!mdio_bus_phy_may_suspend(phydev, true)) 275 274 return 0; 276 275 277 276 return phy_suspend(phydev); ··· 282 281 struct phy_device *phydev = to_phy_device(dev); 283 282 int ret; 284 283 285 - if (!mdio_bus_phy_may_suspend(phydev)) 284 + if (!mdio_bus_phy_may_suspend(phydev, false)) 286 285 goto no_resume; 287 286 288 287 ret = phy_resume(phydev);