Commit e43ea83c authored by David S. Miller's avatar David S. Miller

Merge branch 'net-dsa-replace-routing-tables-with-a-list'

Vivien Didelot says:

====================
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
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5c26c1d6 fcee85f1
...@@ -1143,6 +1143,7 @@ static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) ...@@ -1143,6 +1143,7 @@ static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip)
static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
{ {
struct dsa_switch *ds = chip->ds;
int target, port; int target, port;
int err; int err;
...@@ -1151,10 +1152,9 @@ static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) ...@@ -1151,10 +1152,9 @@ static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip)
/* Initialize the routing port to the 32 possible target devices */ /* Initialize the routing port to the 32 possible target devices */
for (target = 0; target < 32; target++) { for (target = 0; target < 32; target++) {
port = 0x1f; port = dsa_routing_port(ds, target);
if (target < DSA_MAX_SWITCHES) if (port == ds->num_ports)
if (chip->ds->rtable[target] != DSA_RTABLE_NONE) port = 0x1f;
port = chip->ds->rtable[target];
err = mv88e6xxx_g2_device_mapping_write(chip, target, port); err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
if (err) if (err)
......
...@@ -123,10 +123,8 @@ struct dsa_switch_tree { ...@@ -123,10 +123,8 @@ struct dsa_switch_tree {
/* List of switch ports */ /* List of switch ports */
struct list_head ports; struct list_head ports;
/* /* List of DSA links composing the routing table */
* Data for the individual switch chips. struct list_head rtable;
*/
struct dsa_switch *ds[DSA_MAX_SWITCHES];
}; };
/* TC matchall action types, only mirroring for now */ /* TC matchall action types, only mirroring for now */
...@@ -214,6 +212,17 @@ struct dsa_port { ...@@ -214,6 +212,17 @@ struct dsa_port {
bool setup; 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 { struct dsa_switch {
bool setup; bool setup;
...@@ -244,13 +253,6 @@ struct dsa_switch { ...@@ -244,13 +253,6 @@ struct dsa_switch {
*/ */
const struct dsa_switch_ops *ops; 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. * Slave mii_bus and devices for the individual ports.
*/ */
...@@ -324,6 +326,19 @@ static inline u32 dsa_user_ports(struct dsa_switch *ds) ...@@ -324,6 +326,19 @@ static inline u32 dsa_user_ports(struct dsa_switch *ds)
return mask; 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 */ /* Return the local port used to reach an arbitrary switch port */
static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device,
int port) int port)
...@@ -331,7 +346,7 @@ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, ...@@ -331,7 +346,7 @@ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device,
if (device == ds->index) if (device == ds->index)
return port; return port;
else else
return ds->rtable[device]; return dsa_routing_port(ds, device);
} }
/* Return the local port used to reach the dedicated CPU port */ /* Return the local port used to reach the dedicated CPU port */
......
...@@ -45,6 +45,8 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index) ...@@ -45,6 +45,8 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index)
dst->index = index; dst->index = index;
INIT_LIST_HEAD(&dst->rtable);
INIT_LIST_HEAD(&dst->ports); INIT_LIST_HEAD(&dst->ports);
INIT_LIST_HEAD(&dst->list); INIT_LIST_HEAD(&dst->list);
...@@ -122,6 +124,31 @@ static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst, ...@@ -122,6 +124,31 @@ static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst,
return NULL; 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) static bool dsa_port_setup_routing_table(struct dsa_port *dp)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
...@@ -129,6 +156,7 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp) ...@@ -129,6 +156,7 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp)
struct device_node *dn = dp->dn; struct device_node *dn = dp->dn;
struct of_phandle_iterator it; struct of_phandle_iterator it;
struct dsa_port *link_dp; struct dsa_port *link_dp;
struct dsa_link *dl;
int err; int err;
of_for_each_phandle(&it, err, dn, "link", NULL, 0) { of_for_each_phandle(&it, err, dn, "link", NULL, 0) {
...@@ -138,24 +166,23 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp) ...@@ -138,24 +166,23 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp)
return false; 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; 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; bool complete = true;
struct dsa_port *dp; 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) { 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); complete = dsa_port_setup_routing_table(dp);
if (!complete) if (!complete)
break; break;
...@@ -165,25 +192,6 @@ static bool dsa_switch_setup_routing_table(struct dsa_switch *ds) ...@@ -165,25 +192,6 @@ static bool dsa_switch_setup_routing_table(struct dsa_switch *ds)
return complete; 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) static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
{ {
struct dsa_port *dp; struct dsa_port *dp;
...@@ -544,6 +552,8 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst) ...@@ -544,6 +552,8 @@ static int dsa_tree_setup(struct dsa_switch_tree *dst)
static void dsa_tree_teardown(struct dsa_switch_tree *dst) static void dsa_tree_teardown(struct dsa_switch_tree *dst)
{ {
struct dsa_link *dl, *next;
if (!dst->setup) if (!dst->setup)
return; return;
...@@ -553,41 +563,16 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst) ...@@ -553,41 +563,16 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst)
dsa_tree_teardown_default_cpu(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); pr_info("DSA: tree %d torn down\n", dst->index);
dst->setup = false; dst->setup = false;
} }
static void dsa_tree_remove_switch(struct dsa_switch_tree *dst,
unsigned int index)
{
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);
}
return err;
}
static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
{ {
struct dsa_switch_tree *dst = ds->dst; struct dsa_switch_tree *dst = ds->dst;
...@@ -726,8 +711,6 @@ static int dsa_switch_parse_member_of(struct dsa_switch *ds, ...@@ -726,8 +711,6 @@ static int dsa_switch_parse_member_of(struct dsa_switch *ds,
return sz; return sz;
ds->index = m[1]; ds->index = m[1];
if (ds->index >= DSA_MAX_SWITCHES)
return -EINVAL;
ds->dst = dsa_tree_touch(m[0]); ds->dst = dsa_tree_touch(m[0]);
if (!ds->dst) if (!ds->dst)
...@@ -838,15 +821,9 @@ static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd) ...@@ -838,15 +821,9 @@ static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd)
return dsa_switch_parse_ports(ds, 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) static int dsa_switch_probe(struct dsa_switch *ds)
{ {
struct dsa_switch_tree *dst;
struct dsa_chip_data *pdata; struct dsa_chip_data *pdata;
struct device_node *np; struct device_node *np;
int err; int err;
...@@ -870,7 +847,13 @@ static int dsa_switch_probe(struct dsa_switch *ds) ...@@ -870,7 +847,13 @@ static int dsa_switch_probe(struct dsa_switch *ds)
if (err) if (err)
return 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) int dsa_register_switch(struct dsa_switch *ds)
...@@ -889,7 +872,6 @@ EXPORT_SYMBOL_GPL(dsa_register_switch); ...@@ -889,7 +872,6 @@ EXPORT_SYMBOL_GPL(dsa_register_switch);
static void dsa_switch_remove(struct dsa_switch *ds) static void dsa_switch_remove(struct dsa_switch *ds)
{ {
struct dsa_switch_tree *dst = ds->dst; struct dsa_switch_tree *dst = ds->dst;
unsigned int index = ds->index;
struct dsa_port *dp, *next; struct dsa_port *dp, *next;
list_for_each_entry_safe(dp, next, &dst->ports, list) { list_for_each_entry_safe(dp, next, &dst->ports, list) {
...@@ -897,7 +879,8 @@ static void dsa_switch_remove(struct dsa_switch *ds) ...@@ -897,7 +879,8 @@ static void dsa_switch_remove(struct dsa_switch *ds)
kfree(dp); kfree(dp);
} }
dsa_tree_remove_switch(dst, index); dsa_tree_teardown(dst);
dsa_tree_put(dst);
} }
void dsa_unregister_switch(struct dsa_switch *ds) void dsa_unregister_switch(struct dsa_switch *ds)
......
...@@ -31,15 +31,14 @@ ...@@ -31,15 +31,14 @@
* Must be transmitted as zero and ignored on receive. * Must be transmitted as zero and ignored on receive.
* *
* SWITCH_ID - VID[8:6]: * SWITCH_ID - VID[8:6]:
* Index of switch within DSA tree. Must be between 0 and * Index of switch within DSA tree. Must be between 0 and 7.
* DSA_MAX_SWITCHES - 1.
* *
* RSV - VID[5:4]: * RSV - VID[5:4]:
* To be used for further expansion of PORT or for other purposes. * To be used for further expansion of PORT or for other purposes.
* Must be transmitted as zero and ignored on receive. * Must be transmitted as zero and ignored on receive.
* *
* PORT - VID[3:0]: * 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 #define DSA_8021Q_DIR_SHIFT 10
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment