summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2016-03-14 17:30:39 -0700
committerDavid S. Miller <davem@davemloft.net>2016-03-16 19:55:37 -0400
commitb7d3e3d3d21a09f8e45043d548224000a8efe06a (patch)
treefa226a278d8b74975bb064c94409f72f85b3898f /drivers
parent9277a4f875adbeeb6209c0a3e3cf04c752522b2e (diff)
downloadlinux-b7d3e3d3d21a09f8e45043d548224000a8efe06a.tar.gz
net: thunderx: Don't leak phy device references on -EPROBE_DEFER condition.
It is possible, although unlikely, that probing will find the
phy_device for the first LMAC of a thunder BGX device, but then need
to fail with -EPROBE_DEFER on a subsequent LMAC.  In this case, we
need to call put_device() on each of the phy_devices that were
obtained, but will be unused due to returning -EPROBE_DEFER.

Also, since we can break out of the probing loop early, we need to
explicitly call of_node_put() outside of the loop.

Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
index feed2318201b..967951582e03 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -974,17 +974,18 @@ static int bgx_init_acpi_phy(struct bgx *bgx)
 static int bgx_init_of_phy(struct bgx *bgx)
 {
 	struct fwnode_handle *fwn;
+	struct device_node *node = NULL;
 	u8 lmac = 0;
-	const char *mac;
 
 	device_for_each_child_node(&bgx->pdev->dev, fwn) {
 		struct phy_device *pd;
 		struct device_node *phy_np;
-		struct device_node *node = to_of_node(fwn);
+		const char *mac;
 
 		/* Should always be an OF node.  But if it is not, we
 		 * cannot handle it, so exit the loop.
 		 */
+		node = to_of_node(fwn);
 		if (!node)
 			break;
 
@@ -1005,17 +1006,30 @@ static int bgx_init_of_phy(struct bgx *bgx)
 			/* Wait until the phy drivers are available */
 			pd = of_phy_find_device(phy_np);
 			if (!pd)
-				return -EPROBE_DEFER;
+				goto defer;
 			bgx->lmac[lmac].phydev = pd;
 		}
 
 		lmac++;
-		if (lmac == MAX_LMAC_PER_BGX) {
-			of_node_put(node);
+		if (lmac == MAX_LMAC_PER_BGX)
 			break;
-		}
 	}
+	of_node_put(node);
 	return 0;
+
+defer:
+	/* We are bailing out, try not to leak device reference counts
+	 * for phy devices we may have already found.
+	 */
+	while (lmac) {
+		if (bgx->lmac[lmac].phydev) {
+			put_device(&bgx->lmac[lmac].phydev->mdio.dev);
+			bgx->lmac[lmac].phydev = NULL;
+		}
+		lmac--;
+	}
+	of_node_put(node);
+	return -EPROBE_DEFER;
 }
 
 #else