net: mscc: ocelot: deny changing the native VLAN from the prepare phase
authorVladimir Oltean <vladimir.oltean@nxp.com>
Sat, 31 Oct 2020 10:29:15 +0000 (12:29 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 3 Nov 2020 01:09:07 +0000 (17:09 -0800)
Put the preparation phase of switchdev VLAN objects to some good use,
and move the check we already had, for preventing the existence of more
than one egress-untagged VLAN per port, to the preparation phase of the
addition.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/ocelot/felix.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/mscc/ocelot_net.c
include/soc/mscc/ocelot.h

index f791860..3848f6b 100644 (file)
@@ -112,10 +112,21 @@ static void felix_bridge_leave(struct dsa_switch *ds, int port,
        ocelot_port_bridge_leave(ocelot, port, br);
 }
 
-/* This callback needs to be present */
 static int felix_vlan_prepare(struct dsa_switch *ds, int port,
                              const struct switchdev_obj_port_vlan *vlan)
 {
+       struct ocelot *ocelot = ds->priv;
+       u16 vid, flags = vlan->flags;
+       int err;
+
+       for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+               err = ocelot_vlan_prepare(ocelot, port, vid,
+                                         flags & BRIDGE_VLAN_INFO_PVID,
+                                         flags & BRIDGE_VLAN_INFO_UNTAGGED);
+               if (err)
+                       return err;
+       }
+
        return 0;
 }
 
index 60186fc..2632fe2 100644 (file)
@@ -147,21 +147,12 @@ static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask)
        return ocelot_vlant_wait_for_completion(ocelot);
 }
 
-static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
-                                      struct ocelot_vlan native_vlan)
+static void ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
+                                       struct ocelot_vlan native_vlan)
 {
        struct ocelot_port *ocelot_port = ocelot->ports[port];
        u32 val = 0;
 
-       /* Deny changing the native VLAN, but always permit deleting it */
-       if (ocelot_port->native_vlan.vid != native_vlan.vid &&
-           ocelot_port->native_vlan.valid && native_vlan.valid) {
-               dev_err(ocelot->dev,
-                       "Port already has a native VLAN: %d\n",
-                       ocelot_port->native_vlan.vid);
-               return -EBUSY;
-       }
-
        ocelot_port->native_vlan = native_vlan;
 
        ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(native_vlan.vid),
@@ -182,8 +173,6 @@ static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port,
        ocelot_rmw_gix(ocelot, val,
                       REW_TAG_CFG_TAG_CFG_M,
                       REW_TAG_CFG, port);
-
-       return 0;
 }
 
 /* Default vlan to clasify for untagged frames (may be zero) */
@@ -259,6 +248,24 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
 }
 EXPORT_SYMBOL(ocelot_port_vlan_filtering);
 
+int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid,
+                       bool untagged)
+{
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+       /* Deny changing the native VLAN, but always permit deleting it */
+       if (untagged && ocelot_port->native_vlan.vid != vid &&
+           ocelot_port->native_vlan.valid) {
+               dev_err(ocelot->dev,
+                       "Port already has a native VLAN: %d\n",
+                       ocelot_port->native_vlan.vid);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(ocelot_vlan_prepare);
+
 int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
                    bool untagged)
 {
@@ -285,9 +292,7 @@ int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
 
                native_vlan.vid = vid;
                native_vlan.valid = true;
-               ret = ocelot_port_set_native_vlan(ocelot, port, native_vlan);
-               if (ret)
-                       return ret;
+               ocelot_port_set_native_vlan(ocelot, port, native_vlan);
        }
 
        return 0;
@@ -1193,7 +1198,9 @@ int ocelot_port_bridge_leave(struct ocelot *ocelot, int port,
                return ret;
 
        ocelot_port_set_pvid(ocelot, port, pvid);
-       return ocelot_port_set_native_vlan(ocelot, port, native_vlan);
+       ocelot_port_set_native_vlan(ocelot, port, native_vlan);
+
+       return 0;
 }
 EXPORT_SYMBOL(ocelot_port_bridge_leave);
 
index cf5c2a0..c65ae6f 100644 (file)
@@ -206,6 +206,17 @@ static void ocelot_port_adjust_link(struct net_device *dev)
        ocelot_adjust_link(ocelot, port, dev->phydev);
 }
 
+static int ocelot_vlan_vid_prepare(struct net_device *dev, u16 vid, bool pvid,
+                                  bool untagged)
+{
+       struct ocelot_port_private *priv = netdev_priv(dev);
+       struct ocelot_port *ocelot_port = &priv->port;
+       struct ocelot *ocelot = ocelot_port->ocelot;
+       int port = priv->chip_port;
+
+       return ocelot_vlan_prepare(ocelot, port, vid, pvid, untagged);
+}
+
 static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid,
                               bool untagged)
 {
@@ -812,9 +823,14 @@ static int ocelot_port_obj_add_vlan(struct net_device *dev,
        u16 vid;
 
        for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
-               ret = ocelot_vlan_vid_add(dev, vid,
-                                         vlan->flags & BRIDGE_VLAN_INFO_PVID,
-                                         vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
+               bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+               bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+
+               if (switchdev_trans_ph_prepare(trans))
+                       ret = ocelot_vlan_vid_prepare(dev, vid, pvid,
+                                                     untagged);
+               else
+                       ret = ocelot_vlan_vid_add(dev, vid, pvid, untagged);
                if (ret)
                        return ret;
        }
index 67c2af1..ea1de18 100644 (file)
@@ -747,6 +747,8 @@ int ocelot_fdb_add(struct ocelot *ocelot, int port,
                   const unsigned char *addr, u16 vid);
 int ocelot_fdb_del(struct ocelot *ocelot, int port,
                   const unsigned char *addr, u16 vid);
+int ocelot_vlan_prepare(struct ocelot *ocelot, int port, u16 vid, bool pvid,
+                       bool untagged);
 int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid,
                    bool untagged);
 int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid);