net: ethernet: ti: cpsw: fix of_node and phydev leaks
authorJohan Hovold <johan@kernel.org>
Thu, 17 Nov 2016 16:40:01 +0000 (17:40 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 18 Nov 2016 18:48:53 +0000 (13:48 -0500)
Make sure to drop references taken and deregister devices registered
during probe on probe errors (including deferred probe) and driver
unbind.

Specifically, PHY of-node references were never released and fixed-link
PHY devices were never deregistered.

Fixes: 9e42f715264f ("drivers: net: cpsw: add phy-handle parsing")
Fixes: 1f71e8c96fc6 ("drivers: net: cpsw: Add support for fixed-link
PHY")
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ti/cpsw.c

index 5d14abb06486fb45dd9afe4761ca2786124ab91a..c3b78bc4fe5836a5a4ec7607b2dd797f5464f0c8 100644 (file)
@@ -2443,6 +2443,41 @@ no_phy_slave:
 
 static void cpsw_remove_dt(struct platform_device *pdev)
 {
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+       struct cpsw_platform_data *data = &cpsw->data;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *slave_node;
+       int i = 0;
+
+       for_each_available_child_of_node(node, slave_node) {
+               struct cpsw_slave_data *slave_data = &data->slave_data[i];
+
+               if (strcmp(slave_node->name, "slave"))
+                       continue;
+
+               if (of_phy_is_fixed_link(slave_node)) {
+                       struct phy_device *phydev;
+
+                       phydev = of_phy_find_device(slave_node);
+                       if (phydev) {
+                               fixed_phy_unregister(phydev);
+                               /* Put references taken by
+                                * of_phy_find_device() and
+                                * of_phy_register_fixed_link().
+                                */
+                               phy_device_free(phydev);
+                               phy_device_free(phydev);
+                       }
+               }
+
+               of_node_put(slave_data->phy_node);
+
+               i++;
+               if (i == data->slaves)
+                       break;
+       }
+
        of_platform_depopulate(&pdev->dev);
 }