2019-10-31 02:10:28

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next v2 0/7] net: dsa: replace routing tables with a list

This branch gets rid of the ds->rtable static arrays in favor of
a single dst->rtable list. This allows us to move away from the
DSA_MAX_SWITCHES limitation and simplify the switch fabric setup.

Changes in v2:
- fix the reverse christmas for David

Vivien Didelot (7):
net: dsa: list DSA links in the fabric
net: dsa: remove ds->rtable
net: dsa: remove switch routing table setup code
net: dsa: remove the dst->ds array
net: dsa: remove tree functions related to switches
net: dsa: remove limitation of switch index value
net: dsa: tag_8021q: clarify index limitation

drivers/net/dsa/mv88e6xxx/chip.c | 8 +-
include/net/dsa.h | 39 +++++++---
net/dsa/dsa2.c | 121 +++++++++++++------------------
net/dsa/tag_8021q.c | 5 +-
4 files changed, 85 insertions(+), 88 deletions(-)

--
2.23.0


2019-10-31 02:10:28

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next v2 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 <[email protected]>
---
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 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst)

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;
--
2.23.0

2019-10-31 02:10:39

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next v2 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 <[email protected]>
---
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;
--
2.23.0

2019-10-31 02:10:50

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next v2 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 <[email protected]>
---
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)) {
--
2.23.0

2019-10-31 02:10:56

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next v2 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 <[email protected]>
---
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
--
2.23.0

2019-10-31 02:11:04

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next v2 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 <[email protected]>
---
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)
--
2.23.0

2019-10-31 02:12:21

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next v2 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 <[email protected]>
---
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);
}

--
2.23.0

2019-10-31 02:13:07

by Vivien Didelot

[permalink] [raw]
Subject: [PATCH net-next v2 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 <[email protected]>
---
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)
--
2.23.0

2019-10-31 22:54:58

by David Miller

[permalink] [raw]
Subject: Re: [PATCH net-next v2 0/7] net: dsa: replace routing tables with a list

From: Vivien Didelot <[email protected]>
Date: Wed, 30 Oct 2019 22:09:12 -0400

> This branch gets rid of the ds->rtable static arrays in favor of
> a single dst->rtable list. This allows us to move away from the
> DSA_MAX_SWITCHES limitation and simplify the switch fabric setup.
>
> Changes in v2:
> - fix the reverse christmas for David

Series applied, thanks Vivien.