From 1023d2ec1e8bd63ede9ed1d93ebb797f650859b7 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 6 Oct 2015 15:39:53 +0100 Subject: net: dsa: add missing kfree on remove To prevent memory leakage on unbinding, add missing kfree calls. Includes minor cosmetic change to make patch clean. Signed-off-by: Neil Armstrong Signed-off-by: David S. Miller --- net/dsa/dsa.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/dsa/dsa.c') diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index c59fa5d9c22c..ed9d43fd1fec 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -914,8 +914,10 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst) for (i = 0; i < dst->pd->nr_chips; i++) { struct dsa_switch *ds = dst->ds[i]; - if (ds != NULL) + if (ds) { dsa_switch_destroy(ds); + kfree(ds); + } } } @@ -924,6 +926,7 @@ static int dsa_remove(struct platform_device *pdev) struct dsa_switch_tree *dst = platform_get_drvdata(pdev); dsa_remove_dst(dst); + kfree(dst); dsa_of_remove(&pdev->dev); return 0; -- cgit v1.2.3 From e410ddb89ee8e68103ea58938b4972da594e3d2d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 6 Oct 2015 15:40:25 +0100 Subject: net: dsa: add missing dsa_switch mdiobus remove To prevent memory leakage on unbinding, add missing mdiobus unregister and unallocation calls. Reviewed-by: Florian Fainelli Signed-off-by: Neil Armstrong Signed-off-by: David S. Miller --- net/dsa/dsa.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/dsa/dsa.c') diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index ed9d43fd1fec..14fac4ed9569 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -424,6 +424,8 @@ static void dsa_switch_destroy(struct dsa_switch *ds) if (ds->hwmon_dev) hwmon_device_unregister(ds->hwmon_dev); #endif + mdiobus_unregister(ds->slave_mii_bus); + mdiobus_free(ds->slave_mii_bus); } #ifdef CONFIG_PM_SLEEP -- cgit v1.2.3 From cbc5d90b378cd255ffedeb12f5affe243230d47e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 6 Oct 2015 15:40:32 +0100 Subject: net: dsa: complete dsa_switch_destroy When unbinding dsa, complete the dsa_switch_destroy to unregister the fixed link phy then cleanly unregister and destroy the net devices. Reviewed-by: Florian Fainelli Signed-off-by: Neil Armstrong Signed-off-by: David S. Miller --- net/dsa/dsa.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'net/dsa/dsa.c') diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 14fac4ed9569..61559232861b 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "dsa_priv.h" char dsa_driver_version[] = "0.1"; @@ -420,10 +421,46 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, static void dsa_switch_destroy(struct dsa_switch *ds) { + struct device_node *port_dn; + struct phy_device *phydev; + struct dsa_chip_data *cd = ds->pd; + int port; + #ifdef CONFIG_NET_DSA_HWMON if (ds->hwmon_dev) hwmon_device_unregister(ds->hwmon_dev); #endif + + /* Disable configuration of the CPU and DSA ports */ + for (port = 0; port < DSA_MAX_PORTS; port++) { + if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) + continue; + + port_dn = cd->port_dn[port]; + if (of_phy_is_fixed_link(port_dn)) { + phydev = of_phy_find_device(port_dn); + if (phydev) { + int addr = phydev->addr; + + phy_device_free(phydev); + of_node_put(port_dn); + fixed_phy_del(addr); + } + } + } + + /* Destroy network devices for physical switch ports. */ + for (port = 0; port < DSA_MAX_PORTS; port++) { + if (!(ds->phys_port_mask & (1 << port))) + continue; + + if (!ds->ports[port]) + continue; + + unregister_netdev(ds->ports[port]); + free_netdev(ds->ports[port]); + } + mdiobus_unregister(ds->slave_mii_bus); mdiobus_free(ds->slave_mii_bus); } -- cgit v1.2.3 From d4ac35d6ed82e6c96ed5c016ea46fad31294fa7a Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 6 Oct 2015 15:40:37 +0100 Subject: net: dsa: switch to devm_ calls and remove kfree calls Now the kfree calls exists in the the remove functions, remove them in all places except the of_probe functions and replace allocation calls with their devm_ counterparts. Reviewed-by: Florian Fainelli Signed-off-by: Neil Armstrong Signed-off-by: David S. Miller --- net/dsa/dsa.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'net/dsa/dsa.c') diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 61559232861b..d5a162cda087 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -306,7 +306,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) if (ret < 0) goto out; - ds->slave_mii_bus = mdiobus_alloc(); + ds->slave_mii_bus = devm_mdiobus_alloc(parent); if (ds->slave_mii_bus == NULL) { ret = -ENOMEM; goto out; @@ -315,7 +315,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) ret = mdiobus_register(ds->slave_mii_bus); if (ret < 0) - goto out_free; + goto out; /* @@ -368,10 +368,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) return ret; -out_free: - mdiobus_free(ds->slave_mii_bus); out: - kfree(ds); return ret; } @@ -401,7 +398,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, /* * Allocate and initialise switch state. */ - ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL); + ds = devm_kzalloc(parent, sizeof(*ds) + drv->priv_size, GFP_KERNEL); if (ds == NULL) return ERR_PTR(-ENOMEM); @@ -462,7 +459,6 @@ static void dsa_switch_destroy(struct dsa_switch *ds) } mdiobus_unregister(ds->slave_mii_bus); - mdiobus_free(ds->slave_mii_bus); } #ifdef CONFIG_PM_SLEEP @@ -922,7 +918,7 @@ static int dsa_probe(struct platform_device *pdev) goto out; } - dst = kzalloc(sizeof(*dst), GFP_KERNEL); + dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); if (dst == NULL) { dev_put(dev); ret = -ENOMEM; @@ -953,10 +949,8 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst) for (i = 0; i < dst->pd->nr_chips; i++) { struct dsa_switch *ds = dst->ds[i]; - if (ds) { + if (ds) dsa_switch_destroy(ds); - kfree(ds); - } } } @@ -965,7 +959,6 @@ static int dsa_remove(struct platform_device *pdev) struct dsa_switch_tree *dst = platform_get_drvdata(pdev); dsa_remove_dst(dst); - kfree(dst); dsa_of_remove(&pdev->dev); return 0; -- cgit v1.2.3 From 4d7f3e757c15051b4521a59791de87ce748c0eb2 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 6 Oct 2015 15:40:43 +0100 Subject: net: dsa: exit probe if no switch were found If no switch were found in dsa_setup_dst, return -ENODEV and exit the dsa_probe cleanly. Signed-off-by: Neil Armstrong Signed-off-by: David S. Miller --- net/dsa/dsa.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'net/dsa/dsa.c') diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index d5a162cda087..adb5325f4934 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -837,10 +837,11 @@ static inline void dsa_of_remove(struct device *dev) } #endif -static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, - struct device *parent, struct dsa_platform_data *pd) +static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, + struct device *parent, struct dsa_platform_data *pd) { int i; + unsigned configured = 0; dst->pd = pd; dst->master_netdev = dev; @@ -860,8 +861,16 @@ static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, dst->ds[i] = ds; if (ds->drv->poll_link != NULL) dst->link_poll_needed = 1; + + ++configured; } + /* + * If no switch was found, exit cleanly + */ + if (!configured) + return -EPROBE_DEFER; + /* * If we use a tagging format that doesn't have an ethertype * field, make sure that all packets from this point on get @@ -878,6 +887,8 @@ static void dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev, dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); add_timer(&dst->link_poll_timer); } + + return 0; } static int dsa_probe(struct platform_device *pdev) @@ -927,7 +938,9 @@ static int dsa_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dst); - dsa_setup_dst(dst, dev, &pdev->dev, pd); + ret = dsa_setup_dst(dst, dev, &pdev->dev, pd); + if (ret) + goto out; return 0; -- cgit v1.2.3