From c5f51765a1f60b701840544faf3ca63204b8dc3c Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 30 Oct 2019 22:09:13 -0400 Subject: [PATCH 1/7] net: dsa: list DSA links in the fabric Implement a new list of DSA links in the switch fabric itself, to provide an alterative to the ds->rtable static arrays. At the same time, provide a new dsa_routing_port() helper to abstract the usage of ds->rtable in drivers. If there's no port to reach a given device, return the first invalid port, ds->num_ports. This avoids potential signedness errors or the need to define special values. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 8 +++---- include/net/dsa.h | 29 +++++++++++++++++++++- net/dsa/dsa2.c | 41 +++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 619cd081339e..66de492117ad 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1143,6 +1143,7 @@ static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) { + struct dsa_switch *ds = chip->ds; int target, port; int err; @@ -1151,10 +1152,9 @@ static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) /* Initialize the routing port to the 32 possible target devices */ for (target = 0; target < 32; target++) { - port = 0x1f; - if (target < DSA_MAX_SWITCHES) - if (chip->ds->rtable[target] != DSA_RTABLE_NONE) - port = chip->ds->rtable[target]; + port = dsa_routing_port(ds, target); + if (port == ds->num_ports) + port = 0x1f; err = mv88e6xxx_g2_device_mapping_write(chip, target, port); if (err) diff --git a/include/net/dsa.h b/include/net/dsa.h index 9aba326abb64..3d7366d634d8 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -123,6 +123,9 @@ struct dsa_switch_tree { /* List of switch ports */ struct list_head ports; + /* List of DSA links composing the routing table */ + struct list_head rtable; + /* * Data for the individual switch chips. */ @@ -214,6 +217,17 @@ struct dsa_port { bool setup; }; +/* TODO: ideally DSA ports would have a single dp->link_dp member, + * and no dst->rtable nor this struct dsa_link would be needed, + * but this would require some more complex tree walking, + * so keep it stupid at the moment and list them all. + */ +struct dsa_link { + struct dsa_port *dp; + struct dsa_port *link_dp; + struct list_head list; +}; + struct dsa_switch { bool setup; @@ -324,6 +338,19 @@ static inline u32 dsa_user_ports(struct dsa_switch *ds) return mask; } +/* Return the local port used to reach an arbitrary switch device */ +static inline unsigned int dsa_routing_port(struct dsa_switch *ds, int device) +{ + struct dsa_switch_tree *dst = ds->dst; + struct dsa_link *dl; + + list_for_each_entry(dl, &dst->rtable, list) + if (dl->dp->ds == ds && dl->link_dp->ds->index == device) + return dl->dp->index; + + return ds->num_ports; +} + /* Return the local port used to reach an arbitrary switch port */ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, int port) @@ -331,7 +358,7 @@ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, if (device == ds->index) return port; else - return ds->rtable[device]; + return dsa_routing_port(ds, device); } /* Return the local port used to reach the dedicated CPU port */ diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index e7aae96b54bb..222d7dbfcfea 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -45,6 +45,8 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index) dst->index = index; + INIT_LIST_HEAD(&dst->rtable); + INIT_LIST_HEAD(&dst->ports); INIT_LIST_HEAD(&dst->list); @@ -122,6 +124,31 @@ static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst, return NULL; } +struct dsa_link *dsa_link_touch(struct dsa_port *dp, struct dsa_port *link_dp) +{ + struct dsa_switch *ds = dp->ds; + struct dsa_switch_tree *dst; + struct dsa_link *dl; + + dst = ds->dst; + + list_for_each_entry(dl, &dst->rtable, list) + if (dl->dp == dp && dl->link_dp == link_dp) + return dl; + + dl = kzalloc(sizeof(*dl), GFP_KERNEL); + if (!dl) + return NULL; + + dl->dp = dp; + dl->link_dp = link_dp; + + INIT_LIST_HEAD(&dl->list); + list_add_tail(&dl->list, &dst->rtable); + + return dl; +} + static bool dsa_port_setup_routing_table(struct dsa_port *dp) { struct dsa_switch *ds = dp->ds; @@ -129,6 +156,7 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp) struct device_node *dn = dp->dn; struct of_phandle_iterator it; struct dsa_port *link_dp; + struct dsa_link *dl; int err; of_for_each_phandle(&it, err, dn, "link", NULL, 0) { @@ -138,7 +166,11 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp) return false; } - ds->rtable[link_dp->ds->index] = dp->index; + dl = dsa_link_touch(dp, link_dp); + if (!dl) { + of_node_put(it.node); + return false; + } } return true; @@ -544,6 +576,8 @@ teardown_default_cpu: static void dsa_tree_teardown(struct dsa_switch_tree *dst) { + struct dsa_link *dl, *next; + if (!dst->setup) return; @@ -553,6 +587,11 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst) dsa_tree_teardown_default_cpu(dst); + list_for_each_entry_safe(dl, next, &dst->rtable, list) { + list_del(&dl->list); + kfree(dl); + } + pr_info("DSA: tree %d torn down\n", dst->index); dst->setup = false; From 96252b8e05326df072cd321159878aa4725c5bd4 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 30 Oct 2019 22:09:14 -0400 Subject: [PATCH 2/7] net: dsa: remove ds->rtable Drivers do not use the ds->rtable static arrays anymore, get rid of it. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- include/net/dsa.h | 7 ------- net/dsa/dsa2.c | 4 ---- 2 files changed, 11 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 3d7366d634d8..b46222adb5c2 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -258,13 +258,6 @@ struct dsa_switch { */ const struct dsa_switch_ops *ops; - /* - * An array of which element [a] indicates which port on this - * switch should be used to send packets to that are destined - * for switch a. Can be NULL if there is only one switch chip. - */ - s8 rtable[DSA_MAX_SWITCHES]; - /* * Slave mii_bus and devices for the individual ports. */ diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 222d7dbfcfea..efd7453f308e 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -181,10 +181,6 @@ static bool dsa_switch_setup_routing_table(struct dsa_switch *ds) struct dsa_switch_tree *dst = ds->dst; bool complete = true; struct dsa_port *dp; - int i; - - for (i = 0; i < DSA_MAX_SWITCHES; i++) - ds->rtable[i] = DSA_RTABLE_NONE; list_for_each_entry(dp, &dst->ports, list) { if (dp->ds == ds && dsa_port_is_dsa(dp)) { From 3774ecdb8ca201af770288d57997dbf6445eb3c8 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 30 Oct 2019 22:09:15 -0400 Subject: [PATCH 3/7] net: dsa: remove switch routing table setup code The dsa_switch structure has no routing table specific data to setup, so the switch fabric can directly walk its ports and initialize its routing table from them. This allows us to remove the dsa_switch_setup_routing_table function. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- net/dsa/dsa2.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index efd7453f308e..a887231fff13 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -176,14 +176,13 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp) return true; } -static bool dsa_switch_setup_routing_table(struct dsa_switch *ds) +static bool dsa_tree_setup_routing_table(struct dsa_switch_tree *dst) { - struct dsa_switch_tree *dst = ds->dst; bool complete = true; struct dsa_port *dp; list_for_each_entry(dp, &dst->ports, list) { - if (dp->ds == ds && dsa_port_is_dsa(dp)) { + if (dsa_port_is_dsa(dp)) { complete = dsa_port_setup_routing_table(dp); if (!complete) break; @@ -193,25 +192,6 @@ static bool dsa_switch_setup_routing_table(struct dsa_switch *ds) return complete; } -static bool dsa_tree_setup_routing_table(struct dsa_switch_tree *dst) -{ - struct dsa_switch *ds; - bool complete = true; - int device; - - for (device = 0; device < DSA_MAX_SWITCHES; device++) { - ds = dst->ds[device]; - if (!ds) - continue; - - complete = dsa_switch_setup_routing_table(ds); - if (!complete) - break; - } - - return complete; -} - static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst) { struct dsa_port *dp; From 9c8ad1ab66b577526a4c89e4a222e0fac431a2d6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 30 Oct 2019 22:09:16 -0400 Subject: [PATCH 4/7] net: dsa: remove the dst->ds array Now that the DSA ports are listed in the switch fabric, there is no need to store the dsa_switch structures from the drivers in the fabric anymore. So get rid of the dst->ds static array. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- include/net/dsa.h | 5 ----- net/dsa/dsa2.c | 7 ------- 2 files changed, 12 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index b46222adb5c2..e4c697b95c70 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -125,11 +125,6 @@ struct dsa_switch_tree { /* List of DSA links composing the routing table */ struct list_head rtable; - - /* - * Data for the individual switch chips. - */ - struct dsa_switch *ds[DSA_MAX_SWITCHES]; }; /* TC matchall action types, only mirroring for now */ diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index a887231fff13..92e71b12b729 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -578,25 +578,18 @@ static void dsa_tree_remove_switch(struct dsa_switch_tree *dst, { dsa_tree_teardown(dst); - dst->ds[index] = NULL; dsa_tree_put(dst); } static int dsa_tree_add_switch(struct dsa_switch_tree *dst, struct dsa_switch *ds) { - unsigned int index = ds->index; int err; - if (dst->ds[index]) - return -EBUSY; - dsa_tree_get(dst); - dst->ds[index] = ds; err = dsa_tree_setup(dst); if (err) { - dst->ds[index] = NULL; dsa_tree_put(dst); } From 8e5cb84c67e085ad4d8005dcecba3201f2b54504 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 30 Oct 2019 22:09:17 -0400 Subject: [PATCH 5/7] net: dsa: remove tree functions related to switches The DSA fabric setup code has been simplified a lot so get rid of the dsa_tree_remove_switch, dsa_tree_add_switch and dsa_switch_add helpers, and keep the code simple with only the dsa_switch_probe and dsa_switch_remove functions. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- net/dsa/dsa2.c | 43 ++++++++++--------------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 92e71b12b729..371f15042dad 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -573,29 +573,6 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst) dst->setup = false; } -static void dsa_tree_remove_switch(struct dsa_switch_tree *dst, - unsigned int index) -{ - dsa_tree_teardown(dst); - - dsa_tree_put(dst); -} - -static int dsa_tree_add_switch(struct dsa_switch_tree *dst, - struct dsa_switch *ds) -{ - int err; - - dsa_tree_get(dst); - - err = dsa_tree_setup(dst); - if (err) { - dsa_tree_put(dst); - } - - return err; -} - static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) { struct dsa_switch_tree *dst = ds->dst; @@ -846,15 +823,9 @@ static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd) return dsa_switch_parse_ports(ds, cd); } -static int dsa_switch_add(struct dsa_switch *ds) -{ - struct dsa_switch_tree *dst = ds->dst; - - return dsa_tree_add_switch(dst, ds); -} - static int dsa_switch_probe(struct dsa_switch *ds) { + struct dsa_switch_tree *dst; struct dsa_chip_data *pdata; struct device_node *np; int err; @@ -878,7 +849,13 @@ static int dsa_switch_probe(struct dsa_switch *ds) if (err) return err; - return dsa_switch_add(ds); + dst = ds->dst; + dsa_tree_get(dst); + err = dsa_tree_setup(dst); + if (err) + dsa_tree_put(dst); + + return err; } int dsa_register_switch(struct dsa_switch *ds) @@ -897,7 +874,6 @@ EXPORT_SYMBOL_GPL(dsa_register_switch); static void dsa_switch_remove(struct dsa_switch *ds) { struct dsa_switch_tree *dst = ds->dst; - unsigned int index = ds->index; struct dsa_port *dp, *next; list_for_each_entry_safe(dp, next, &dst->ports, list) { @@ -905,7 +881,8 @@ static void dsa_switch_remove(struct dsa_switch *ds) kfree(dp); } - dsa_tree_remove_switch(dst, index); + dsa_tree_teardown(dst); + dsa_tree_put(dst); } void dsa_unregister_switch(struct dsa_switch *ds) From 27d4d19d7c82b3fd9d09ac9e2cd73c70ed4ca4b2 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 30 Oct 2019 22:09:18 -0400 Subject: [PATCH 6/7] net: dsa: remove limitation of switch index value Because there is no static array describing the links between switches anymore, we have no reason to force a limitation of the index value set by the device tree. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- net/dsa/dsa2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 371f15042dad..ff2fa3950c62 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -711,8 +711,6 @@ static int dsa_switch_parse_member_of(struct dsa_switch *ds, return sz; ds->index = m[1]; - if (ds->index >= DSA_MAX_SWITCHES) - return -EINVAL; ds->dst = dsa_tree_touch(m[0]); if (!ds->dst) From fcee85f19f39d1b98b2674c2a9e57348fe803252 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 30 Oct 2019 22:09:19 -0400 Subject: [PATCH 7/7] net: dsa: tag_8021q: clarify index limitation Now that there's no restriction from the DSA core side regarding the switch IDs and port numbers, only tag_8021q which is currently reserving 3 bits for the switch ID and 4 bits for the port number, has limitation for these values. Update their descriptions to reflect that. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- net/dsa/tag_8021q.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c index bf91fc55fc44..bc5cb91bf052 100644 --- a/net/dsa/tag_8021q.c +++ b/net/dsa/tag_8021q.c @@ -31,15 +31,14 @@ * Must be transmitted as zero and ignored on receive. * * SWITCH_ID - VID[8:6]: - * Index of switch within DSA tree. Must be between 0 and - * DSA_MAX_SWITCHES - 1. + * Index of switch within DSA tree. Must be between 0 and 7. * * RSV - VID[5:4]: * To be used for further expansion of PORT or for other purposes. * Must be transmitted as zero and ignored on receive. * * PORT - VID[3:0]: - * Index of switch port. Must be between 0 and DSA_MAX_PORTS - 1. + * Index of switch port. Must be between 0 and 15. */ #define DSA_8021Q_DIR_SHIFT 10