From f1a26a062f03b27fa52f62487897fe205303fa7f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Mar 2015 12:35:04 -0800 Subject: [PATCH 1/5] net: dsa: update dsa_of_{probe, remove} to use a device pointer In preparation for allowing a different mechanism to register DSA switch devices and driver, update dsa_of_probe and dsa_of_remove to take a struct device pointer since neither of these two functions uses the struct platform_device pointer. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index a1d1f0775bea..d804364150bd 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -563,9 +563,9 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd) kfree(pd->chip); } -static int dsa_of_probe(struct platform_device *pdev) +static int dsa_of_probe(struct device *dev) { - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev->of_node; struct device_node *child, *mdio, *ethernet, *port, *link; struct mii_bus *mdio_bus; struct platform_device *ethernet_dev; @@ -597,7 +597,7 @@ static int dsa_of_probe(struct platform_device *pdev) if (!pd) return -ENOMEM; - pdev->dev.platform_data = pd; + dev->platform_data = pd; pd->netdev = ðernet_dev->dev; pd->nr_chips = of_get_available_child_count(np); if (pd->nr_chips > DSA_MAX_SWITCHES) @@ -670,27 +670,27 @@ out_free_chip: dsa_of_free_platform_data(pd); out_free: kfree(pd); - pdev->dev.platform_data = NULL; + dev->platform_data = NULL; return ret; } -static void dsa_of_remove(struct platform_device *pdev) +static void dsa_of_remove(struct device *dev) { - struct dsa_platform_data *pd = pdev->dev.platform_data; + struct dsa_platform_data *pd = dev->platform_data; - if (!pdev->dev.of_node) + if (!dev->of_node) return; dsa_of_free_platform_data(pd); kfree(pd); } #else -static inline int dsa_of_probe(struct platform_device *pdev) +static inline int dsa_of_probe(struct device *dev) { return 0; } -static inline void dsa_of_remove(struct platform_device *pdev) +static inline void dsa_of_remove(struct device *dev) { } #endif @@ -706,7 +706,7 @@ static int dsa_probe(struct platform_device *pdev) dsa_driver_version); if (pdev->dev.of_node) { - ret = dsa_of_probe(pdev); + ret = dsa_of_probe(&pdev->dev); if (ret) return ret; @@ -777,7 +777,7 @@ static int dsa_probe(struct platform_device *pdev) return 0; out: - dsa_of_remove(pdev); + dsa_of_remove(&pdev->dev); return ret; } @@ -799,7 +799,7 @@ static int dsa_remove(struct platform_device *pdev) dsa_switch_destroy(ds); } - dsa_of_remove(pdev); + dsa_of_remove(&pdev->dev); return 0; } From b324c07ac4771a6ac8f57a3e1897e1b36b0a9ff0 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Mar 2015 12:35:05 -0800 Subject: [PATCH 2/5] net: dsa: allow deferred probing In preparation for allowing a different model to register DSA switches, update dsa_of_probe() and dsa_probe() to return -EPROBE_DEFER where appropriate. Failure to find a phandle or Device Tree property is still fatal, but looking up the internal device structure associated with a Device Tree node is something that might need to be delayed based on driver probe ordering. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index d804364150bd..79879d01488a 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -583,7 +583,7 @@ static int dsa_of_probe(struct device *dev) mdio_bus = of_mdio_find_bus(mdio); if (!mdio_bus) - return -EINVAL; + return -EPROBE_DEFER; ethernet = of_parse_phandle(np, "dsa,ethernet", 0); if (!ethernet) @@ -591,7 +591,7 @@ static int dsa_of_probe(struct device *dev) ethernet_dev = of_find_device_by_node(ethernet); if (!ethernet_dev) - return -ENODEV; + return -EPROBE_DEFER; pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) @@ -718,7 +718,7 @@ static int dsa_probe(struct platform_device *pdev) dev = dev_to_net_device(pd->netdev); if (dev == NULL) { - ret = -EINVAL; + ret = -EPROBE_DEFER; goto out; } From df197195a5248164df0709fbadc61133897281f5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Mar 2015 12:35:06 -0800 Subject: [PATCH 3/5] net: dsa: split dsa_switch_setup into two functions Split the part of dsa_switch_setup() which is responsible for allocating and initializing a 'struct dsa_switch' and the part which is doing a given switch device setup and slave network device creation. This is a preliminary change to allow a separate caller of dsa_switch_setup_one() which may have externally initialized the dsa_switch structure, outside of dsa_switch_setup(). Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa.c | 88 +++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 79879d01488a..6f02ccc57593 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -175,43 +175,14 @@ __ATTRIBUTE_GROUPS(dsa_hwmon); #endif /* CONFIG_NET_DSA_HWMON */ /* basic switch operations **************************************************/ -static struct dsa_switch * -dsa_switch_setup(struct dsa_switch_tree *dst, int index, - struct device *parent, struct device *host_dev) +static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) { - struct dsa_chip_data *pd = dst->pd->chip + index; - struct dsa_switch_driver *drv; - struct dsa_switch *ds; - int ret; - char *name; - int i; + struct dsa_switch_driver *drv = ds->drv; + struct dsa_switch_tree *dst = ds->dst; + struct dsa_chip_data *pd = ds->pd; bool valid_name_found = false; - - /* - * Probe for switch model. - */ - drv = dsa_switch_probe(host_dev, pd->sw_addr, &name); - if (drv == NULL) { - netdev_err(dst->master_netdev, "[%d]: could not detect attached switch\n", - index); - return ERR_PTR(-EINVAL); - } - netdev_info(dst->master_netdev, "[%d]: detected a %s switch\n", - index, name); - - - /* - * Allocate and initialise switch state. - */ - ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL); - if (ds == NULL) - return ERR_PTR(-ENOMEM); - - ds->dst = dst; - ds->index = index; - ds->pd = dst->pd->chip + index; - ds->drv = drv; - ds->master_dev = host_dev; + int index = ds->index; + int i, ret; /* * Validate supplied switch configuration. @@ -350,13 +321,56 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, } #endif /* CONFIG_NET_DSA_HWMON */ - return ds; + return ret; out_free: mdiobus_free(ds->slave_mii_bus); out: kfree(ds); - return ERR_PTR(ret); + return ret; +} + +static struct dsa_switch * +dsa_switch_setup(struct dsa_switch_tree *dst, int index, + struct device *parent, struct device *host_dev) +{ + struct dsa_chip_data *pd = dst->pd->chip + index; + struct dsa_switch_driver *drv; + struct dsa_switch *ds; + int ret; + char *name; + + /* + * Probe for switch model. + */ + drv = dsa_switch_probe(host_dev, pd->sw_addr, &name); + if (drv == NULL) { + netdev_err(dst->master_netdev, "[%d]: could not detect attached switch\n", + index); + return ERR_PTR(-EINVAL); + } + netdev_info(dst->master_netdev, "[%d]: detected a %s switch\n", + index, name); + + + /* + * Allocate and initialise switch state. + */ + ds = kzalloc(sizeof(*ds) + drv->priv_size, GFP_KERNEL); + if (ds == NULL) + return NULL; + + ds->dst = dst; + ds->index = index; + ds->pd = pd; + ds->drv = drv; + ds->master_dev = host_dev; + + ret = dsa_switch_setup_one(ds, parent); + if (ret) + return NULL; + + return ds; } static void dsa_switch_destroy(struct dsa_switch *ds) From 59299031038f3ea92cf484bc4a68d16ad4bb3050 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Mar 2015 12:35:07 -0800 Subject: [PATCH 4/5] net: dsa: let switches specify their tagging protocol In order to support the new DSA device driver model, a dsa_switch should be able to advertise the type of tagging protocol supported by the underlying switch device. This also removes constraints on how tagging can be stacked to each other. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/net/dsa.h | 5 +++++ net/dsa/dsa.c | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index c542c131d551..b525ac516559 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -127,6 +127,11 @@ struct dsa_switch { struct dsa_switch_tree *dst; int index; + /* + * Tagging protocol understood by this switch + */ + enum dsa_tag_protocol tag_protocol; + /* * Configuration data for this switch. */ diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 6f02ccc57593..4cc995664fdf 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -227,7 +227,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) * switch. */ if (dst->cpu_switch == index) { - switch (drv->tag_protocol) { + switch (ds->tag_protocol) { #ifdef CONFIG_NET_DSA_TAG_DSA case DSA_TAG_PROTO_DSA: dst->rcv = dsa_netdev_ops.rcv; @@ -255,7 +255,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) goto out; } - dst->tag_protocol = drv->tag_protocol; + dst->tag_protocol = ds->tag_protocol; } /* @@ -364,6 +364,7 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index, ds->index = index; ds->pd = pd; ds->drv = drv; + ds->tag_protocol = drv->tag_protocol; ds->master_dev = host_dev; ret = dsa_switch_setup_one(ds, parent); From c86e59b9e63659bb7fc2ba1781aabe2f37aaf10b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Mar 2015 12:35:08 -0800 Subject: [PATCH 5/5] net: dsa: extract dsa switch tree setup and removal Extract the core logic that setups a 'struct dsa_switch_tree' and removes it, update dsa_probe() and dsa_remove() to use the two helper functions. This will be useful to allow for other callers to setup this structure differently. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa.c | 91 +++++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 4cc995664fdf..b40f11bb419c 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -710,12 +710,55 @@ 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) +{ + int i; + + dst->pd = pd; + dst->master_netdev = dev; + dst->cpu_switch = -1; + dst->cpu_port = -1; + + for (i = 0; i < pd->nr_chips; i++) { + struct dsa_switch *ds; + + ds = dsa_switch_setup(dst, i, parent, pd->chip[i].host_dev); + if (IS_ERR(ds)) { + netdev_err(dev, "[%d]: couldn't create dsa switch instance (error %ld)\n", + i, PTR_ERR(ds)); + continue; + } + + dst->ds[i] = ds; + if (ds->drv->poll_link != NULL) + dst->link_poll_needed = 1; + } + + /* + * If we use a tagging format that doesn't have an ethertype + * field, make sure that all packets from this point on get + * sent to the tag format's receive function. + */ + wmb(); + dev->dsa_ptr = (void *)dst; + + if (dst->link_poll_needed) { + INIT_WORK(&dst->link_poll_work, dsa_link_poll_work); + init_timer(&dst->link_poll_timer); + dst->link_poll_timer.data = (unsigned long)dst; + dst->link_poll_timer.function = dsa_link_poll_timer; + dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); + add_timer(&dst->link_poll_timer); + } +} + static int dsa_probe(struct platform_device *pdev) { struct dsa_platform_data *pd = pdev->dev.platform_data; struct net_device *dev; struct dsa_switch_tree *dst; - int i, ret; + int ret; pr_notice_once("Distributed Switch Architecture driver version %s\n", dsa_driver_version); @@ -752,42 +795,7 @@ static int dsa_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dst); - dst->pd = pd; - dst->master_netdev = dev; - dst->cpu_switch = -1; - dst->cpu_port = -1; - - for (i = 0; i < pd->nr_chips; i++) { - struct dsa_switch *ds; - - ds = dsa_switch_setup(dst, i, &pdev->dev, pd->chip[i].host_dev); - if (IS_ERR(ds)) { - netdev_err(dev, "[%d]: couldn't create dsa switch instance (error %ld)\n", - i, PTR_ERR(ds)); - continue; - } - - dst->ds[i] = ds; - if (ds->drv->poll_link != NULL) - dst->link_poll_needed = 1; - } - - /* - * If we use a tagging format that doesn't have an ethertype - * field, make sure that all packets from this point on get - * sent to the tag format's receive function. - */ - wmb(); - dev->dsa_ptr = (void *)dst; - - if (dst->link_poll_needed) { - INIT_WORK(&dst->link_poll_work, dsa_link_poll_work); - init_timer(&dst->link_poll_timer); - dst->link_poll_timer.data = (unsigned long)dst; - dst->link_poll_timer.function = dsa_link_poll_timer; - dst->link_poll_timer.expires = round_jiffies(jiffies + HZ); - add_timer(&dst->link_poll_timer); - } + dsa_setup_dst(dst, dev, &pdev->dev, pd); return 0; @@ -797,9 +805,8 @@ out: return ret; } -static int dsa_remove(struct platform_device *pdev) +static void dsa_remove_dst(struct dsa_switch_tree *dst) { - struct dsa_switch_tree *dst = platform_get_drvdata(pdev); int i; if (dst->link_poll_needed) @@ -813,7 +820,13 @@ static int dsa_remove(struct platform_device *pdev) if (ds != NULL) dsa_switch_destroy(ds); } +} +static int dsa_remove(struct platform_device *pdev) +{ + struct dsa_switch_tree *dst = platform_get_drvdata(pdev); + + dsa_remove_dst(dst); dsa_of_remove(&pdev->dev); return 0;