In order to support cross-chip operations, we need to inform each switch
driver when a port operation occurs in a DSA tree.

Implement tree-wide VLAN operations.

Signed-off-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com>
---
 drivers/net/dsa/mv88e6xxx.c | 12 +++++++++
 net/dsa/dsa_priv.h          |  8 ++++++
 net/dsa/slave.c             | 59 ++++++--------------------------------------
 net/dsa/tree.c              | 60 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 87 insertions(+), 52 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 7d29de3..8004d00 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1378,6 +1378,9 @@ int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, 
struct dsa_port *dp,
        u16 pvid;
        int err;
 
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        mutex_lock(&ps->smi_mutex);
 
        err = _mv88e6xxx_port_pvid_get(ds, dp->port, &pvid);
@@ -1835,6 +1838,9 @@ int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, 
struct dsa_port *dp,
 {
        int err;
 
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        /* If the requested port doesn't belong to the same bridge as the VLAN
         * members, do not support it (yet) and fallback to software VLAN.
         */
@@ -1874,6 +1880,9 @@ void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, 
struct dsa_port *dp,
        bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
        u16 vid;
 
+       if (dsa_port_is_external(dp, ds))
+               return;
+
        mutex_lock(&ps->smi_mutex);
 
        for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
@@ -1930,6 +1939,9 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, struct 
dsa_port *dp,
        u16 pvid, vid;
        int err = 0;
 
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        mutex_lock(&ps->smi_mutex);
 
        err = _mv88e6xxx_port_pvid_get(ds, dp->port, &pvid);
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index e8765c3..d743d6a 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -60,6 +60,14 @@ int dsa_tree_port_fdb_del(struct dsa_switch_tree *dst, 
struct dsa_port *dp,
 int dsa_tree_port_fdb_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
                           struct switchdev_obj_port_fdb *fdb,
                           switchdev_obj_dump_cb_t *cb);
+int dsa_tree_port_vlan_add(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                          const struct switchdev_obj_port_vlan *vlan,
+                          struct switchdev_trans *trans);
+int dsa_tree_port_vlan_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                          const struct switchdev_obj_port_vlan *vlan);
+int dsa_tree_port_vlan_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                           struct switchdev_obj_port_vlan *vlan,
+                           switchdev_obj_dump_cb_t *cb);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 90bcf8a..19469dc 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -195,50 +195,6 @@ out:
        return 0;
 }
 
-static int dsa_slave_port_vlan_add(struct net_device *dev,
-                                  const struct switchdev_obj_port_vlan *vlan,
-                                  struct switchdev_trans *trans)
-{
-       struct dsa_slave_priv *p = netdev_priv(dev);
-       struct dsa_switch *ds = p->dp->ds;
-
-       if (switchdev_trans_ph_prepare(trans)) {
-               if (!ds->drv->port_vlan_prepare || !ds->drv->port_vlan_add)
-                       return -EOPNOTSUPP;
-
-               return ds->drv->port_vlan_prepare(ds, p->dp, vlan, trans);
-       }
-
-       ds->drv->port_vlan_add(ds, p->dp, vlan, trans);
-
-       return 0;
-}
-
-static int dsa_slave_port_vlan_del(struct net_device *dev,
-                                  const struct switchdev_obj_port_vlan *vlan)
-{
-       struct dsa_slave_priv *p = netdev_priv(dev);
-       struct dsa_switch *ds = p->dp->ds;
-
-       if (!ds->drv->port_vlan_del)
-               return -EOPNOTSUPP;
-
-       return ds->drv->port_vlan_del(ds, p->dp, vlan);
-}
-
-static int dsa_slave_port_vlan_dump(struct net_device *dev,
-                                   struct switchdev_obj_port_vlan *vlan,
-                                   switchdev_obj_dump_cb_t *cb)
-{
-       struct dsa_slave_priv *p = netdev_priv(dev);
-       struct dsa_switch *ds = p->dp->ds;
-
-       if (ds->drv->port_vlan_dump)
-               return ds->drv->port_vlan_dump(ds, p->dp, vlan, cb);
-
-       return -EOPNOTSUPP;
-}
-
 static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
@@ -323,9 +279,9 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
                                            SWITCHDEV_OBJ_PORT_FDB(obj), trans);
                break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
-               err = dsa_slave_port_vlan_add(dev,
-                                             SWITCHDEV_OBJ_PORT_VLAN(obj),
-                                             trans);
+               err = dsa_tree_port_vlan_add(dst, dp,
+                                            SWITCHDEV_OBJ_PORT_VLAN(obj),
+                                            trans);
                break;
        default:
                err = -EOPNOTSUPP;
@@ -349,8 +305,8 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
                                            SWITCHDEV_OBJ_PORT_FDB(obj));
                break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
-               err = dsa_slave_port_vlan_del(dev,
-                                             SWITCHDEV_OBJ_PORT_VLAN(obj));
+               err = dsa_tree_port_vlan_del(dst, dp,
+                                            SWITCHDEV_OBJ_PORT_VLAN(obj));
                break;
        default:
                err = -EOPNOTSUPP;
@@ -375,9 +331,8 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
                                             SWITCHDEV_OBJ_PORT_FDB(obj), cb);
                break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
-               err = dsa_slave_port_vlan_dump(dev,
-                                              SWITCHDEV_OBJ_PORT_VLAN(obj),
-                                              cb);
+               err = dsa_tree_port_vlan_dump(dst, dp,
+                                             SWITCHDEV_OBJ_PORT_VLAN(obj), cb);
                break;
        default:
                err = -EOPNOTSUPP;
diff --git a/net/dsa/tree.c b/net/dsa/tree.c
index 8394019..0ef103e 100644
--- a/net/dsa/tree.c
+++ b/net/dsa/tree.c
@@ -125,3 +125,63 @@ int dsa_tree_port_fdb_dump(struct dsa_switch_tree *dst, 
struct dsa_port *dp,
 
        return 0;
 }
+
+int dsa_tree_port_vlan_add(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                           const struct switchdev_obj_port_vlan *vlan,
+                           struct switchdev_trans *trans)
+{
+       struct dsa_switch *ds;
+       int err;
+
+       dsa_tree_for_each_switch(dst, ds) {
+               if (switchdev_trans_ph_prepare(trans)) {
+                       if (!ds->drv->port_vlan_prepare ||
+                           !ds->drv->port_vlan_add)
+                               return -EOPNOTSUPP;
+
+                       err = ds->drv->port_vlan_prepare(ds, dp, vlan, trans);
+                       if (err)
+                               return err;
+               } else {
+                       ds->drv->port_vlan_add(ds, dp, vlan, trans);
+               }
+       }
+
+       return 0;
+}
+
+int dsa_tree_port_vlan_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                           const struct switchdev_obj_port_vlan *vlan)
+{
+       struct dsa_switch *ds;
+       int err;
+
+       dsa_tree_for_each_switch(dst, ds) {
+               if (!ds->drv->port_vlan_del)
+                       return -EOPNOTSUPP;
+
+               err = ds->drv->port_vlan_del(ds, dp, vlan);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+int dsa_tree_port_vlan_dump(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                            struct switchdev_obj_port_vlan *vlan,
+                            switchdev_obj_dump_cb_t *cb)
+{
+       struct dsa_switch *ds;
+       int err;
+
+       dsa_tree_for_each_switch(dst, ds) {
+               if (ds->drv->port_vlan_dump) {
+                       err = ds->drv->port_vlan_dump(ds, dp, vlan, cb);
+                       if (err && err != -EOPNOTSUPP)
+                               return err;
+               }
+       }
+
+       return 0;
+}
-- 
2.8.0

Reply via email to