>From 8e687ddb949214d5f9cb581db7d0246af3556a54 Mon Sep 17 00:00:00 2001 From: Lauri Jakku Date: Sun, 17 May 2020 15:04:51 +0300 Subject: [PATCH] net: ethernet: realtek: r8168 / r8169 driver fix. There is issue with tp->phydev->drv: It never gets non-null value while driver is probed first time -> modify the driver check to trust MAC information fetched from HW. Something does not run/register PHY interface properly -> the attachment is done way later -> driver does not work properly. Function phy_probe is not called in first module loading. Line from drivers/net/phy/phy_device.c witch is not executed when loading first time: -------------------- static int phy_probe(struct device *dev) { struct phy_device *phydev = to_phy_device(dev); struct device_driver *drv = phydev->mdio.dev.driver; struct phy_driver *phydrv = to_phy_driver(drv); int err = 0; phydev->drv = phydrv; <--- This is never done in probe of r8169_main.c ------------------- That line is not executed when driver is loaded with modprobe, but when load->remove->reload cycle is done, it is ok. --- drivers/net/ethernet/realtek/r8169_main.c | 20 +++--- drivers/net/phy/phy-core.c | 76 ++++++++++++++++++++++- drivers/net/phy/phy_device.c | 4 +- 3 files changed, 89 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index bf5bf05970a2..1ad5fb591621 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5172,15 +5172,19 @@ static int r8169_mdio_register(struct rtl8169_private *tp) if (!tp->phydev) { mdiobus_unregister(new_bus); return -ENODEV; - } else if (!tp->phydev->drv) { - /* Most chip versions fail with the genphy driver. - * Therefore ensure that the dedicated PHY driver is loaded. - */ - dev_err(&pdev->dev, "realtek.ko not loaded, maybe it needs to be added to initramfs?\n"); - mdiobus_unregister(new_bus); - return -EUNATCH; + } else { + dev_info(&pdev->dev, "PHY version: 0x%x\n", tp->phydev->phy_id); + dev_info(&pdev->dev, "MAC version: %d\n", tp->mac_version); + + if (tp->mac_version == RTL_GIGA_MAC_NONE) { + /* Most chip versions fail with the genphy driver. + * Therefore ensure that the dedicated PHY driver is loaded. + */ + dev_err(&pdev->dev, "Not known MAC/PHY version.\n", tp->phydev->phy_id); + mdiobus_unregister(new_bus); + return -EUNATCH; + } } - /* PHY will be woken up in rtl_open() */ phy_suspend(tp->phydev); diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 66b8c61ca74c..809ad2f943d3 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -151,6 +151,18 @@ static const struct phy_setting settings[] = { }; #undef PHY_SETTING +#define PHY_NOT_ATTACHED_CHECK \ + { \ + void *attached_dev_ptr = (phydev) ? phydev->attached_dev : NULL; \ + if (! ( \ + (attached_dev_ptr) && \ + (phydev->state >= PHY_READY) \ + ) \ + ) \ + return -EOPNOTSUPP; \ + }; + + /** * phy_lookup_setting - lookup a PHY setting * @speed: speed to match @@ -457,6 +469,9 @@ int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + phy_lock_mdio_bus(phydev); ret = __phy_read_mmd(phydev, devad, regnum); phy_unlock_mdio_bus(phydev); @@ -479,6 +494,9 @@ int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + if (regnum > (u16)~0 || devad > 32) return -EINVAL; @@ -518,6 +536,9 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + phy_lock_mdio_bus(phydev); ret = __phy_write_mmd(phydev, devad, regnum, val); phy_unlock_mdio_bus(phydev); @@ -543,6 +564,9 @@ int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + phy_lock_mdio_bus(phydev); ret = __phy_modify_changed(phydev, regnum, mask, set); phy_unlock_mdio_bus(phydev); @@ -566,6 +590,9 @@ int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + ret = __phy_modify_changed(phydev, regnum, mask, set); return ret < 0 ? ret : 0; @@ -587,6 +614,9 @@ int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + phy_lock_mdio_bus(phydev); ret = __phy_modify(phydev, regnum, mask, set); phy_unlock_mdio_bus(phydev); @@ -613,6 +643,9 @@ int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum, { int new, ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + ret = __phy_read_mmd(phydev, devad, regnum); if (ret < 0) return ret; @@ -646,6 +679,9 @@ int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum, { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + phy_lock_mdio_bus(phydev); ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set); phy_unlock_mdio_bus(phydev); @@ -671,6 +707,9 @@ int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum, { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set); return ret < 0 ? ret : 0; @@ -694,6 +733,9 @@ int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum, { int ret; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + phy_lock_mdio_bus(phydev); ret = __phy_modify_mmd(phydev, devad, regnum, mask, set); phy_unlock_mdio_bus(phydev); @@ -704,6 +746,10 @@ EXPORT_SYMBOL_GPL(phy_modify_mmd); static int __phy_read_page(struct phy_device *phydev) { + + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n")) return -EOPNOTSUPP; @@ -712,6 +758,10 @@ static int __phy_read_page(struct phy_device *phydev) static int __phy_write_page(struct phy_device *phydev, int page) { + + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n")) return -EOPNOTSUPP; @@ -728,6 +778,10 @@ static int __phy_write_page(struct phy_device *phydev, int page) */ int phy_save_page(struct phy_device *phydev) { + + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + phy_lock_mdio_bus(phydev); return __phy_read_page(phydev); } @@ -748,6 +802,9 @@ int phy_select_page(struct phy_device *phydev, int page) { int ret, oldpage; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + oldpage = ret = phy_save_page(phydev); if (ret < 0) return ret; @@ -782,6 +839,9 @@ int phy_restore_page(struct phy_device *phydev, int oldpage, int ret) { int r; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + if (oldpage >= 0) { r = __phy_write_page(phydev, oldpage); @@ -813,6 +873,9 @@ int phy_read_paged(struct phy_device *phydev, int page, u32 regnum) { int ret = 0, oldpage; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + oldpage = phy_select_page(phydev, page); if (oldpage >= 0) ret = __phy_read(phydev, regnum); @@ -834,6 +897,9 @@ int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val) { int ret = 0, oldpage; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + oldpage = phy_select_page(phydev, page); if (oldpage >= 0) ret = __phy_write(phydev, regnum, val); @@ -857,6 +923,9 @@ int phy_modify_paged_changed(struct phy_device *phydev, int page, u32 regnum, { int ret = 0, oldpage; + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + oldpage = phy_select_page(phydev, page); if (oldpage >= 0) ret = __phy_modify_changed(phydev, regnum, mask, set); @@ -878,7 +947,12 @@ EXPORT_SYMBOL(phy_modify_paged_changed); int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum, u16 mask, u16 set) { - int ret = phy_modify_paged_changed(phydev, page, regnum, mask, set); + int ret; + + /* If phy not attached, do nothing */ + PHY_NOT_ATTACHED_CHECK + + ret = phy_modify_paged_changed(phydev, page, regnum, mask, set); return ret < 0 ? ret : 0; } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index ac2784192472..3aff74bfead0 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1352,8 +1352,6 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev->interface = interface; - phydev->state = PHY_READY; - /* Initial carrier state is off as the phy is about to be * (re)initialized. */ @@ -1371,6 +1369,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phy_resume(phydev); phy_led_triggers_register(phydev); + phydev->state = PHY_READY; + return err; error: -- 2.26.2