Commit 2e554a7a authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller
Browse files

net: dsa: propagate switchdev vlan_filtering prepare phase to drivers



A driver may refuse to enable VLAN filtering for any reason beyond what
the DSA framework cares about, such as:
- having tc-flower rules that rely on the switch being VLAN-aware
- the particular switch does not support VLAN, even if the driver does
  (the DSA framework just checks for the presence of the .port_vlan_add
  and .port_vlan_del pointers)
- simply not supporting this configuration to be toggled at runtime

Currently, when a driver rejects a configuration it cannot support, it
does this from the commit phase, which triggers various warnings in
switchdev.

So propagate the prepare phase to drivers, to give them the ability to
refuse invalid configurations cleanly and avoid the warnings.

Since we need to modify all function prototypes and check for the
prepare phase from within the drivers, take that opportunity and move
the existing driver restrictions within the prepare phase where that is
possible and easy.

Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Hauke Mehrtens <hauke@hauke-m.de>
Cc: Woojung Huh <woojung.huh@microchip.com>
Cc: Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
Cc: Sean Wang <sean.wang@mediatek.com>
Cc: Landen Chao <Landen.Chao@mediatek.com>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Vivien Didelot <vivien.didelot@gmail.com>
Cc: Jonathan McDowell <noodles@earth.li>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c2568c8c
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -1374,10 +1374,14 @@ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
}
EXPORT_SYMBOL(b53_phylink_mac_link_up);

int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
		       struct switchdev_trans *trans)
{
	struct b53_device *dev = ds->priv;

	if (switchdev_trans_ph_prepare(trans))
		return 0;

	b53_enable_vlan(dev, dev->vlan_enabled, vlan_filtering);

	return 0;
+2 −1
Original line number Diff line number Diff line
@@ -347,7 +347,8 @@ void b53_phylink_mac_link_up(struct dsa_switch *ds, int port,
			     struct phy_device *phydev,
			     int speed, int duplex,
			     bool tx_pause, bool rx_pause);
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering);
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
		       struct switchdev_trans *trans);
int b53_vlan_prepare(struct dsa_switch *ds, int port,
		     const struct switchdev_obj_port_vlan *vlan);
void b53_vlan_add(struct dsa_switch *ds, int port,
+2 −1
Original line number Diff line number Diff line
@@ -190,7 +190,8 @@ static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,
}

static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,
					bool vlan_filtering)
					bool vlan_filtering,
					struct switchdev_trans *trans)
{
	dev_dbg(ds->dev, "%s: port: %d, vlan_filtering: %d\n",
		__func__, port, vlan_filtering);
+21 −5
Original line number Diff line number Diff line
@@ -736,15 +736,24 @@ static int gswip_pce_load_microcode(struct gswip_priv *priv)
}

static int gswip_port_vlan_filtering(struct dsa_switch *ds, int port,
				     bool vlan_filtering)
				     bool vlan_filtering,
				     struct switchdev_trans *trans)
{
	struct gswip_priv *priv = ds->priv;
	struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;

	/* Do not allow changing the VLAN filtering options while in bridge */
	if (!!(priv->port_vlan_filter & BIT(port)) != vlan_filtering && bridge)
	if (switchdev_trans_ph_prepare(trans)) {
		struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;

		if (!bridge)
			return 0;

		if (!!(priv->port_vlan_filter & BIT(port)) != vlan_filtering)
			return -EIO;

		return 0;
	}

	if (vlan_filtering) {
		/* Use port based VLAN tag */
		gswip_switch_mask(priv,
@@ -781,8 +790,15 @@ static int gswip_setup(struct dsa_switch *ds)

	/* disable port fetch/store dma on all ports */
	for (i = 0; i < priv->hw_info->max_ports; i++) {
		struct switchdev_trans trans;

		/* Skip the prepare phase, this shouldn't return an error
		 * during setup.
		 */
		trans.ph_prepare = false;

		gswip_port_disable(ds, i);
		gswip_port_vlan_filtering(ds, i, false);
		gswip_port_vlan_filtering(ds, i, false, &trans);
	}

	/* enable Switch */
+5 −1
Original line number Diff line number Diff line
@@ -782,10 +782,14 @@ static void ksz8795_flush_dyn_mac_table(struct ksz_device *dev, int port)
}

static int ksz8795_port_vlan_filtering(struct dsa_switch *ds, int port,
				       bool flag)
				       bool flag,
				       struct switchdev_trans *trans)
{
	struct ksz_device *dev = ds->priv;

	if (switchdev_trans_ph_prepare(trans))
		return 0;

	ksz_cfg(dev, S_MIRROR_CTRL, SW_VLAN_ENABLE, flag);

	return 0;
Loading