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 FDB operations.

Signed-off-by: Vivien Didelot <vivien.dide...@savoirfairelinux.com>
---
 drivers/net/dsa/bcm_sf2.c   | 12 ++++++++
 drivers/net/dsa/mv88e6xxx.c | 12 ++++++++
 net/dsa/dsa_priv.h          |  9 ++++++
 net/dsa/slave.c             | 68 ++++++++++-----------------------------------
 net/dsa/tree.c              | 61 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 109 insertions(+), 53 deletions(-)

diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 0a91ea9..6e634e5 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -733,6 +733,9 @@ static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, 
struct dsa_port *dp,
                                  const struct switchdev_obj_port_fdb *fdb,
                                  struct switchdev_trans *trans)
 {
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        /* We do not need to do anything specific here yet */
        return 0;
 }
@@ -743,6 +746,9 @@ static void bcm_sf2_sw_fdb_add(struct dsa_switch *ds, 
struct dsa_port *dp,
 {
        struct bcm_sf2_priv *priv = ds_to_priv(ds);
 
+       if (dsa_port_is_external(dp, ds))
+               return;
+
        if (bcm_sf2_arl_op(priv, 0, dp->port, fdb->addr, fdb->vid, true))
                pr_err("%s: failed to add MAC address\n", __func__);
 }
@@ -752,6 +758,9 @@ static int bcm_sf2_sw_fdb_del(struct dsa_switch *ds, struct 
dsa_port *dp,
 {
        struct bcm_sf2_priv *priv = ds_to_priv(ds);
 
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        return bcm_sf2_arl_op(priv, 0, dp->port, fdb->addr, fdb->vid, false);
 }
 
@@ -813,6 +822,9 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, 
struct dsa_port *dp,
        unsigned int count = 0;
        int ret;
 
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        dev = ds->ports[dp->port];
 
        /* Start search operation */
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 6fef29b..7d29de3 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -2037,6 +2037,9 @@ int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, 
struct dsa_port *dp,
                               const struct switchdev_obj_port_fdb *fdb,
                               struct switchdev_trans *trans)
 {
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        /* We don't need any dynamic resource from the kernel (yet),
         * so skip the prepare phase.
         */
@@ -2052,6 +2055,9 @@ void mv88e6xxx_port_fdb_add(struct dsa_switch *ds, struct 
dsa_port *dp,
                GLOBAL_ATU_DATA_STATE_UC_STATIC;
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
 
+       if (dsa_port_is_external(dp, ds))
+               return;
+
        mutex_lock(&ps->smi_mutex);
        if (_mv88e6xxx_port_fdb_load(ds, dp->port, fdb->addr, fdb->vid, state))
                netdev_err(ds->ports[dp->port], "failed to load MAC address\n");
@@ -2064,6 +2070,9 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, struct 
dsa_port *dp,
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int ret;
 
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        mutex_lock(&ps->smi_mutex);
        ret = _mv88e6xxx_port_fdb_load(ds, dp->port, fdb->addr, fdb->vid,
                                       GLOBAL_ATU_DATA_STATE_UNUSED);
@@ -2169,6 +2178,9 @@ int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, struct 
dsa_port *dp,
        u16 fid;
        int err;
 
+       if (dsa_port_is_external(dp, ds))
+               return -EOPNOTSUPP;
+
        mutex_lock(&ps->smi_mutex);
 
        /* Dump port's default Filtering Information Database (VLAN ID 0) */
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 6e08b3d..e8765c3 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -14,6 +14,7 @@
 #include <linux/phy.h>
 #include <linux/netdevice.h>
 #include <linux/netpoll.h>
+#include <net/switchdev.h>
 
 struct dsa_device_ops {
        struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
@@ -51,6 +52,14 @@ int dsa_tree_bridge_port_join(struct dsa_switch_tree *dst, 
struct dsa_port *dp,
                              struct net_device *br);
 void dsa_tree_bridge_port_leave(struct dsa_switch_tree *dst,
                                struct dsa_port *dp, struct net_device *br);
+int dsa_tree_port_fdb_add(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                         const struct switchdev_obj_port_fdb *fdb,
+                         struct switchdev_trans *trans);
+int dsa_tree_port_fdb_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                         const struct switchdev_obj_port_fdb *fdb);
+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);
 
 /* slave.c */
 extern const struct dsa_device_ops notag_netdev_ops;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 7123ae2..90bcf8a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -239,51 +239,6 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,
        return -EOPNOTSUPP;
 }
 
-static int dsa_slave_port_fdb_add(struct net_device *dev,
-                                 const struct switchdev_obj_port_fdb *fdb,
-                                 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_fdb_prepare || !ds->drv->port_fdb_add)
-                       return -EOPNOTSUPP;
-
-               return ds->drv->port_fdb_prepare(ds, p->dp, fdb, trans);
-       }
-
-       ds->drv->port_fdb_add(ds, p->dp, fdb, trans);
-
-       return 0;
-}
-
-static int dsa_slave_port_fdb_del(struct net_device *dev,
-                                 const struct switchdev_obj_port_fdb *fdb)
-{
-       struct dsa_slave_priv *p = netdev_priv(dev);
-       struct dsa_switch *ds = p->dp->ds;
-       int ret = -EOPNOTSUPP;
-
-       if (ds->drv->port_fdb_del)
-               ret = ds->drv->port_fdb_del(ds, p->dp, fdb);
-
-       return ret;
-}
-
-static int dsa_slave_port_fdb_dump(struct net_device *dev,
-                                  struct switchdev_obj_port_fdb *fdb,
-                                  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_fdb_dump)
-               return ds->drv->port_fdb_dump(ds, p->dp, fdb, 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);
@@ -352,6 +307,9 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
                                  const struct switchdev_obj *obj,
                                  struct switchdev_trans *trans)
 {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_port *dp = p->dp;
+       struct dsa_switch_tree *dst = dp->ds->dst;
        int err;
 
        /* For the prepare phase, ensure the full set of changes is feasable in
@@ -361,9 +319,8 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 
        switch (obj->id) {
        case SWITCHDEV_OBJ_ID_PORT_FDB:
-               err = dsa_slave_port_fdb_add(dev,
-                                            SWITCHDEV_OBJ_PORT_FDB(obj),
-                                            trans);
+               err = dsa_tree_port_fdb_add(dst, dp,
+                                           SWITCHDEV_OBJ_PORT_FDB(obj), trans);
                break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
                err = dsa_slave_port_vlan_add(dev,
@@ -381,12 +338,15 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
 static int dsa_slave_port_obj_del(struct net_device *dev,
                                  const struct switchdev_obj *obj)
 {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_port *dp = p->dp;
+       struct dsa_switch_tree *dst = dp->ds->dst;
        int err;
 
        switch (obj->id) {
        case SWITCHDEV_OBJ_ID_PORT_FDB:
-               err = dsa_slave_port_fdb_del(dev,
-                                            SWITCHDEV_OBJ_PORT_FDB(obj));
+               err = dsa_tree_port_fdb_del(dst, dp,
+                                           SWITCHDEV_OBJ_PORT_FDB(obj));
                break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
                err = dsa_slave_port_vlan_del(dev,
@@ -404,13 +364,15 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,
                                   struct switchdev_obj *obj,
                                   switchdev_obj_dump_cb_t *cb)
 {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_port *dp = p->dp;
+       struct dsa_switch_tree *dst = dp->ds->dst;
        int err;
 
        switch (obj->id) {
        case SWITCHDEV_OBJ_ID_PORT_FDB:
-               err = dsa_slave_port_fdb_dump(dev,
-                                             SWITCHDEV_OBJ_PORT_FDB(obj),
-                                             cb);
+               err = dsa_tree_port_fdb_dump(dst, dp,
+                                            SWITCHDEV_OBJ_PORT_FDB(obj), cb);
                break;
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
                err = dsa_slave_port_vlan_dump(dev,
diff --git a/net/dsa/tree.c b/net/dsa/tree.c
index d3f5aea..8394019 100644
--- a/net/dsa/tree.c
+++ b/net/dsa/tree.c
@@ -11,6 +11,7 @@
 #include <linux/if_bridge.h>
 #include <linux/list.h>
 #include <linux/netdevice.h>
+#include <net/switchdev.h>
 
 #include "dsa_priv.h"
 
@@ -64,3 +65,63 @@ void dsa_tree_bridge_port_leave(struct dsa_switch_tree *dst,
                                                    BR_STATE_FORWARDING);
        }
 }
+
+int dsa_tree_port_fdb_add(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                         const struct switchdev_obj_port_fdb *fdb,
+                         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_fdb_prepare ||
+                           !ds->drv->port_fdb_add)
+                               return -EOPNOTSUPP;
+
+                       err = ds->drv->port_fdb_prepare(ds, dp, fdb, trans);
+                       if (err)
+                               return err;
+               } else {
+                       ds->drv->port_fdb_add(ds, dp, fdb, trans);
+               }
+       }
+
+       return 0;
+}
+
+int dsa_tree_port_fdb_del(struct dsa_switch_tree *dst, struct dsa_port *dp,
+                         const struct switchdev_obj_port_fdb *fdb)
+{
+       struct dsa_switch *ds;
+       int err;
+
+       dsa_tree_for_each_switch(dst, ds) {
+               if (!ds->drv->port_fdb_del)
+                       return -EOPNOTSUPP;
+
+               err = ds->drv->port_fdb_del(ds, dp, fdb);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+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)
+{
+       struct dsa_switch *ds;
+       int err;
+
+       dsa_tree_for_each_switch(dst, ds) {
+               if (ds->drv->port_fdb_dump) {
+                       err = ds->drv->port_fdb_dump(ds, dp, fdb, cb);
+                       if (err && err != -EOPNOTSUPP)
+                               return err;
+               }
+       }
+
+       return 0;
+}
-- 
2.8.0

Reply via email to