Commit bbed0bbd authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: tag_8021q: add VLANs to the master interface too

The whole purpose of tag_8021q is to send VLAN-tagged traffic to the
CPU, from which the driver can decode the source port and switch id.

Currently this only works if the VLAN filtering on the master is
disabled. Change that by explicitly adding code to tag_8021q.c to add
the VLANs corresponding to the tags to the filter of the master
interface.

Because we now need to call vlan_vid_add, then we also need to hold the
RTNL mutex. Propagate that requirement to the callers of dsa_8021q_setup
and modify the existing call sites as appropriate. Note that one call
path, sja1105_best_effort_vlan_filtering_set -> sja1105_vlan_filtering
-> sja1105_setup_8021q_tagging, was already holding this lock.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2209158c
...@@ -3038,7 +3038,11 @@ static int sja1105_setup(struct dsa_switch *ds) ...@@ -3038,7 +3038,11 @@ static int sja1105_setup(struct dsa_switch *ds)
* default, and that means vlan_filtering is 0 since they're not under * default, and that means vlan_filtering is 0 since they're not under
* a bridge, so it's safe to set up switch tagging at this time. * a bridge, so it's safe to set up switch tagging at this time.
*/ */
return sja1105_setup_8021q_tagging(ds, true); rtnl_lock();
rc = sja1105_setup_8021q_tagging(ds, true);
rtnl_unlock();
return rc;
} }
static void sja1105_teardown(struct dsa_switch *ds) static void sja1105_teardown(struct dsa_switch *ds)
...@@ -3532,6 +3536,7 @@ static int sja1105_probe(struct spi_device *spi) ...@@ -3532,6 +3536,7 @@ static int sja1105_probe(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
priv->dsa_8021q_ctx->ops = &sja1105_dsa_8021q_ops; priv->dsa_8021q_ctx->ops = &sja1105_dsa_8021q_ops;
priv->dsa_8021q_ctx->proto = htons(ETH_P_8021Q);
priv->dsa_8021q_ctx->ds = ds; priv->dsa_8021q_ctx->ds = ds;
INIT_LIST_HEAD(&priv->dsa_8021q_ctx->crosschip_links); INIT_LIST_HEAD(&priv->dsa_8021q_ctx->crosschip_links);
......
...@@ -31,6 +31,8 @@ struct dsa_8021q_context { ...@@ -31,6 +31,8 @@ struct dsa_8021q_context {
const struct dsa_8021q_ops *ops; const struct dsa_8021q_ops *ops;
struct dsa_switch *ds; struct dsa_switch *ds;
struct list_head crosschip_links; struct list_head crosschip_links;
/* EtherType of RX VID, used for filtering on master interface */
__be16 proto;
}; };
#define DSA_8021Q_N_SUBVLAN 8 #define DSA_8021Q_N_SUBVLAN 8
......
...@@ -215,7 +215,8 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port, ...@@ -215,7 +215,8 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port,
int upstream = dsa_upstream_port(ctx->ds, port); int upstream = dsa_upstream_port(ctx->ds, port);
u16 rx_vid = dsa_8021q_rx_vid(ctx->ds, port); u16 rx_vid = dsa_8021q_rx_vid(ctx->ds, port);
u16 tx_vid = dsa_8021q_tx_vid(ctx->ds, port); u16 tx_vid = dsa_8021q_tx_vid(ctx->ds, port);
int i, err; struct net_device *master;
int i, err, subvlan;
/* The CPU port is implicitly configured by /* The CPU port is implicitly configured by
* configuring the front-panel ports * configuring the front-panel ports
...@@ -223,6 +224,8 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port, ...@@ -223,6 +224,8 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port,
if (!dsa_is_user_port(ctx->ds, port)) if (!dsa_is_user_port(ctx->ds, port))
return 0; return 0;
master = dsa_to_port(ctx->ds, port)->cpu_dp->master;
/* Add this user port's RX VID to the membership list of all others /* Add this user port's RX VID to the membership list of all others
* (including itself). This is so that bridging will not be hindered. * (including itself). This is so that bridging will not be hindered.
* L2 forwarding rules still take precedence when there are no VLAN * L2 forwarding rules still take precedence when there are no VLAN
...@@ -261,6 +264,19 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port, ...@@ -261,6 +264,19 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port,
return err; return err;
} }
/* Add to the master's RX filter not only @rx_vid, but in fact
* the entire subvlan range, just in case this DSA switch might
* want to use sub-VLANs.
*/
for (subvlan = 0; subvlan < DSA_8021Q_N_SUBVLAN; subvlan++) {
u16 vid = dsa_8021q_rx_vid_subvlan(ctx->ds, port, subvlan);
if (enabled)
vlan_vid_add(master, ctx->proto, vid);
else
vlan_vid_del(master, ctx->proto, vid);
}
/* Finally apply the TX VID on this port and on the CPU port */ /* Finally apply the TX VID on this port and on the CPU port */
err = dsa_8021q_vid_apply(ctx, port, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED, err = dsa_8021q_vid_apply(ctx, port, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED,
enabled); enabled);
...@@ -285,6 +301,8 @@ int dsa_8021q_setup(struct dsa_8021q_context *ctx, bool enabled) ...@@ -285,6 +301,8 @@ int dsa_8021q_setup(struct dsa_8021q_context *ctx, bool enabled)
{ {
int rc, port; int rc, port;
ASSERT_RTNL();
for (port = 0; port < ctx->ds->num_ports; port++) { for (port = 0; port < ctx->ds->num_ports; port++) {
rc = dsa_8021q_setup_port(ctx, port, enabled); rc = dsa_8021q_setup_port(ctx, port, enabled);
if (rc < 0) { if (rc < 0) {
......
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