From fbd03513bf36c4e5c2942f436f05c8eb99a3cc9e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 22 Sep 2015 11:28:14 +0200 Subject: net: dsa: Fix Marvell Egress Trailer check The Marvell Egress rx trailer check must be fixed to correctly detect bad bits in the third byte of the Eggress trailer as described in the Table 28 of the 88E6060 datasheet. The current code incorrectly omits to check the third byte and checks the fourth byte twice. Signed-off-by: Neil Armstrong Acked-by: Guenter Roeck Signed-off-by: David S. Miller --- net/dsa/tag_trailer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/dsa') diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index d25efc93d8f1..b6ca0890d018 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -78,7 +78,7 @@ static int trailer_rcv(struct sk_buff *skb, struct net_device *dev, trailer = skb_tail_pointer(skb) - 4; if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 || - (trailer[3] & 0xef) != 0x00 || trailer[3] != 0x00) + (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) goto out_drop; source_port = trailer[1] & 7; -- cgit v1.2.3-58-ga151 From e496ae690b2faff751e1849fb97b060615e21f28 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 24 Sep 2015 20:35:57 +0100 Subject: net: dsa: fix of_mdio_find_bus() device refcount leak Current users of of_mdio_find_bus() leak a struct device refcount, as they fail to clean up the reference obtained inside class_find_device(). Fix the DSA code to properly refcount the returned MDIO bus by: 1. taking a reference on the struct device whenever we assign it to pd->chip[x].host_dev. 2. dropping the reference when we overwrite the existing reference. 3. dropping the reference when we free the data structure. 4. dropping the initial reference we obtained after setting up the platform data structure, or on failure. In step 2 above, where we obtain a new MDIO bus, there is no need to take a reference on it as we would only have to drop it immediately after assignment again, iow: put_device(cd->host_dev); /* drop original assignment ref */ cd->host_dev = get_device(&mdio_bus_switch->dev); /* get our ref */ put_device(&mdio_bus_switch->dev); /* drop of_mdio_find_bus ref */ Signed-off-by: Russell King Signed-off-by: David S. Miller --- net/dsa/dsa.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) (limited to 'net/dsa') diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 76e3800765f8..bf4ba15fb780 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -634,6 +634,10 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd) port_index++; } kfree(pd->chip[i].rtable); + + /* Drop our reference to the MDIO bus device */ + if (pd->chip[i].host_dev) + put_device(pd->chip[i].host_dev); } kfree(pd->chip); } @@ -661,16 +665,22 @@ static int dsa_of_probe(struct device *dev) return -EPROBE_DEFER; ethernet = of_parse_phandle(np, "dsa,ethernet", 0); - if (!ethernet) - return -EINVAL; + if (!ethernet) { + ret = -EINVAL; + goto out_put_mdio; + } ethernet_dev = of_find_net_device_by_node(ethernet); - if (!ethernet_dev) - return -EPROBE_DEFER; + if (!ethernet_dev) { + ret = -EPROBE_DEFER; + goto out_put_mdio; + } pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) - return -ENOMEM; + if (!pd) { + ret = -ENOMEM; + goto out_put_mdio; + } dev->platform_data = pd; pd->of_netdev = ethernet_dev; @@ -691,7 +701,9 @@ static int dsa_of_probe(struct device *dev) cd = &pd->chip[chip_index]; cd->of_node = child; - cd->host_dev = &mdio_bus->dev; + + /* When assigning the host device, increment its refcount */ + cd->host_dev = get_device(&mdio_bus->dev); sw_addr = of_get_property(child, "reg", NULL); if (!sw_addr) @@ -711,6 +723,12 @@ static int dsa_of_probe(struct device *dev) ret = -EPROBE_DEFER; goto out_free_chip; } + + /* Drop the mdio_bus device ref, replacing the host + * device with the mdio_bus_switch device, keeping + * the refcount from of_mdio_find_bus() above. + */ + put_device(cd->host_dev); cd->host_dev = &mdio_bus_switch->dev; } @@ -744,6 +762,10 @@ static int dsa_of_probe(struct device *dev) } } + /* The individual chips hold their own refcount on the mdio bus, + * so drop ours */ + put_device(&mdio_bus->dev); + return 0; out_free_chip: @@ -751,6 +773,8 @@ out_free_chip: out_free: kfree(pd); dev->platform_data = NULL; +out_put_mdio: + put_device(&mdio_bus->dev); return ret; } -- cgit v1.2.3-58-ga151 From 9861f72074c77a8a065622c1be7e9c4277e600eb Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 24 Sep 2015 20:36:33 +0100 Subject: net: fix net_device refcounting of_find_net_device_by_node() uses class_find_device() internally to lookup the corresponding network device. class_find_device() returns a reference to the embedded struct device, with its refcount incremented. Add a comment to the definition in net/core/net-sysfs.c indicating the need to drop this refcount, and fix the DSA code to drop this refcount when the OF-generated platform data is cleaned up and freed. Also arrange for the ref to be dropped when handling errors. Signed-off-by: Russell King Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 9 +++++++++ net/dsa/dsa.c | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'net/dsa') diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index b279077c3089..805a95a48107 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1481,6 +1481,15 @@ static int of_dev_node_match(struct device *dev, const void *data) return ret == 0 ? dev->of_node == data : ret; } +/* + * of_find_net_device_by_node - lookup the net device for the device node + * @np: OF device node + * + * Looks up the net_device structure corresponding with the device node. + * If successful, returns a pointer to the net_device with the embedded + * struct device refcount incremented by one, or NULL on failure. The + * refcount must be dropped when done with the net_device. + */ struct net_device *of_find_net_device_by_node(struct device_node *np) { struct device *dev; diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index bf4ba15fb780..c59fa5d9c22c 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -679,7 +679,7 @@ static int dsa_of_probe(struct device *dev) pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) { ret = -ENOMEM; - goto out_put_mdio; + goto out_put_ethernet; } dev->platform_data = pd; @@ -773,6 +773,8 @@ out_free_chip: out_free: kfree(pd); dev->platform_data = NULL; +out_put_ethernet: + put_device(ðernet_dev->dev); out_put_mdio: put_device(&mdio_bus->dev); return ret; @@ -786,6 +788,7 @@ static void dsa_of_remove(struct device *dev) return; dsa_of_free_platform_data(pd); + put_device(&pd->of_netdev->dev); kfree(pd); } #else -- cgit v1.2.3-58-ga151