net: fix phy refcounting in a bunch of drivers
authorRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 24 Sep 2015 19:36:18 +0000 (20:36 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 25 Sep 2015 06:04:53 +0000 (23:04 -0700)
of_phy_find_device() increments the phy struct device refcount, which
we need to properly balance.  Add code to network drivers using this
function to ensure that the struct device refcount is correctly
balanced.

For xgene, looking back in the history, we should be able to use
of_phy_connect() with a zero flags argument for the DT case as this is
how the driver used to operate prior to de7b5b3d790a ("net: eth: xgene:
change APM X-Gene SoC platform ethernet to support ACPI").

This leaves the Cavium Thunder BGX unfixed; fixing this driver is a
complicated task, one which the maintainers need to be involved with.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/xilinx/xilinx_emaclite.c

index cfa37041ab715db677f7d986bf45f51bbcae0444..c4bb8027b3fb0824a38f012a02de57d372b76494 100644 (file)
@@ -689,16 +689,24 @@ static int xgene_enet_phy_connect(struct net_device *ndev)
                        netdev_dbg(ndev, "No phy-handle found in DT\n");
                        return -ENODEV;
                }
-               pdata->phy_dev = of_phy_find_device(phy_np);
-       }
 
-       phy_dev = pdata->phy_dev;
+               phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link,
+                                        0, pdata->phy_mode);
+               if (!phy_dev) {
+                       netdev_err(ndev, "Could not connect to PHY\n");
+                       return -ENODEV;
+               }
+
+               pdata->phy_dev = phy_dev;
+       } else {
+               phy_dev = pdata->phy_dev;
 
-       if (!phy_dev ||
-           phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link,
-                              pdata->phy_mode)) {
-               netdev_err(ndev, "Could not connect to PHY\n");
-               return  -ENODEV;
+               if (!phy_dev ||
+                   phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link,
+                                      pdata->phy_mode)) {
+                       netdev_err(ndev, "Could not connect to PHY\n");
+                       return  -ENODEV;
+               }
        }
 
        pdata->phy_speed = SPEED_UNKNOWN;
index 803ed4c93503405369b5c4144ce3391698b08110..a5cf4332d307dd4a4f053e80fd3bbe5b7717b9bb 100644 (file)
@@ -1702,6 +1702,7 @@ static void gfar_configure_serdes(struct net_device *dev)
        tbiphy = of_phy_find_device(priv->tbi_node);
        if (!tbiphy) {
                dev_err(&dev->dev, "error: Could not get TBI device\n");
+               put_device(&tbiphy->dev);
                return;
        }
 
@@ -1723,6 +1724,8 @@ static void gfar_configure_serdes(struct net_device *dev)
        phy_write(tbiphy, MII_BMCR,
                  BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX |
                  BMCR_SPEED1000);
+
+       put_device(&tbiphy->dev);
 }
 
 static int __gfar_is_rx_idle(struct gfar_private *priv)
index 4dd40e057f40035ff6b8a1e236ab80c8ddc5497b..650f7888e32be90f805d10b44e9f8c913c357376 100644 (file)
@@ -1384,6 +1384,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
                value = phy_read(tbiphy, ENET_TBI_MII_CR);
                value &= ~0x1000;       /* Turn off autonegotiation */
                phy_write(tbiphy, ENET_TBI_MII_CR, value);
+
+               put_device(&tbiphy->dev);
        }
 
        init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
@@ -1702,8 +1704,10 @@ static void uec_configure_serdes(struct net_device *dev)
         * everything for us?  Resetting it takes the link down and requires
         * several seconds for it to come back.
         */
-       if (phy_read(tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS)
+       if (phy_read(tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS) {
+               put_device(&tbiphy->dev);
                return;
+       }
 
        /* Single clk mode, mii mode off(for serdes communication) */
        phy_write(tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS);
@@ -1711,6 +1715,8 @@ static void uec_configure_serdes(struct net_device *dev)
        phy_write(tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT);
 
        phy_write(tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS);
+
+       put_device(&tbiphy->dev);
 }
 
 /* Configure the PHY for dev.
index 09ec32e33076cf84040be77006b0607b4806f8eb..514df76fc70f36430a2d646fbee30997e6767210 100644 (file)
@@ -3175,6 +3175,8 @@ static int mvneta_probe(struct platform_device *pdev)
                struct phy_device *phy = of_phy_find_device(dn);
 
                mvneta_fixed_link_update(pp, phy);
+
+               put_device(&phy->dev);
        }
 
        return 0;
index 6008eee01a33a7a9e62918627443874eae56813a..cf468c87ce57e0954fe2d55d953968e64a2db74d 100644 (file)
@@ -828,6 +828,8 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
                if (!phydev)
                        dev_info(dev,
                                 "MDIO of the phy is not registered yet\n");
+               else
+                       put_device(&phydev->dev);
                return 0;
        }