diff options
author | Vladimir Oltean <vladimir.oltean@nxp.com> | 2021-07-19 20:14:48 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-07-20 06:36:42 -0700 |
commit | d7b1fd520d5d4271f4ab9b1671afbdcd868039d3 (patch) | |
tree | 26c90bdeecd753820ed8989a9fb37c489838a9f3 /drivers/net/dsa/ocelot/felix.c | |
parent | 8b6e638b4be2ad77f61fb93b4e1776c6ccc2edab (diff) |
net: dsa: let the core manage the tag_8021q context
The basic problem description is as follows:
Be there 3 switches in a daisy chain topology:
|
sw0p0 sw0p1 sw0p2 sw0p3 sw0p4
[ user ] [ user ] [ user ] [ dsa ] [ cpu ]
|
+---------+
|
sw1p0 sw1p1 sw1p2 sw1p3 sw1p4
[ user ] [ user ] [ user ] [ dsa ] [ dsa ]
|
+---------+
|
sw2p0 sw2p1 sw2p2 sw2p3 sw2p4
[ user ] [ user ] [ user ] [ user ] [ dsa ]
The CPU will not be able to ping through the user ports of the
bottom-most switch (like for example sw2p0), simply because tag_8021q
was not coded up for this scenario - it has always assumed DSA switch
trees with a single switch.
To add support for the topology above, we must admit that the RX VLAN of
sw2p0 must be added on some ports of switches 0 and 1 as well. This is
in fact a textbook example of thing that can use the cross-chip notifier
framework that DSA has set up in switch.c.
There is only one problem: core DSA (switch.c) is not able right now to
make the connection between a struct dsa_switch *ds and a struct
dsa_8021q_context *ctx. Right now, it is drivers who call into
tag_8021q.c and always provide a struct dsa_8021q_context *ctx pointer,
and tag_8021q.c calls them back with the .tag_8021q_vlan_{add,del}
methods.
But with cross-chip notifiers, it is possible for tag_8021q to call
drivers without drivers having ever asked for anything. A good example
is right above: when sw2p0 wants to set itself up for tag_8021q,
the .tag_8021q_vlan_add method needs to be called for switches 1 and 0,
so that they transport sw2p0's VLANs towards the CPU without dropping
them.
So instead of letting drivers manage the tag_8021q context, add a
tag_8021q_ctx pointer inside of struct dsa_switch, which will be
populated when dsa_tag_8021q_register() returns success.
The patch is fairly long-winded because we are partly reverting commit
5899ee367ab3 ("net: dsa: tag_8021q: add a context structure") which made
the driver-facing tag_8021q API use "ctx" instead of "ds". Now that we
can access "ctx" directly from "ds", this is no longer needed.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa/ocelot/felix.c')
-rw-r--r-- | drivers/net/dsa/ocelot/felix.c | 22 |
1 files changed, 11 insertions, 11 deletions
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index b52cc381cdc1..9e4ae15aa4fb 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -425,14 +425,14 @@ static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu) ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_MC); ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_BC); - felix->dsa_8021q_ctx = dsa_tag_8021q_register(ds, &felix_tag_8021q_ops, - htons(ETH_P_8021AD)); - if (!felix->dsa_8021q_ctx) - return -ENOMEM; + err = dsa_tag_8021q_register(ds, &felix_tag_8021q_ops, + htons(ETH_P_8021AD)); + if (err) + return err; - err = dsa_8021q_setup(felix->dsa_8021q_ctx, true); + err = dsa_8021q_setup(ds, true); if (err) - goto out_free_dsa_8021_ctx; + goto out_tag_8021q_unregister; err = felix_setup_mmio_filtering(felix); if (err) @@ -441,9 +441,9 @@ static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu) return 0; out_teardown_dsa_8021q: - dsa_8021q_setup(felix->dsa_8021q_ctx, false); -out_free_dsa_8021_ctx: - dsa_tag_8021q_unregister(felix->dsa_8021q_ctx); + dsa_8021q_setup(ds, false); +out_tag_8021q_unregister: + dsa_tag_8021q_unregister(ds); return err; } @@ -458,11 +458,11 @@ static void felix_teardown_tag_8021q(struct dsa_switch *ds, int cpu) dev_err(ds->dev, "felix_teardown_mmio_filtering returned %d", err); - err = dsa_8021q_setup(felix->dsa_8021q_ctx, false); + err = dsa_8021q_setup(ds, false); if (err) dev_err(ds->dev, "dsa_8021q_setup returned %d", err); - dsa_tag_8021q_unregister(felix->dsa_8021q_ctx); + dsa_tag_8021q_unregister(ds); for (port = 0; port < ds->num_ports; port++) { if (dsa_is_unused_port(ds, port)) |