Hi, Now i got it working without user meddeling at all: From: Lauri Jakku <lja@xxxxxx> Date: Mon, 9 Aug 2021 21:44:53 +0300 Subject: [PATCH] net:realtek:r8169 driver load fix net:realtek:r8169 Problem: The driver seems not to work at first run for some HW's, not even when proper hardware is detected by it at the first probe. Solution: the driver will trust the hardware that reports valid ID and then make re-loading of the module as it would being reloaded manually. Signed-off-by: Lauri Jakku <lja@xxxxxx> --- .../drivers/net/ethernet/realtek/r8169_main.c | 35 ++++++++++++++--- linux-5.14-rc4/drivers/net/phy/phy_device.c | 38 +++++++++++++++++++ 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/linux-5.14-rc4/drivers/net/ethernet/realtek/r8169_main.c b/linux-5.14-rc4/drivers/net/ethernet/realtek/r8169_main.c index c7af5bc3b..d8e602527 100644 --- a/linux-5.14-rc4/drivers/net/ethernet/realtek/r8169_main.c +++ b/linux-5.14-rc4/drivers/net/ethernet/realtek/r8169_main.c @@ -634,6 +634,8 @@ struct rtl8169_private { struct rtl_fw *rtl_fw; u32 ocp_base; + + int retry_probeing; }; typedef void (*rtl_generic_fct)(struct rtl8169_private *tp); @@ -5097,13 +5099,16 @@ static int r8169_mdio_register(struct rtl8169_private *tp) tp->phydev = mdiobus_get_phy(new_bus, 0); if (!tp->phydev) { return -ENODEV; - } else if (!tp->phydev->drv) { - /* Most chip versions fail with the genphy driver. - * Therefore ensure that the dedicated PHY driver is loaded. + } else if (tp->phydev->phy_id != RTL_GIGA_MAC_NONE) { + /* Most chip versions fail with the genphy driver, BUT do rerport valid IW + * ID. Re-starting the module seem to fix the issue of non-functional driver. */ - dev_err(&pdev->dev, "no dedicated PHY driver found for PHY ID 0x%08x, maybe realtek.ko needs to be added to initramfs?\n", + dev_err(&pdev->dev, + "no dedicated driver, but HW found: PHY PHY ID 0x%08x\n", tp->phydev->phy_id); - return -EUNATCH; + + dev_err(&pdev->dev, "trying re-probe few times..\n"); + } tp->phydev->mac_managed_pm = 1; @@ -5250,6 +5255,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) enum mac_version chipset; struct net_device *dev; u16 xid; + int savederr = 0; dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp)); if (!dev) @@ -5261,6 +5267,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->dev = dev; tp->pci_dev = pdev; tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; + tp->retry_probeing = 0; tp->eee_adv = -1; tp->ocp_base = OCP_STD_PHY_BASE; @@ -5410,7 +5417,15 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, tp); - rc = r8169_mdio_register(tp); + savederr = r8169_mdio_register(tp); + + if ( + (tp->retry_probeing > 0) && + (savederr == -EAGAIN) + ) { + netdev_info(dev, " retry of probe requested.............."); + } + if (rc) return rc; @@ -5435,6 +5450,14 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_dev_run_wake(pdev)) pm_runtime_put_sync(&pdev->dev); + if ( + (tp->retry_probeing > 0) && + (savederr == -EAGAIN) + ) { + netdev_info(dev, " retry of probe requested.............."); + return savederr; + } + return 0; } diff --git a/linux-5.14-rc4/drivers/net/phy/phy_device.c b/linux-5.14-rc4/drivers/net/phy/phy_device.c index 5d5f9a9ee..59c6ac031 100644 --- a/linux-5.14-rc4/drivers/net/phy/phy_device.c +++ b/linux-5.14-rc4/drivers/net/phy/phy_device.c @@ -2980,6 +2980,9 @@ struct fwnode_handle *fwnode_get_phy_node(struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_get_phy_node); + +static int phy_remove(struct device *dev); + /** * phy_probe - probe and init a PHY device * @dev: device to probe and init @@ -2988,13 +2991,22 @@ EXPORT_SYMBOL_GPL(fwnode_get_phy_node); * set the state to READY (the driver's init function should * set it to STARTING if needed). */ +#define REDO_PROBE_TIMES 5 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 again = 0; + int savederr = 0; +again_retry: int err = 0; + if (again > 0) { + pr_err("%s: Re-probe %d of driver.....\n", + phydrv->name, again); + } + phydev->drv = phydrv; /* Disable the interrupt if the PHY doesn't support it @@ -3013,6 +3025,17 @@ static int phy_probe(struct device *dev) if (phydev->drv->probe) { err = phydev->drv->probe(phydev); + + /* If again requested. */ + if (err == -EAGAIN) { + again++; + savederr = err; + err = 0; + + pr_info("%s: EAGAIN: %d ...\n", + phydrv->name, again); + } + if (err) goto out; } @@ -3081,6 +3104,20 @@ static int phy_probe(struct device *dev) mutex_unlock(&phydev->lock); + if ((savederr == -EAGAIN) && + ((again > 0) && (again < REDO_PROBE_TIMES)) + ) { + pr_err("%s: Retry removal driver..\n", + phydrv->name); + + phy_remove(dev); + + pr_err("%s: Re-probe driver..\n", + phydrv->name); + savederr = 0; + goto again_retry; + } + return err; } @@ -3108,6 +3145,7 @@ static int phy_remove(struct device *dev) return 0; } + static void phy_shutdown(struct device *dev) { struct phy_device *phydev = to_phy_device(dev); -- 2.17.1