From: Geert Uytterhoeven <geert+rene...@glider.be>

commit 77972b55fb9d35d4a6b0abca99abffaa4ec6a85b upstream.

This reverts commit 1838d6c62f57836639bd3d83e7855e0ee4f6defc.

This commit moved the ravb_mdio_init() call (and thus the
of_mdiobus_register() call) from the ravb_probe() to the ravb_open()
call.  This causes a regression during system resume (s2idle/s2ram), as
new PHY devices cannot be bound while suspended.

During boot, the Micrel PHY is detected like this:

    Micrel KSZ9031 Gigabit PHY e6800000.ethernet-ffffffff:00: attached PHY 
driver [Micrel KSZ9031 Gigabit PHY] 
(mii_bus:phy_addr=e6800000.ethernet-ffffffff:00, irq=228)
    ravb e6800000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off

During system suspend, (A) defer_all_probes is set to true, and (B)
usermodehelper_disabled is set to UMH_DISABLED, to avoid drivers being
probed while suspended.

  A. If CONFIG_MODULES=n, phy_device_register() calling device_add()
     merely adds the device, but does not probe it yet, as
     really_probe() returns early due to defer_all_probes being set:

       dpm_resume+0x128/0x4f8
         device_resume+0xcc/0x1b0
           dpm_run_callback+0x74/0x340
             ravb_resume+0x190/0x1b8
               ravb_open+0x84/0x770
                 of_mdiobus_register+0x1e0/0x468
                   of_mdiobus_register_phy+0x1b8/0x250
                     of_mdiobus_phy_device_register+0x178/0x1e8
                       phy_device_register+0x114/0x1b8
                         device_add+0x3d4/0x798
                           bus_probe_device+0x98/0xa0
                             device_initial_probe+0x10/0x18
                               __device_attach+0xe4/0x140
                                 bus_for_each_drv+0x64/0xc8
                                   __device_attach_driver+0xb8/0xe0
                                     driver_probe_device.part.11+0xc4/0xd8
                                       really_probe+0x32c/0x3b8

     Later, phy_attach_direct() notices no PHY driver has been bound,
     and falls back to the Generic PHY, leading to degraded operation:

       Generic PHY e6800000.ethernet-ffffffff:00: attached PHY driver [Generic 
PHY] (mii_bus:phy_addr=e6800000.ethernet-ffffffff:00, irq=POLL)
       ravb e6800000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off

  B. If CONFIG_MODULES=y, request_module() returns early with -EBUSY due
     to UMH_DISABLED, and MDIO initialization fails completely:

       mdio_bus e6800000.ethernet-ffffffff:00: error -16 loading PHY driver 
module for ID 0x00221622
       ravb e6800000.ethernet eth0: failed to initialize MDIO
       PM: dpm_run_callback(): ravb_resume+0x0/0x1b8 returns -16
       PM: Device e6800000.ethernet failed to resume: error -16

     Ignoring -EBUSY in phy_request_driver_module(), like was done for
     -ENOENT in commit 21e194425abd65b5 ("net: phy: fix issue with loading
     PHY driver w/o initramfs"), would makes it fall back to the Generic
     PHY, like in the CONFIG_MODULES=n case.

Signed-off-by: Geert Uytterhoeven <geert+rene...@glider.be>
Cc: sta...@vger.kernel.org
Reviewed-by: Sergei Shtylyov <sergei.shtyl...@gmail.com>
Signed-off-by: David S. Miller <da...@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/net/ethernet/renesas/ravb_main.c |  110 +++++++++++++++----------------
 1 file changed, 55 insertions(+), 55 deletions(-)

--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1337,51 +1337,6 @@ static inline int ravb_hook_irq(unsigned
        return error;
 }
 
-/* MDIO bus init function */
-static int ravb_mdio_init(struct ravb_private *priv)
-{
-       struct platform_device *pdev = priv->pdev;
-       struct device *dev = &pdev->dev;
-       int error;
-
-       /* Bitbang init */
-       priv->mdiobb.ops = &bb_ops;
-
-       /* MII controller setting */
-       priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
-       if (!priv->mii_bus)
-               return -ENOMEM;
-
-       /* Hook up MII support for ethtool */
-       priv->mii_bus->name = "ravb_mii";
-       priv->mii_bus->parent = dev;
-       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-                pdev->name, pdev->id);
-
-       /* Register MDIO bus */
-       error = of_mdiobus_register(priv->mii_bus, dev->of_node);
-       if (error)
-               goto out_free_bus;
-
-       return 0;
-
-out_free_bus:
-       free_mdio_bitbang(priv->mii_bus);
-       return error;
-}
-
-/* MDIO bus release function */
-static int ravb_mdio_release(struct ravb_private *priv)
-{
-       /* Unregister mdio bus */
-       mdiobus_unregister(priv->mii_bus);
-
-       /* Free bitbang info */
-       free_mdio_bitbang(priv->mii_bus);
-
-       return 0;
-}
-
 /* Network device open function for Ethernet AVB */
 static int ravb_open(struct net_device *ndev)
 {
@@ -1390,13 +1345,6 @@ static int ravb_open(struct net_device *
        struct device *dev = &pdev->dev;
        int error;
 
-       /* MDIO bus init */
-       error = ravb_mdio_init(priv);
-       if (error) {
-               netdev_err(ndev, "failed to initialize MDIO\n");
-               return error;
-       }
-
        napi_enable(&priv->napi[RAVB_BE]);
        napi_enable(&priv->napi[RAVB_NC]);
 
@@ -1474,7 +1422,6 @@ out_free_irq:
 out_napi_off:
        napi_disable(&priv->napi[RAVB_NC]);
        napi_disable(&priv->napi[RAVB_BE]);
-       ravb_mdio_release(priv);
        return error;
 }
 
@@ -1774,8 +1721,6 @@ static int ravb_close(struct net_device
        ravb_ring_free(ndev, RAVB_BE);
        ravb_ring_free(ndev, RAVB_NC);
 
-       ravb_mdio_release(priv);
-
        return 0;
 }
 
@@ -1922,6 +1867,51 @@ static const struct net_device_ops ravb_
        .ndo_set_features       = ravb_set_features,
 };
 
+/* MDIO bus init function */
+static int ravb_mdio_init(struct ravb_private *priv)
+{
+       struct platform_device *pdev = priv->pdev;
+       struct device *dev = &pdev->dev;
+       int error;
+
+       /* Bitbang init */
+       priv->mdiobb.ops = &bb_ops;
+
+       /* MII controller setting */
+       priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
+       if (!priv->mii_bus)
+               return -ENOMEM;
+
+       /* Hook up MII support for ethtool */
+       priv->mii_bus->name = "ravb_mii";
+       priv->mii_bus->parent = dev;
+       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+                pdev->name, pdev->id);
+
+       /* Register MDIO bus */
+       error = of_mdiobus_register(priv->mii_bus, dev->of_node);
+       if (error)
+               goto out_free_bus;
+
+       return 0;
+
+out_free_bus:
+       free_mdio_bitbang(priv->mii_bus);
+       return error;
+}
+
+/* MDIO bus release function */
+static int ravb_mdio_release(struct ravb_private *priv)
+{
+       /* Unregister mdio bus */
+       mdiobus_unregister(priv->mii_bus);
+
+       /* Free bitbang info */
+       free_mdio_bitbang(priv->mii_bus);
+
+       return 0;
+}
+
 static const struct of_device_id ravb_match_table[] = {
        { .compatible = "renesas,etheravb-r8a7790", .data = (void *)RCAR_GEN2 },
        { .compatible = "renesas,etheravb-r8a7794", .data = (void *)RCAR_GEN2 },
@@ -2148,6 +2138,13 @@ static int ravb_probe(struct platform_de
                eth_hw_addr_random(ndev);
        }
 
+       /* MDIO bus init */
+       error = ravb_mdio_init(priv);
+       if (error) {
+               dev_err(&pdev->dev, "failed to initialize MDIO\n");
+               goto out_dma_free;
+       }
+
        netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll, 64);
        netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll, 64);
 
@@ -2169,6 +2166,8 @@ static int ravb_probe(struct platform_de
 out_napi_del:
        netif_napi_del(&priv->napi[RAVB_NC]);
        netif_napi_del(&priv->napi[RAVB_BE]);
+       ravb_mdio_release(priv);
+out_dma_free:
        dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
                          priv->desc_bat_dma);
 
@@ -2200,6 +2199,7 @@ static int ravb_remove(struct platform_d
        unregister_netdev(ndev);
        netif_napi_del(&priv->napi[RAVB_NC]);
        netif_napi_del(&priv->napi[RAVB_BE]);
+       ravb_mdio_release(priv);
        pm_runtime_disable(&pdev->dev);
        free_netdev(ndev);
        platform_set_drvdata(pdev, NULL);


Reply via email to