diff options
author | David S. Miller <davem@davemloft.net> | 2019-04-30 23:05:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-04-30 23:05:30 -0400 |
commit | 492593010de4a323a7b98dffb0ba6567456b5ba0 (patch) | |
tree | 69566e08f1d74a449e6df3d1444ef89925084780 /drivers/net/dsa | |
parent | a658a3f2ecbabba60dafa9ba94f12fc25c18474f (diff) | |
parent | 314f76d7a68bab0516aa52877944e6aacfa0fc3f (diff) |
Merge branch 'dsa-core-vlan'
Vladimir Oltean says:
====================
Improvements to DSA core VLAN manipulation
In preparation of submitting the NXP SJA1105 driver, the Broadcom b53
and Mediatek mt7530 drivers have been found to apply some VLAN
workarounds that are needed in the new driver as well.
Therefore this patchset is mostly simply promoting the DSA driver
workarounds for VLAN to the generic code.
The b53 driver was applying a few workarounds in order to convince DSA
that its vlan_filtering setting is not really per-port. This is now
simply set by the driver via a DSA variable at probe time. The sja1105
driver will be a second user of this.
The mt7530 was also keeping track of when the .port_vlan_filtering
callback was being called. Remove the kept state from this driver
and simplify dealing with vlan_filtering in the generic case.
TODO:
Find the best way to deal generically with the situation described below
(discussion at https://lkml.org/lkml/2019/4/16/1355):
> > +Segregating the switch ports in multiple bridges is supported (e.g. 2 + 2), but
> > +all bridges should have the same level of VLAN awareness (either both have
> > +``vlan_filtering`` 0, or both 1). Also an inevitable limitation of the fact
> > +that VLAN awareness is global at the switch level is that once a bridge with
> > +``vlan_filtering`` enslaves at least one switch port, the other un-bridged
> > +ports are no longer available for standalone traffic termination.
>
> That is quite a limitation that I don't think I had fully grasped until
> reading your different patches. Since enslaving ports into a bridge
> comes after the network device was already made available for use, maybe
> you should force the carrier down or something along those lines as soon
> as a port is enslaved into a bridge with vlan_filtering=1 to make this
> more predictable for the user?
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa')
-rw-r--r-- | drivers/net/dsa/b53/b53_common.c | 34 | ||||
-rw-r--r-- | drivers/net/dsa/b53/b53_priv.h | 1 | ||||
-rw-r--r-- | drivers/net/dsa/mt7530.c | 20 | ||||
-rw-r--r-- | drivers/net/dsa/mt7530.h | 1 |
4 files changed, 18 insertions, 38 deletions
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 0852e5e08177..c8040ecf4425 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -428,7 +428,6 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable, b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); dev->vlan_enabled = enable; - dev->vlan_filtering_enabled = enable_filtering; } static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100) @@ -665,7 +664,7 @@ int b53_configure_vlan(struct dsa_switch *ds) b53_do_vlan_op(dev, VTA_CMD_CLEAR); } - b53_enable_vlan(dev, false, dev->vlan_filtering_enabled); + b53_enable_vlan(dev, false, ds->vlan_filtering); b53_for_each_port(dev, i) b53_write16(dev, B53_VLAN_PAGE, @@ -966,6 +965,13 @@ static int b53_setup(struct dsa_switch *ds) b53_disable_port(ds, port); } + /* Let DSA handle the case were multiple bridges span the same switch + * device and different VLAN awareness settings are requested, which + * would be breaking filtering semantics for any of the other bridge + * devices. (not hardware supported) + */ + ds->vlan_filtering_is_global = true; + return ret; } @@ -1275,35 +1281,17 @@ EXPORT_SYMBOL(b53_phylink_mac_link_up); int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) { struct b53_device *dev = ds->priv; - struct net_device *bridge_dev; - unsigned int i; u16 pvid, new_pvid; - /* Handle the case were multiple bridges span the same switch device - * and one of them has a different setting than what is being requested - * which would be breaking filtering semantics for any of the other - * bridge devices. - */ - b53_for_each_port(dev, i) { - bridge_dev = dsa_to_port(ds, i)->bridge_dev; - if (bridge_dev && - bridge_dev != dsa_to_port(ds, port)->bridge_dev && - br_vlan_enabled(bridge_dev) != vlan_filtering) { - netdev_err(bridge_dev, - "VLAN filtering is global to the switch!\n"); - return -EINVAL; - } - } - b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid); new_pvid = pvid; - if (dev->vlan_filtering_enabled && !vlan_filtering) { + if (!vlan_filtering) { /* Filtering is currently enabled, use the default PVID since * the bridge does not expect tagging anymore */ dev->ports[port].pvid = pvid; new_pvid = b53_default_pvid(dev); - } else if (!dev->vlan_filtering_enabled && vlan_filtering) { + } else { /* Filtering is currently disabled, restore the previous PVID */ new_pvid = dev->ports[port].pvid; } @@ -1329,7 +1317,7 @@ int b53_vlan_prepare(struct dsa_switch *ds, int port, if (vlan->vid_end > dev->num_vlans) return -ERANGE; - b53_enable_vlan(dev, true, dev->vlan_filtering_enabled); + b53_enable_vlan(dev, true, ds->vlan_filtering); return 0; } diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index e3441dcf2d21..f25bc80c4ffc 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -139,7 +139,6 @@ struct b53_device { unsigned int num_vlans; struct b53_vlan *vlans; bool vlan_enabled; - bool vlan_filtering_enabled; unsigned int num_ports; struct b53_port *ports; }; diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 7357b4fc0185..8d531c5f21f3 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -828,11 +828,9 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port) mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK, VLAN_ATTR(MT7530_VLAN_TRANSPARENT)); - priv->ports[port].vlan_filtering = false; - for (i = 0; i < MT7530_NUM_PORTS; i++) { if (dsa_is_user_port(ds, i) && - priv->ports[i].vlan_filtering) { + dsa_port_is_vlan_filtering(&ds->ports[i])) { all_user_ports_removed = false; break; } @@ -891,8 +889,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, * And the other port's port matrix cannot be broken when the * other port is still a VLAN-aware port. */ - if (!priv->ports[i].vlan_filtering && - dsa_is_user_port(ds, i) && i != port) { + if (dsa_is_user_port(ds, i) && i != port && + !dsa_port_is_vlan_filtering(&ds->ports[i])) { if (dsa_to_port(ds, i)->bridge_dev != bridge) continue; if (priv->ports[i].enable) @@ -910,8 +908,6 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, PCR_MATRIX(BIT(MT7530_CPU_PORT))); priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); - mt7530_port_set_vlan_unaware(ds, port); - mutex_unlock(&priv->reg_mutex); } @@ -1013,10 +1009,6 @@ static int mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering) { - struct mt7530_priv *priv = ds->priv; - - priv->ports[port].vlan_filtering = vlan_filtering; - if (vlan_filtering) { /* The port is being kept as VLAN-unaware port when bridge is * set up with vlan_filtering not being set, Otherwise, the @@ -1025,6 +1017,8 @@ mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, */ mt7530_port_set_vlan_aware(ds, port); mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT); + } else { + mt7530_port_set_vlan_unaware(ds, port); } return 0; @@ -1139,7 +1133,7 @@ mt7530_port_vlan_add(struct dsa_switch *ds, int port, /* The port is kept as VLAN-unaware if bridge with vlan_filtering not * being set. */ - if (!priv->ports[port].vlan_filtering) + if (!dsa_port_is_vlan_filtering(&ds->ports[port])) return; mutex_lock(&priv->reg_mutex); @@ -1170,7 +1164,7 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port, /* The port is kept as VLAN-unaware if bridge with vlan_filtering not * being set. */ - if (!priv->ports[port].vlan_filtering) + if (!dsa_port_is_vlan_filtering(&ds->ports[port])) return 0; mutex_lock(&priv->reg_mutex); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index a95ed958df5b..1eec7bdc283a 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -410,7 +410,6 @@ struct mt7530_port { bool enable; u32 pm; u16 pvid; - bool vlan_filtering; }; /* struct mt7530_priv - This is the main data structure for holding the state |